| // Copyright 2020 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // ---------------- |
| |
| /* |
| This test program is typically run indirectly, by the "wuffs test" or "wuffs |
| bench" commands. These commands take an optional "-mimic" flag to check that |
| Wuffs' output mimics (i.e. exactly matches) other libraries' output, such as |
| giflib for GIF, libpng for PNG, etc. |
| |
| To manually run this test: |
| |
| for CC in clang gcc; do |
| $CC -std=c99 -Wall -Werror json.c && ./a.out |
| rm -f a.out |
| done |
| |
| Each edition should print "PASS", amongst other information, and exit(0). |
| |
| Add the "wuffs mimic cflags" (everything after the colon below) to the C |
| compiler flags (after the .c file) to run the mimic tests. |
| |
| To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace |
| the first "./a.out" with "./a.out -bench". Combine these changes with the |
| "wuffs mimic cflags" to run the mimic benchmarks. |
| */ |
| |
| // ¿ wuffs mimic cflags: -DWUFFS_MIMIC |
| |
| // Wuffs ships as a "single file C library" or "header file library" as per |
| // https://github.com/nothings/stb/blob/master/docs/stb_howto.txt |
| // |
| // To use that single file as a "foo.c"-like implementation, instead of a |
| // "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or |
| // compiling it. |
| #define WUFFS_IMPLEMENTATION |
| |
| // Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of |
| // release/c/etc.c choose which parts of Wuffs to build. That file contains the |
| // entire Wuffs standard library, implementing a variety of codecs and file |
| // formats. Without this macro definition, an optimizing compiler or linker may |
| // very well discard Wuffs code for unused codecs, but listing the Wuffs |
| // modules we use makes that process explicit. Preprocessing means that such |
| // code simply isn't compiled. |
| #define WUFFS_CONFIG__MODULES |
| #define WUFFS_CONFIG__MODULE__BASE |
| #define WUFFS_CONFIG__MODULE__JSON |
| |
| // If building this program in an environment that doesn't easily accommodate |
| // relative includes, you can use the script/inline-c-relative-includes.go |
| // program to generate a stand-alone C file. |
| #include "../../../release/c/wuffs-unsupported-snapshot.c" |
| #include "../testlib/testlib.c" |
| #ifdef WUFFS_MIMIC |
| // No mimic library. |
| #endif |
| |
| // ---------------- Numeric Types Tests |
| |
| const char* // |
| test_wuffs_core_count_leading_zeroes_u64() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| uint64_t num; |
| uint32_t want; |
| } test_cases[] = { |
| {.num = 0x0000000000000000, .want = 64}, |
| {.num = 0x0000000000000001, .want = 63}, |
| {.num = 0x0000000000008001, .want = 48}, |
| {.num = 0x0000000040302010, .want = 33}, |
| {.num = 0x0123456789ABCDEF, .want = 7}, |
| {.num = 0x8000000000000001, .want = 0}, |
| {.num = 0xFFFFFFFFFFFFFFFF, .want = 0}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| uint32_t have = wuffs_base__count_leading_zeroes_u64(test_cases[tc].num); |
| if (have != test_cases[tc].want) { |
| RETURN_FAIL("0x%" PRIX64 ": have %" PRIu32 ", want %" PRIu32, |
| test_cases[tc].num, have, test_cases[tc].want); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_core_multiply_u64() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| uint64_t x; |
| uint64_t y; |
| uint64_t want_hi; |
| uint64_t want_lo; |
| } test_cases[] = { |
| {.x = 0x0000000000005678, |
| .y = 0x0000000000001001, |
| .want_hi = 0x0000000000000000, |
| .want_lo = 0x000000000567D678}, |
| {.x = 0x00000000DEADBEEF, |
| .y = 0x000000BEEEEEEEEF, |
| .want_hi = 0x00000000000000A6, |
| .want_lo = 0x14C912411FE97321}, |
| {.x = 0x0123456789ABCDEF, |
| .y = 0x8080707066554321, |
| .want_hi = 0x009234D666DAD50F, |
| .want_lo = 0x89B3DE09506618CF}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__multiply_u64__output have = |
| wuffs_base__multiply_u64(test_cases[tc].x, test_cases[tc].y); |
| if ((have.hi != test_cases[tc].want_hi) || |
| (have.lo != test_cases[tc].want_lo)) { |
| RETURN_FAIL("0x%" PRIX64 " * 0x%" PRIX64 ": have (0x%" PRIX64 |
| ", 0x%" PRIX64 "), want (0x%" PRIX64 ", 0x%" PRIX64 ")", |
| test_cases[tc].x, test_cases[tc].y, have.hi, have.lo, |
| test_cases[tc].want_hi, test_cases[tc].want_lo); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- String Conversions Tests |
| |
| // wuffs_base__private_implementation__high_prec_dec__to_debug_string converts |
| // hpd into a human-readable NUL-terminated C string. |
| const char* // |
| wuffs_base__private_implementation__high_prec_dec__to_debug_string( |
| wuffs_base__private_implementation__high_prec_dec* hpd, |
| wuffs_base__slice_u8 dst) { |
| if (!hpd) { |
| return "high_prec_dec__to_debug_string: invalid hpd"; |
| } |
| uint8_t* p = dst.ptr; |
| uint8_t* q = dst.ptr + dst.len; |
| |
| // Sign bit. |
| if ((q - p) < 1) { |
| goto too_short; |
| } |
| *p++ = hpd->negative ? '-' : '+'; |
| |
| // Digits and decimal point. |
| if (hpd->decimal_point > |
| +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) { |
| // We have "infinity". |
| if ((q - p) < 3) { |
| goto too_short; |
| } |
| *p++ = 'i'; |
| *p++ = 'n'; |
| *p++ = 'f'; |
| goto nul_terminator; |
| |
| } else if (hpd->decimal_point < |
| -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) { |
| // We have "epsilon": a very small number, equivalent to zero. |
| if ((q - p) < 3) { |
| goto too_short; |
| } |
| *p++ = 'e'; |
| *p++ = 'p'; |
| *p++ = 's'; |
| goto nul_terminator; |
| |
| } else if (hpd->num_digits == 0) { |
| // We have "0". |
| if ((q - p) < 1) { |
| goto too_short; |
| } |
| *p++ = '0'; |
| goto nul_terminator; |
| |
| } else if (hpd->decimal_point < 0) { |
| // Referring to the wuffs_base__private_implementation__high_prec_dec |
| // typedef's comment, we have something like ".00789". |
| if ((q - p) < (hpd->num_digits + ((uint32_t)(-hpd->decimal_point)) + 1)) { |
| goto too_short; |
| } |
| uint8_t* src = &hpd->digits[0]; |
| |
| // Step A.1: write the ".". |
| *p++ = '.'; |
| |
| // Step A.2: write the "00". |
| uint32_t n = ((uint32_t)(-hpd->decimal_point)); |
| if (n > 0) { |
| memset(p, '0', n); |
| p += n; |
| } |
| |
| // Step A.3: write the "789". |
| n = hpd->num_digits; |
| while (n--) { |
| *p++ = '0' | *src++; |
| } |
| |
| } else if (((uint32_t)(hpd->decimal_point)) <= hpd->num_digits) { |
| // Referring to the wuffs_base__private_implementation__high_prec_dec |
| // typedef's comment, we have something like "78.9". |
| if ((q - p) < (hpd->num_digits + 1)) { |
| goto too_short; |
| } |
| uint8_t* src = &hpd->digits[0]; |
| |
| // Step B.1: write the "78". |
| uint32_t n = ((uint32_t)(hpd->decimal_point)); |
| while (n--) { |
| *p++ = '0' | *src++; |
| } |
| |
| // Step B.2: write the ".". |
| *p++ = '.'; |
| |
| // Step B.3: write the "9". |
| n = hpd->num_digits - ((uint32_t)(hpd->decimal_point)); |
| while (n--) { |
| *p++ = '0' | *src++; |
| } |
| |
| } else { |
| // Referring to the wuffs_base__private_implementation__high_prec_dec |
| // typedef's comment, we have something like "78900.". |
| if ((q - p) < (((uint32_t)(hpd->decimal_point)) + 1)) { |
| goto too_short; |
| } |
| uint8_t* src = &hpd->digits[0]; |
| |
| // Step C.1: write the "789". |
| uint32_t n = hpd->num_digits; |
| while (n--) { |
| *p++ = '0' | *src++; |
| } |
| |
| // Step C.2: write the "00". |
| n = ((uint32_t)(hpd->decimal_point)) - hpd->num_digits; |
| if (n > 0) { |
| memset(p, '0', n); |
| p += n; |
| } |
| |
| // Step C.3: write the ".". |
| *p++ = '.'; |
| } |
| |
| // Truncated bit. |
| if (hpd->truncated) { |
| if ((q - p) < 1) { |
| goto too_short; |
| } |
| *p++ = '$'; |
| } |
| |
| nul_terminator: |
| if ((q - p) < 1) { |
| goto too_short; |
| } |
| *p++ = '\x00'; |
| return NULL; |
| |
| too_short: |
| return "high_prec_dec__to_debug_string: dst buffer is too short"; |
| } |
| |
| const char* // |
| test_wuffs_strconv_hpd_rounded_integer() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| uint64_t want; |
| const char* str; |
| } test_cases[] = { |
| {.want = 4, .str = "-3.9"}, |
| {.want = 3, .str = "-3.14159"}, |
| {.want = 0, .str = "+0"}, |
| {.want = 0, .str = "0.0000000009"}, |
| {.want = 0, .str = "0.1"}, |
| {.want = 1, .str = "0.9"}, |
| {.want = 12, .str = "1234e-2"}, |
| {.want = 57, .str = "5678e-2"}, |
| {.want = 60, .str = "60.0"}, |
| {.want = 60, .str = "60.4999"}, |
| {.want = 60, .str = "60.5"}, |
| {.want = 60, .str = "60.5000"}, |
| {.want = 61, .str = "60.5001"}, |
| {.want = 61, .str = "60.6"}, |
| {.want = 61, .str = "61.0"}, |
| {.want = 61, .str = "61.4999"}, |
| {.want = 62, .str = "61.5"}, |
| {.want = 62, .str = "61.5000"}, |
| {.want = 62, .str = "61.5001"}, |
| {.want = 62, .str = "61.6"}, |
| {.want = 62, .str = "62.0"}, |
| {.want = 62, .str = "62.4999"}, |
| {.want = 62, .str = "62.5"}, |
| {.want = 62, .str = "62.5000"}, |
| {.want = 63, .str = "62.5001"}, |
| {.want = 63, .str = "62.6"}, |
| {.want = 1000, .str = "999.999"}, |
| {.want = 4560000, .str = "456e+4"}, |
| |
| // With round-to-even, ½ rounds to 0 but "a tiny bit more than ½" rounds |
| // to 1, even if the HPD struct truncates that "1" digit. |
| {.want = 0, .str = "0.5"}, |
| {.want = 1, // 50 '0's per row. |
| .str = "0.500000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000001"}, |
| |
| // Inputs with exactly 18 decimal digits before the decimal point. |
| {.want = 123456789012345679, .str = "123456789012345678.9"}, |
| {.want = 1000000000000000000, .str = "999999999999999999.9"}, |
| |
| // Inputs with exactly 19 decimal digits before the decimal point. |
| {.want = UINT64_MAX, .str = "1234567890123456789"}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__private_implementation__high_prec_dec hpd; |
| CHECK_STATUS("hpd__parse", |
| wuffs_base__private_implementation__high_prec_dec__parse( |
| &hpd, |
| wuffs_base__make_slice_u8((void*)test_cases[tc].str, |
| strlen(test_cases[tc].str)), |
| WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| uint64_t have = |
| wuffs_base__private_implementation__high_prec_dec__rounded_integer( |
| &hpd); |
| if (have != test_cases[tc].want) { |
| RETURN_FAIL("\"%s\": have %" PRIu64 ", want %" PRIu64, test_cases[tc].str, |
| have, test_cases[tc].want); |
| } |
| } |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_hpd_shift() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| const char* str; |
| int32_t shift; // -ve means left shift, +ve means right shift. |
| const char* want; |
| } test_cases[] = { |
| {.str = "0", .shift = +2, .want = "+0"}, |
| {.str = "1", .shift = +3, .want = "+.125"}, |
| {.str = "12e3", .shift = +5, .want = "+375."}, |
| {.str = "-0.007", .shift = +8, .want = "-.00002734375"}, |
| {.str = "3.14159E+26", |
| .shift = +60, |
| .want = "+272489496.244698869986677891574800014495849609375"}, |
| |
| {.str = "0", .shift = -2, .want = "+0"}, |
| {.str = ".125", .shift = -3, .want = "+1."}, |
| {.str = "3750e-1", .shift = -5, .want = "+12000."}, |
| {.str = "-2.734375e-5", .shift = -8, .want = "-.007"}, |
| {.str = "+272489496.244698869986677891574800014495849609375", |
| .shift = -60, |
| .want = "+314159000000000000000000000."}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__private_implementation__high_prec_dec hpd; |
| CHECK_STATUS("hpd__parse", |
| wuffs_base__private_implementation__high_prec_dec__parse( |
| &hpd, |
| wuffs_base__make_slice_u8((void*)test_cases[tc].str, |
| strlen(test_cases[tc].str)), |
| WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| int32_t shift = test_cases[tc].shift; |
| if (shift > 0) { |
| wuffs_base__private_implementation__high_prec_dec__small_rshift( |
| &hpd, (uint32_t)(+shift)); |
| } else if (shift < 0) { |
| wuffs_base__private_implementation__high_prec_dec__small_lshift( |
| &hpd, (uint32_t)(-shift)); |
| } |
| |
| uint8_t have[1024]; |
| CHECK_STRING( |
| wuffs_base__private_implementation__high_prec_dec__to_debug_string( |
| &hpd, |
| wuffs_base__make_slice_u8(have, WUFFS_TESTLIB_ARRAY_SIZE(have)))); |
| if (strcmp(((void*)(have)), test_cases[tc].want)) { |
| RETURN_FAIL("\"%s\" %s %" PRId32 ":\n have: \"%s\"\n want: \"%s\"", |
| test_cases[tc].str, ((shift > 0) ? ">>" : "<<"), |
| ((shift > 0) ? +shift : -shift), have, test_cases[tc].want); |
| } |
| } |
| return NULL; |
| } |
| |
| // ---------------- |
| |
| const char* // |
| test_wuffs_strconv_ieee_754_bit_representation_from_u16() { |
| CHECK_FOCUS(__func__); |
| |
| double inf = 1.0 / 0.0; |
| uint64_t nan_u64 = 0x7FFFFFFFFFFFFFFF; |
| double nan = |
| wuffs_base__ieee_754_bit_representation__from_u64_to_f64(nan_u64); |
| |
| struct { |
| uint16_t u16_bits; |
| uint64_t want_u64; |
| double want_f64; |
| } test_cases[] = { |
| { |
| .u16_bits = 0x0000, |
| .want_u64 = 0x0000000000000000, |
| .want_f64 = 0.0, |
| }, |
| { |
| .u16_bits = 0x0001, |
| .want_u64 = 0x3E70000000000000, |
| .want_f64 = 0.000000059604644775390625, |
| }, |
| { |
| .u16_bits = 0x0123, |
| .want_u64 = 0x3EF2300000000000, |
| .want_f64 = 0.000017344951629638671875, |
| }, |
| { |
| .u16_bits = 0x03FF, |
| .want_u64 = 0x3F0FF80000000000, |
| .want_f64 = 0.000060975551605224609375, |
| }, |
| { |
| .u16_bits = 0x0400, |
| .want_u64 = 0x3F10000000000000, |
| .want_f64 = 0.00006103515625, |
| }, |
| { |
| .u16_bits = 0x0401, |
| .want_u64 = 0x3F10040000000000, |
| .want_f64 = 0.000061094760894775390625, |
| }, |
| { |
| .u16_bits = 0x3C00, |
| .want_u64 = 0x3FF0000000000000, |
| .want_f64 = 1.0, |
| }, |
| { |
| .u16_bits = 0x4580, |
| .want_u64 = 0x4016000000000000, |
| .want_f64 = 5.5, |
| }, |
| { |
| .u16_bits = 0x7BFF, |
| .want_u64 = 0x40EFFC0000000000, |
| .want_f64 = 65504.0, |
| }, |
| { |
| .u16_bits = 0x7C00, |
| .want_u64 = 0x7FF0000000000000, |
| .want_f64 = inf, |
| }, |
| { |
| .u16_bits = 0x7FFF, |
| .want_u64 = nan_u64, |
| .want_f64 = nan, |
| }, |
| { |
| .u16_bits = 0xFC00, |
| .want_u64 = 0xFFF0000000000000, |
| .want_f64 = -inf, |
| }, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| double have_f64 = wuffs_base__ieee_754_bit_representation__from_u16_to_f64( |
| test_cases[tc].u16_bits); |
| double want_f64 = test_cases[tc].want_f64; |
| // See if they're equal, considering that NaN != NaN. |
| bool equal = ((have_f64 == want_f64) || |
| ((have_f64 != have_f64) && (want_f64 != want_f64))); |
| if (!equal) { |
| RETURN_FAIL("tc=%zu: to_f64: have %g, want %g", tc, have_f64, want_f64); |
| } |
| |
| uint64_t have_u64 = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u64(have_f64); |
| uint64_t want_u64 = test_cases[tc].want_u64; |
| // There's more than one representation of NaN. |
| if ((have_u64 != want_u64) && (want_u64 != nan_u64)) { |
| RETURN_FAIL("tc=%zu: to_u64: have 0x%016" PRIX64 ", want 0x%016" PRIX64, |
| tc, have_u64, want_u64); |
| } |
| |
| int noise; |
| for (noise = 0; noise < 2; noise++) { |
| if ((noise > 0) && ((want_f64 == inf) || (want_f64 == -inf))) { |
| continue; |
| } |
| wuffs_base__lossy_value_u16 lv = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u16_truncate( |
| wuffs_base__ieee_754_bit_representation__from_u64_to_f64( |
| want_u64 ^ ((uint64_t)noise))); |
| if (lv.value != test_cases[tc].u16_bits) { |
| RETURN_FAIL("tc=%zu: noise=%d: to_u16 value: have 0x%04" PRIX16 |
| ", want 0x%04" PRIX16, |
| tc, noise, lv.value, test_cases[tc].u16_bits); |
| } |
| int want_lossy = (want_f64 == want_f64) ? noise : 0; |
| if (((int)lv.lossy) != want_lossy) { |
| RETURN_FAIL("tc=%zu: noise=%d: to_u16 lossy: have %d, want %d", tc, |
| noise, ((int)(lv.lossy)), want_lossy); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_ieee_754_bit_representation_from_u32() { |
| CHECK_FOCUS(__func__); |
| |
| double inf = 1.0 / 0.0; |
| uint64_t nan_u64 = 0x7FFFFFFFFFFFFFFF; |
| double nan = |
| wuffs_base__ieee_754_bit_representation__from_u64_to_f64(nan_u64); |
| |
| struct { |
| uint32_t u32_bits; |
| uint64_t want_u64; |
| double want_f64; |
| } test_cases[] = { |
| { |
| .u32_bits = 0x00000000, |
| .want_u64 = 0x0000000000000000, |
| .want_f64 = 0.0, |
| }, |
| { |
| .u32_bits = 0x00000001, |
| .want_u64 = 0x36A0000000000000, |
| .want_f64 = 1.4012984643248170709237295832899161312802619418765e-45, |
| }, |
| { |
| .u32_bits = 0x00000123, |
| .want_u64 = 0x3722300000000000, |
| .want_f64 = 4.0777785311852176763880530873736559420255622508607e-43, |
| }, |
| { |
| .u32_bits = 0x007FFFFF, |
| .want_u64 = 0x380FFFFFC0000000, |
| .want_f64 = 1.1754942106924410754870294448492873488270524287459e-38, |
| }, |
| { |
| .u32_bits = 0x00800000, |
| .want_u64 = 0x3810000000000000, |
| .want_f64 = 1.1754943508222875079687365372222456778186655567721e-38, |
| }, |
| { |
| .u32_bits = 0x00800001, |
| .want_u64 = 0x3810000020000000, |
| .want_f64 = 1.1754944909521339404504436295952040068102786847983e-38, |
| }, |
| { |
| .u32_bits = 0x3F800000, |
| .want_u64 = 0x3FF0000000000000, |
| .want_f64 = 1.0, |
| }, |
| { |
| .u32_bits = 0x40B00000, |
| .want_u64 = 0x4016000000000000, |
| .want_f64 = 5.5, |
| }, |
| { |
| .u32_bits = 0x7F7FFFFF, |
| .want_u64 = 0x47EFFFFFE0000000, |
| .want_f64 = 3.40282346638528859811704183484516925440e38, |
| }, |
| { |
| .u32_bits = 0x7F800000, |
| .want_u64 = 0x7FF0000000000000, |
| .want_f64 = inf, |
| }, |
| { |
| .u32_bits = 0x7FFFFFFF, |
| .want_u64 = nan_u64, |
| .want_f64 = nan, |
| }, |
| { |
| .u32_bits = 0xFF800000, |
| .want_u64 = 0xFFF0000000000000, |
| .want_f64 = -inf, |
| }, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| double have_f64 = wuffs_base__ieee_754_bit_representation__from_u32_to_f64( |
| test_cases[tc].u32_bits); |
| double want_f64 = test_cases[tc].want_f64; |
| // See if they're equal, considering that NaN != NaN. |
| bool equal = ((have_f64 == want_f64) || |
| ((have_f64 != have_f64) && (want_f64 != want_f64))); |
| if (!equal) { |
| RETURN_FAIL("tc=%zu: to_f64: have %g, want %g", tc, have_f64, want_f64); |
| } |
| |
| uint64_t have_u64 = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u64(have_f64); |
| uint64_t want_u64 = test_cases[tc].want_u64; |
| // There's more than one representation of NaN. |
| if ((have_u64 != want_u64) && (want_u64 != nan_u64)) { |
| RETURN_FAIL("tc=%zu: to_u64: have 0x%016" PRIX64 ", want 0x%016" PRIX64, |
| tc, have_u64, want_u64); |
| } |
| |
| int noise; |
| for (noise = 0; noise < 2; noise++) { |
| if ((noise > 0) && ((want_f64 == inf) || (want_f64 == -inf))) { |
| continue; |
| } |
| wuffs_base__lossy_value_u32 lv = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u32_truncate( |
| wuffs_base__ieee_754_bit_representation__from_u64_to_f64( |
| want_u64 ^ ((uint64_t)noise))); |
| if (lv.value != test_cases[tc].u32_bits) { |
| RETURN_FAIL("tc=%zu: noise=%d: to_u32 value: have 0x%08" PRIX32 |
| ", want 0x%08" PRIX32, |
| tc, noise, lv.value, test_cases[tc].u32_bits); |
| } |
| int want_lossy = (want_f64 == want_f64) ? noise : 0; |
| if (((int)lv.lossy) != want_lossy) { |
| RETURN_FAIL("tc=%zu: noise=%d: to_u32 lossy: have %d, want %d", tc, |
| noise, ((int)(lv.lossy)), want_lossy); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- |
| |
| const char* // |
| test_wuffs_strconv_base_16() { |
| CHECK_FOCUS(__func__); |
| const bool src_closed = true; |
| |
| { |
| const char* str = "6A6b7"; // The "7" should cause "#base: bad data". |
| wuffs_base__slice_u8 dst = g_have_slice_u8; |
| wuffs_base__slice_u8 src = |
| wuffs_base__make_slice_u8((void*)str, strlen(str)); |
| wuffs_base__transform__output have = wuffs_base__base_16__decode2( |
| dst, src, src_closed, WUFFS_BASE__BASE_16__DEFAULT_OPTIONS); |
| if (have.status.repr != wuffs_base__error__bad_data) { |
| RETURN_FAIL("decode2: have \"%s\", want \"%s\"", have.status.repr, |
| wuffs_base__error__bad_data); |
| } |
| if (have.num_dst != 2) { |
| RETURN_FAIL("decode2: num_dst: have %zu, want 2", have.num_dst); |
| } |
| if (have.num_src != 4) { |
| RETURN_FAIL("decode2: num_src: have %zu, want 3", have.num_src); |
| } |
| if (g_have_array_u8[0] != 0x6A) { |
| RETURN_FAIL("decode2: dst[0]: have 0x%02X, want 0x6A", |
| (int)(g_have_array_u8[0])); |
| } |
| if (g_have_array_u8[1] != 0x6B) { |
| RETURN_FAIL("decode2: dst[1]: have 0x%02X, want 0x6B", |
| (int)(g_have_array_u8[1])); |
| } |
| } |
| |
| { |
| const char* str = "\\xa9\\x00\\xFe"; |
| wuffs_base__slice_u8 dst = g_have_slice_u8; |
| wuffs_base__slice_u8 src = |
| wuffs_base__make_slice_u8((void*)str, strlen(str)); |
| wuffs_base__transform__output have = wuffs_base__base_16__decode4( |
| dst, src, src_closed, WUFFS_BASE__BASE_16__DEFAULT_OPTIONS); |
| if (have.status.repr) { |
| RETURN_FAIL("decode2: %s", have.status.repr); |
| } |
| if (have.num_dst != 3) { |
| RETURN_FAIL("decode4: num_dst: have %zu, want 3", have.num_dst); |
| } |
| if (have.num_src != 12) { |
| RETURN_FAIL("decode4: num_src: have %zu, want 3", have.num_src); |
| } |
| if (g_have_array_u8[0] != 0xA9) { |
| RETURN_FAIL("decode4: dst[0]: have 0x%02X, want 0xA9", |
| (int)(g_have_array_u8[0])); |
| } |
| if (g_have_array_u8[1] != 0x00) { |
| RETURN_FAIL("decode4: dst[1]: have 0x%02X, want 0x00", |
| (int)(g_have_array_u8[1])); |
| } |
| if (g_have_array_u8[2] != 0xFE) { |
| RETURN_FAIL("decode4: dst[2]: have 0x%02X, want 0xFE", |
| (int)(g_have_array_u8[2])); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_base_64() { |
| CHECK_FOCUS(__func__); |
| |
| char* foobar = "foobar"; |
| const char* wants[] = { |
| "", // |
| "Zg==", // |
| "Zm8=", // |
| "Zm9v", // |
| "Zm9vYg==", // |
| "Zm9vYmE=", // |
| "Zm9vYmFy", // |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(wants); tc++) { |
| const bool src_closed = true; |
| |
| wuffs_base__transform__output e = wuffs_base__base_64__encode( |
| g_have_slice_u8, wuffs_base__make_slice_u8(((uint8_t*)foobar), tc), |
| src_closed, WUFFS_BASE__BASE_64__ENCODE_EMIT_PADDING); |
| if (e.status.repr) { |
| RETURN_FAIL("tc=%zu: encode: \"%s\"", tc, e.status.repr); |
| } |
| if (e.num_src != tc) { |
| RETURN_FAIL("tc=%zu: encode: num_src: have %zu, want %zu", tc, e.num_src, |
| tc); |
| } |
| if (e.num_dst != (((tc + 2) / 3) * 4)) { |
| RETURN_FAIL("tc=%zu: encode: num_dst: have %zu, want %zu", tc, e.num_dst, |
| (((tc + 2) / 3) * 4)); |
| } |
| if ((e.num_dst + 1) > g_have_slice_u8.len) { |
| RETURN_FAIL("tc=%zu: encode: num_dst is too large", tc); |
| } |
| g_have_slice_u8.ptr[e.num_dst] = '\x00'; |
| if (strncmp((const char*)(g_have_slice_u8.ptr), wants[tc], e.num_dst) != |
| 0) { |
| RETURN_FAIL("tc=%zu: encode:\nhave \"%s\"\nwant \"%s\"", tc, |
| g_have_slice_u8.ptr, wants[tc]); |
| } |
| |
| int trim; |
| for (trim = 0; trim < 2; trim++) { |
| size_t n = e.num_dst; |
| if (trim) { |
| while ((n > 0) && (g_have_slice_u8.ptr[n - 1] == '=')) { |
| n--; |
| } |
| } |
| |
| wuffs_base__transform__output d = wuffs_base__base_64__decode( |
| g_work_slice_u8, wuffs_base__make_slice_u8(g_have_slice_u8.ptr, n), |
| src_closed, WUFFS_BASE__BASE_64__DECODE_ALLOW_PADDING); |
| if (d.status.repr) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode: \"%s\"", tc, trim, d.status.repr); |
| } |
| if (d.num_src != n) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode: num_src: have %zu, want %zu", tc, |
| trim, d.num_src, n); |
| } |
| if (d.num_dst != tc) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode: num_dst: have %zu, want %zu", tc, |
| trim, d.num_dst, tc); |
| } |
| if ((d.num_dst + 1) > g_work_slice_u8.len) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode: num_dst is too large", tc, trim); |
| } |
| g_work_slice_u8.ptr[d.num_dst] = '\x00'; |
| if ((tc + 1) > g_want_slice_u8.len) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode: tc is too large", tc, trim); |
| } |
| memcpy(g_want_slice_u8.ptr, foobar, tc); |
| g_want_slice_u8.ptr[tc] = '\x00'; |
| if (strcmp(((const char*)(g_work_slice_u8.ptr)), |
| ((const char*)(g_want_slice_u8.ptr))) != 0) { |
| RETURN_FAIL("tc=%zu: trim=%d: decode:\nhave \"%s\"\nwant \"%s\"", tc, |
| trim, g_work_slice_u8.ptr, g_want_slice_u8.ptr); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- |
| |
| const char* // |
| test_wuffs_strconv_parse_number_f64_options() { |
| CHECK_FOCUS(__func__); |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_MULTIPLE_LEADING_ZEROES. |
| { |
| for (int o = 0; o < 2; o++) { |
| const char* str = "001.25"; |
| wuffs_base__result_f64 r = wuffs_base__parse_number_f64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| (o ? WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_MULTIPLE_LEADING_ZEROES |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o == 0) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL( |
| "ALLOW_MULTIPLE_LEADING_ZEROES off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| CHECK_STATUS("ALLOW_MULTIPLE_LEADING_ZEROES on", r.status); |
| uint64_t have = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u64(r.value); |
| uint64_t want = 0x3FF4000000000000; |
| if (have != want) { |
| RETURN_FAIL("ALLOW_MULTIPLE_LEADING_ZEROES on: have 0x%016" PRIX64 |
| ", want 0x%016" PRIX64, |
| have, want); |
| } |
| } |
| } |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES. |
| { |
| for (int o = 0; o < 2; o++) { |
| const char* str = "_1.2__5"; |
| wuffs_base__result_f64 r = wuffs_base__parse_number_f64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| (o ? WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o == 0) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL("ALLOW_UNDERSCORES off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| CHECK_STATUS("ALLOW_UNDERSCORES on", r.status); |
| uint64_t have = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u64(r.value); |
| uint64_t want = 0x3FF4000000000000; |
| if (have != want) { |
| RETURN_FAIL("ALLOW_UNDERSCORES on: have 0x%016" PRIX64 |
| ", want 0x%016" PRIX64, |
| have, want); |
| } |
| } |
| } |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA. |
| { |
| for (int o = 0; o < 2; o++) { |
| const char* str = "1,75"; |
| wuffs_base__result_f64 r = wuffs_base__parse_number_f64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| (o ? WUFFS_BASE__PARSE_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o == 0) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL( |
| "DECIMAL_SEPARATOR_IS_A_COMMA off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| CHECK_STATUS("DECIMAL_SEPARATOR_IS_A_COMMA on", r.status); |
| uint64_t have = |
| wuffs_base__ieee_754_bit_representation__from_f64_to_u64(r.value); |
| uint64_t want = 0x3FFC000000000000; |
| if (have != want) { |
| RETURN_FAIL("DECIMAL_SEPARATOR_IS_A_COMMA on: have 0x%016" PRIX64 |
| ", want 0x%016" PRIX64, |
| have, want); |
| } |
| } |
| } |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN. |
| { |
| for (int o = 0; o < 4; o++) { |
| const char* str = (o & 2) ? "1e999" : "nan"; |
| wuffs_base__result_f64 r = wuffs_base__parse_number_f64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| ((o & 1) ? WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o & 1) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL("REJECT_INF_AND_NAN off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| if (r.status.repr != NULL) { |
| RETURN_FAIL("REJECT_INF_AND_NAN on: have \"%s\", want NULL", |
| r.status.repr); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_parse_number_f64_regular() { |
| CHECK_FOCUS(__func__); |
| |
| const uint64_t fail = 0xDEADBEEF; |
| |
| struct { |
| uint64_t want; |
| const char* str; |
| } test_cases[] = { |
| // If adding new cases, consider updating u64TestCases in |
| // script/print-render-number-f64-tests.go |
| |
| {.want = 0x0000000000000000, .str = "+0.0"}, |
| {.want = 0x0000000000000000, .str = "0"}, |
| {.want = 0x0000000000000000, .str = "0e0"}, |
| {.want = 0x0000000000000000, .str = "0e99"}, |
| {.want = 0x0000000000000000, .str = "1e-332"}, |
| {.want = 0x0000000000000001, .str = "4.9406564584124654e-324"}, |
| {.want = 0x0000000000000002, .str = "9.8813129168249309e-324"}, |
| {.want = 0x0000000000000003, .str = "1.4821969375237396e-323"}, |
| {.want = 0x000730D67819E8D2, .str = "1e-308"}, |
| {.want = 0x000FFFFFFFFFFFFF, .str = "2.2250738585072009E-308"}, |
| {.want = 0x0010000000000000, .str = "2.2250738585072014E-308"}, |
| {.want = 0x0031FA182C40C60D, .str = "1e-307"}, |
| {.want = 0x369C2DF8DA5B6CA8, .str = "1.234e-45"}, |
| {.want = 0x369C314ABE948EB1, |
| .str = "0.0000000000000000000000000000000000000000000012345678900000"}, |
| {.want = 0x3E70000000000000, .str = "5.9604644775390625e-8"}, |
| {.want = 0x3F88000000000000, .str = "0.01171875"}, |
| {.want = 0x3FD0000000000000, .str = ".25"}, |
| {.want = 0x3FD3333333333333, |
| .str = "0.2999999999999999888977697537484345957636833190917968750000"}, |
| {.want = 0x3FD3333333333333, .str = "0.3"}, |
| {.want = 0x3FD3333333333334, .str = "0.30000000000000004"}, |
| {.want = 0x3FD3333333333334, |
| .str = "0.3000000000000000444089209850062616169452667236328125000000"}, |
| {.want = 0x3FD5555555555555, .str = "0.333333333333333333333333333333"}, |
| {.want = 0x3FEFFFFFFFFFFFFF, .str = "0.99999999999999988898"}, |
| {.want = 0x3FF0000000000000, .str = "0.999999999999999999999999999999"}, |
| {.want = 0x3FF0000000000000, .str = "1"}, |
| {.want = 0x3FF0000000000001, .str = "1.0000000000000002"}, |
| {.want = 0x3FF0000000000002, .str = "1.0000000000000004"}, |
| {.want = 0x3FF4000000000000, .str = "1.25"}, |
| {.want = 0x3FF8000000000000, .str = "+1.5"}, |
| {.want = 0x4008000000000000, .str = "3"}, |
| {.want = 0x400921F9F01B866E, .str = "3.14159"}, |
| {.want = 0x400921FB54442D11, .str = "3.14159265358979"}, |
| {.want = 0x400921FB54442D18, .str = "3.141592653589793"}, |
| {.want = 0x400921FB54442D18, .str = "3.141592653589793238462643383279"}, |
| {.want = 0x400921FB54442D18, |
| .str = "3.1415926535897932384626433832795028841971693993751"}, |
| {.want = 0x400C000000000000, .str = "3.5"}, |
| {.want = 0x4014000000000000, .str = "5"}, |
| {.want = 0x4036000000000000, .str = "22"}, |
| {.want = 0x4036000000000000, .str = "_+__2_2__."}, |
| {.want = 0x4037000000000000, .str = "23"}, |
| {.want = 0x4038000000000000, .str = "2.4E+00000000001"}, |
| {.want = 0x4038000000000000, .str = "2.4E001"}, |
| {.want = 0x4038000000000000, .str = "2.4E1"}, |
| {.want = 0x4038000000000000, .str = "24"}, |
| {.want = 0x4038000000000000, .str = "2400_00000_00000.00000_e-_1_2"}, |
| {.want = 0x405E9AA48FBB2888, .str = "122.416294033786585"}, |
| {.want = 0x405E9AA48FBB2888, .str = "122.41629403378658"}, |
| {.want = 0x405E9AA48FBB2889, .str = "122.4162940337866"}, |
| {.want = 0x40FE240C9FCB0C02, .str = "123456.789012"}, |
| {.want = 0x41E0246690000001, |
| .str = "2.16656806400000023841857910156251e9"}, |
| {.want = 0x4202A05F20000000, .str = "1e10"}, |
| {.want = 0x4330000000000000, .str = "4503599627370496"}, // 1 << 52. |
| {.want = 0x4330000000000000, .str = "4503599627370496.5"}, |
| {.want = 0x4330000000000001, .str = "4503599627370497"}, |
| {.want = 0x4330000000000002, .str = "4503599627370497.5"}, |
| {.want = 0x4330000000000002, .str = "4503599627370498"}, |
| {.want = 0x433FFFFFFFFFFFFE, .str = "9007199254740990"}, |
| {.want = 0x433FFFFFFFFFFFFF, .str = "9.007199254740991e+15"}, |
| {.want = 0x4340000000000000, .str = "9007199254740992"}, // 1 << 53. |
| {.want = 0x4340000000000000, .str = "9007199254740993"}, |
| {.want = 0x4340000000000001, .str = "9007199254740994"}, |
| {.want = 0x4340000000000002, .str = "9007199254740995"}, |
| {.want = 0x4340000000000002, .str = "9007199254740996"}, |
| {.want = 0x4340000000000002, .str = "9_007__199_254__740_996"}, |
| {.want = 0x4370000000000000, .str = "7.2057594037927933e+16"}, |
| {.want = 0x43E158E460913D00, .str = "9999999999999999999"}, |
| {.want = 0x43F002F1776DDA67, .str = "18459999196907202592"}, |
| {.want = 0x4415AF1D78B58C40, .str = "1e20"}, |
| {.want = 0x44B52D02C7E14AF6, .str = "1e+23"}, |
| {.want = 0x44B52D02C7E14AF6, .str = "1e23"}, |
| {.want = 0x46293E5939A08CEA, .str = "1e30"}, |
| {.want = 0x54B249AD2594C37D, .str = "+1E+100"}, |
| {.want = 0x54B249AD2594C37D, .str = "+_1_E_+_1_0_0_"}, |
| {.want = 0x7BBA44DF832B8D46, .str = "1e+288"}, |
| {.want = 0x7BF06B0BB1FB384C, .str = "1e+289"}, |
| {.want = 0x7C2485CE9E7A065F, .str = "1e+290"}, |
| {.want = 0x7FAC7B1F3CAC7433, .str = "9999999999999999999e+288"}, |
| {.want = 0x7FE1CCF385EBC8A0, .str = "9999999999999999999e+289"}, |
| {.want = 0x7FEFFFFFFFFFFFFF, .str = "1.7976931348623157e308"}, |
| {.want = 0x7FF0000000000000, .str = "1.8e308"}, |
| {.want = 0x7FF0000000000000, .str = "1e+316"}, |
| {.want = 0x7FF0000000000000, |
| .str = "10000000000000000000000000000000000000000000e+308"}, |
| {.want = 0x7FF0000000000000, .str = "1e999"}, |
| {.want = 0x7FF0000000000000, .str = "9999999999999999999e+290"}, |
| {.want = 0x7FF0000000000000, .str = "__InFinity__"}, |
| {.want = 0x7FF0000000000000, .str = "inf"}, |
| {.want = 0x7FFFFFFFFFFFFFFF, .str = "+nan"}, |
| {.want = 0x7FFFFFFFFFFFFFFF, .str = "_+_NaN_"}, |
| {.want = 0x7FFFFFFFFFFFFFFF, .str = "nan"}, |
| {.want = 0x8000000000000000, .str = "-0.000e0"}, |
| {.want = 0xC008000000000000, .str = "-3"}, |
| {.want = 0xFFF0000000000000, .str = "-2e308"}, |
| {.want = 0xFFF0000000000000, .str = "-inf"}, |
| {.want = 0xFFFFFFFFFFFFFFFF, .str = "-NAN"}, |
| |
| // If adding new cases, consider updating u64TestCases in |
| // script/print-render-number-f64-tests.go |
| |
| {.want = fail, .str = " 0"}, |
| {.want = fail, .str = ""}, |
| {.want = fail, .str = "."}, |
| {.want = fail, .str = "00"}, |
| {.want = fail, .str = "001.2"}, |
| {.want = fail, .str = "06.44"}, |
| {.want = fail, .str = "0644"}, |
| {.want = fail, .str = "1234 67.8e9"}, |
| {.want = fail, .str = "2,345,678"}, // Two ','s. |
| {.want = fail, .str = "2.345,678"}, // One '.' and one ','. |
| {.want = fail, .str = "7 "}, |
| {.want = fail, .str = "7 .9"}, |
| {.want = fail, .str = "7e"}, |
| {.want = fail, .str = "7e-"}, |
| {.want = fail, .str = "7e-+1"}, |
| {.want = fail, .str = "7e++1"}, |
| {.want = fail, .str = "NAN "}, |
| {.want = fail, .str = "NANA"}, |
| {.want = fail, .str = "inf_inity"}, |
| {.want = fail, .str = "nun"}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__result_f64 r = wuffs_base__parse_number_f64( |
| wuffs_base__make_slice_u8((void*)test_cases[tc].str, |
| strlen(test_cases[tc].str)), |
| WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES); |
| uint64_t have = |
| (r.status.repr == NULL) |
| ? wuffs_base__ieee_754_bit_representation__from_f64_to_u64(r.value) |
| : fail; |
| if (have != test_cases[tc].want) { |
| RETURN_FAIL("\"%s\": have 0x%016" PRIX64 ", want 0x%016" PRIX64, |
| test_cases[tc].str, have, test_cases[tc].want); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_parse_number_i64() { |
| CHECK_FOCUS(__func__); |
| |
| const int64_t fail = 0xDEADBEEF; |
| |
| struct { |
| int64_t want; |
| const char* str; |
| } test_cases[] = { |
| {.want = +0x0000000000000000, .str = "+0"}, |
| {.want = +0x0000000000000000, .str = "-0"}, |
| {.want = +0x0000000000000000, .str = "0"}, |
| {.want = +0x000000000000012C, .str = "+300"}, |
| {.want = +0x7FFFFFFFFFFFFFFF, .str = "+9223372036854775807"}, |
| {.want = +0x7FFFFFFFFFFFFFFF, .str = "9223372036854775807"}, |
| {.want = -0x0000000000000002, .str = "-2"}, |
| {.want = -0x00000000000000AB, .str = "_-_0x_AB"}, |
| {.want = -0x7FFFFFFFFFFFFFFF, .str = "-9223372036854775807"}, |
| {.want = -0x8000000000000000, .str = "-9223372036854775808"}, |
| |
| {.want = fail, .str = "+ 1"}, |
| {.want = fail, .str = "++1"}, |
| {.want = fail, .str = "+-1"}, |
| {.want = fail, .str = "+9223372036854775808"}, // 1 << 63. |
| {.want = fail, .str = "-"}, |
| {.want = fail, .str = "-+1"}, |
| {.want = fail, .str = "-0x8000000000000001"}, // -((1 << 63) + 1). |
| {.want = fail, .str = "-9223372036854775809"}, // -((1 << 63) + 1). |
| {.want = fail, .str = "0x8000000000000000"}, // 1 << 63. |
| {.want = fail, .str = "1-"}, |
| {.want = fail, .str = "9223372036854775808"}, // 1 << 63. |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__result_i64 r = wuffs_base__parse_number_i64( |
| wuffs_base__make_slice_u8((void*)test_cases[tc].str, |
| strlen(test_cases[tc].str)), |
| WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES); |
| int64_t have = (r.status.repr == NULL) ? r.value : fail; |
| if (have != test_cases[tc].want) { |
| RETURN_FAIL("\"%s\": have 0x%" PRIX64 ", want 0x%" PRIX64, |
| test_cases[tc].str, have, test_cases[tc].want); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_parse_number_u64() { |
| CHECK_FOCUS(__func__); |
| |
| const uint64_t fail = 0xDEADBEEF; |
| |
| struct { |
| uint64_t want; |
| const char* str; |
| } test_cases[] = { |
| {.want = 0x0000000000000000, .str = "0"}, |
| {.want = 0x0000000000000000, .str = "0_"}, |
| {.want = 0x0000000000000000, .str = "0d0"}, |
| {.want = 0x0000000000000000, .str = "0x000"}, |
| {.want = 0x0000000000000000, .str = "_0"}, |
| {.want = 0x0000000000000000, .str = "__0__"}, |
| {.want = 0x000000000000004A, .str = "0x4A"}, |
| {.want = 0x000000000000004B, .str = "0x__4_B_"}, |
| {.want = 0x000000000000007B, .str = "123"}, |
| {.want = 0x000000000000007C, .str = "12_4"}, |
| {.want = 0x000000000000007D, .str = "_1__2________5_"}, |
| {.want = 0x00000000000001F4, .str = "0d500"}, |
| {.want = 0x00000000000001F5, .str = "0D___5_01__"}, |
| {.want = 0x00000000FFFFFFFF, .str = "4294967295"}, |
| {.want = 0x0000000100000000, .str = "4294967296"}, |
| {.want = 0x0123456789ABCDEF, .str = "0x0123456789ABCDEF"}, |
| {.want = 0x0123456789ABCDEF, .str = "0x0123456789abcdef"}, |
| {.want = 0xFFFFFFFFFFFFFFF9, .str = "18446744073709551609"}, |
| {.want = 0xFFFFFFFFFFFFFFFA, .str = "18446744073709551610"}, |
| {.want = 0xFFFFFFFFFFFFFFFE, .str = "0xFFFFffffFFFFfffe"}, |
| {.want = 0xFFFFFFFFFFFFFFFE, .str = "18446744073709551614"}, |
| {.want = 0xFFFFFFFFFFFFFFFF, .str = "0xFFFF_FFFF_FFFF_FFFF"}, |
| {.want = 0xFFFFFFFFFFFFFFFF, .str = "18446744073709551615"}, |
| |
| {.want = fail, .str = " "}, |
| {.want = fail, .str = " 0"}, |
| {.want = fail, .str = " 12 "}, |
| {.want = fail, .str = ""}, |
| {.want = fail, .str = "+0"}, |
| {.want = fail, .str = "+1"}, |
| {.want = fail, .str = "-0"}, |
| {.want = fail, .str = "-1"}, |
| {.want = fail, .str = "0 "}, |
| {.want = fail, .str = "00"}, |
| {.want = fail, .str = "000000x"}, |
| {.want = fail, .str = "000000x0"}, |
| {.want = fail, .str = "007"}, |
| {.want = fail, .str = "0644"}, |
| {.want = fail, .str = "0_0"}, |
| {.want = fail, .str = "0_x1"}, |
| {.want = fail, .str = "0d___"}, |
| {.want = fail, .str = "0x"}, |
| {.want = fail, .str = "0x10000000000000000"}, // 1 << 64. |
| {.want = fail, .str = "0x1_0000_0000_0000_0000"}, // 1 << 64. |
| {.want = fail, .str = "1 23"}, |
| {.want = fail, .str = "1,23"}, |
| {.want = fail, .str = "1.23"}, |
| {.want = fail, .str = "123 "}, |
| {.want = fail, .str = "123456789012345678901234"}, |
| {.want = fail, .str = "12a3"}, |
| {.want = fail, .str = "18446744073709551616"}, // UINT64_MAX. |
| {.want = fail, .str = "18446744073709551617"}, |
| {.want = fail, .str = "18446744073709551618"}, |
| {.want = fail, .str = "18446744073709551619"}, |
| {.want = fail, .str = "18446744073709551620"}, |
| {.want = fail, .str = "18446744073709551621"}, |
| {.want = fail, .str = "_"}, |
| {.want = fail, .str = "d"}, |
| {.want = fail, .str = "x"}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__result_u64 r = wuffs_base__parse_number_u64( |
| wuffs_base__make_slice_u8((void*)test_cases[tc].str, |
| strlen(test_cases[tc].str)), |
| WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES); |
| uint64_t have = (r.status.repr == NULL) ? r.value : fail; |
| if (have != test_cases[tc].want) { |
| RETURN_FAIL("\"%s\": have 0x%" PRIX64 ", want 0x%" PRIX64, |
| test_cases[tc].str, have, test_cases[tc].want); |
| } |
| } |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_MULTIPLE_LEADING_ZEROES. |
| { |
| for (int o = 0; o < 2; o++) { |
| const char* str = "007"; |
| wuffs_base__result_u64 r = wuffs_base__parse_number_u64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| (o ? WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_MULTIPLE_LEADING_ZEROES |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o == 0) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL( |
| "ALLOW_MULTIPLE_LEADING_ZEROES off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| CHECK_STATUS("ALLOW_MULTIPLE_LEADING_ZEROES on", r.status); |
| uint64_t want = 7; |
| if (r.value != want) { |
| RETURN_FAIL("ALLOW_MULTIPLE_LEADING_ZEROES on: have %" PRIu64 |
| ", want %" PRIu64, |
| r.value, want); |
| } |
| } |
| } |
| |
| // Test WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES. |
| { |
| for (int o = 0; o < 2; o++) { |
| const char* str = "56_7__8"; |
| wuffs_base__result_u64 r = wuffs_base__parse_number_u64( |
| wuffs_base__make_slice_u8((void*)str, strlen(str)), |
| (o ? WUFFS_BASE__PARSE_NUMBER_XXX__ALLOW_UNDERSCORES |
| : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS)); |
| |
| if (o == 0) { |
| if (r.status.repr != wuffs_base__error__bad_argument) { |
| RETURN_FAIL( |
| "ALLOW_MULTIPLE_LEADING_ZEROES off: have \"%s\", want \"%s\"", |
| r.status.repr, wuffs_base__error__bad_argument); |
| } |
| continue; |
| } |
| |
| CHECK_STATUS("ALLOW_MULTIPLE_LEADING_ZEROES on", r.status); |
| uint64_t want = 5678; |
| if (r.value != want) { |
| RETURN_FAIL("ALLOW_MULTIPLE_LEADING_ZEROES on: have %" PRIu64 |
| ", want %" PRIu64, |
| r.value, want); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- |
| |
| const char* // |
| test_wuffs_strconv_render_number_f64() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| uint64_t x; |
| // These want strings come from Go's strconv.FormatFloat. |
| const char* want__e; // FormatFloat(etc, 'e', -1, etc) |
| const char* want__f; // FormatFloat(etc, 'f', -1, etc) |
| const char* want_0g; // FormatFloat(etc, 'g', +0, etc) |
| const char* want_2e; // FormatFloat(etc, 'e', +2, etc) |
| const char* want_3f; // FormatFloat(etc, 'f', +3, etc) |
| const char* want_4g; // FormatFloat(etc, 'g', +4, etc) |
| } test_cases[] = { |
| // These test cases were generated by |
| // script/print-render-number-f64-tests.go |
| |
| { |
| .x = 0x0000000000000000, |
| .want__e = "0e+00", |
| .want__f = "0", |
| .want_0g = "0", |
| .want_2e = "0.00e+00", |
| .want_3f = "0.000", |
| .want_4g = "0", |
| }, |
| { |
| .x = 0x0000000000000001, |
| .want__e = "5e-324", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000005", |
| .want_0g = "5e-324", |
| .want_2e = "4.94e-324", |
| .want_3f = "0.000", |
| .want_4g = "4.941e-324", |
| }, |
| { |
| .x = 0x0000000000000002, |
| .want__e = "1e-323", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "0000000000000000000000001", |
| .want_0g = "1e-323", |
| .want_2e = "9.88e-324", |
| .want_3f = "0.000", |
| .want_4g = "9.881e-324", |
| }, |
| { |
| .x = 0x0000000000000003, |
| .want__e = "1.5e-323", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000015", |
| .want_0g = "1e-323", |
| .want_2e = "1.48e-323", |
| .want_3f = "0.000", |
| .want_4g = "1.482e-323", |
| }, |
| { |
| .x = 0x000730D67819E8D2, |
| .want__e = "1e-308", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "0000000001", |
| .want_0g = "1e-308", |
| .want_2e = "1.00e-308", |
| .want_3f = "0.000", |
| .want_4g = "1e-308", |
| }, |
| { |
| .x = 0x000FFFFFFFFFFFFF, |
| .want__e = "2.225073858507201e-308", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "0000000002225073858507201", |
| .want_0g = "2e-308", |
| .want_2e = "2.23e-308", |
| .want_3f = "0.000", |
| .want_4g = "2.225e-308", |
| }, |
| { |
| .x = 0x0010000000000000, |
| .want__e = "2.2250738585072014e-308", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000022250738585072014", |
| .want_0g = "2e-308", |
| .want_2e = "2.23e-308", |
| .want_3f = "0.000", |
| .want_4g = "2.225e-308", |
| }, |
| { |
| .x = 0x0031FA182C40C60D, |
| .want__e = "1e-307", |
| .want__f = "0.000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "000000001", |
| .want_0g = "1e-307", |
| .want_2e = "1.00e-307", |
| .want_3f = "0.000", |
| .want_4g = "1e-307", |
| }, |
| { |
| .x = 0x369C2DF8DA5B6CA8, |
| .want__e = "1.234e-45", |
| .want__f = "0.000000000000000000000000000000000000000000001234", |
| .want_0g = "1e-45", |
| .want_2e = "1.23e-45", |
| .want_3f = "0.000", |
| .want_4g = "1.234e-45", |
| }, |
| { |
| .x = 0x369C314ABE948EB1, |
| .want__e = "1.23456789e-45", |
| .want__f = "0.000000000000000000000000000000000000000000001234" |
| "56789", |
| .want_0g = "1e-45", |
| .want_2e = "1.23e-45", |
| .want_3f = "0.000", |
| .want_4g = "1.235e-45", |
| }, |
| { |
| .x = 0x3E70000000000000, |
| .want__e = "5.960464477539063e-08", |
| .want__f = "0.00000005960464477539063", |
| .want_0g = "6e-08", |
| .want_2e = "5.96e-08", |
| .want_3f = "0.000", |
| .want_4g = "5.96e-08", |
| }, |
| { |
| .x = 0x3F88000000000000, |
| .want__e = "1.171875e-02", |
| .want__f = "0.01171875", |
| .want_0g = "0.01", |
| .want_2e = "1.17e-02", |
| .want_3f = "0.012", |
| .want_4g = "0.01172", |
| }, |
| { |
| .x = 0x3FD0000000000000, |
| .want__e = "2.5e-01", |
| .want__f = "0.25", |
| .want_0g = "0.2", |
| .want_2e = "2.50e-01", |
| .want_3f = "0.250", |
| .want_4g = "0.25", |
| }, |
| { |
| .x = 0x3FD3333333333333, |
| .want__e = "3e-01", |
| .want__f = "0.3", |
| .want_0g = "0.3", |
| .want_2e = "3.00e-01", |
| .want_3f = "0.300", |
| .want_4g = "0.3", |
| }, |
| { |
| .x = 0x3FD3333333333334, |
| .want__e = "3.0000000000000004e-01", |
| .want__f = "0.30000000000000004", |
| .want_0g = "0.3", |
| .want_2e = "3.00e-01", |
| .want_3f = "0.300", |
| .want_4g = "0.3", |
| }, |
| { |
| .x = 0x3FD5555555555555, |
| .want__e = "3.333333333333333e-01", |
| .want__f = "0.3333333333333333", |
| .want_0g = "0.3", |
| .want_2e = "3.33e-01", |
| .want_3f = "0.333", |
| .want_4g = "0.3333", |
| }, |
| { |
| .x = 0x3FEFFFFFFFFFFFFF, |
| .want__e = "9.999999999999999e-01", |
| .want__f = "0.9999999999999999", |
| .want_0g = "1", |
| .want_2e = "1.00e+00", |
| .want_3f = "1.000", |
| .want_4g = "1", |
| }, |
| { |
| .x = 0x3FF0000000000000, |
| .want__e = "1e+00", |
| .want__f = "1", |
| .want_0g = "1", |
| .want_2e = "1.00e+00", |
| .want_3f = "1.000", |
| .want_4g = "1", |
| }, |
| { |
| .x = 0x3FF0000000000001, |
| .want__e = "1.0000000000000002e+00", |
| .want__f = "1.0000000000000002", |
| .want_0g = "1", |
| .want_2e = "1.00e+00", |
| .want_3f = "1.000", |
| .want_4g = "1", |
| }, |
| { |
| .x = 0x3FF0000000000002, |
| .want__e = "1.0000000000000004e+00", |
| .want__f = "1.0000000000000004", |
| .want_0g = "1", |
| .want_2e = "1.00e+00", |
| .want_3f = "1.000", |
| .want_4g = "1", |
| }, |
| { |
| .x = 0x3FF4000000000000, |
| .want__e = "1.25e+00", |
| .want__f = "1.25", |
| .want_0g = "1", |
| .want_2e = "1.25e+00", |
| .want_3f = "1.250", |
| .want_4g = "1.25", |
| }, |
| { |
| .x = 0x3FF8000000000000, |
| .want__e = "1.5e+00", |
| .want__f = "1.5", |
| .want_0g = "2", |
| .want_2e = "1.50e+00", |
| .want_3f = "1.500", |
| .want_4g = "1.5", |
| }, |
| { |
| .x = 0x400599999999999A, |
| .want__e = "2.7e+00", |
| .want__f = "2.7", |
| .want_0g = "3", |
| .want_2e = "2.70e+00", |
| .want_3f = "2.700", |
| .want_4g = "2.7", |
| }, |
| { |
| .x = 0x4005BE76C8B43958, |
| .want__e = "2.718e+00", |
| .want__f = "2.718", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005BF0995AAF790, |
| .want__e = "2.71828e+00", |
| .want__f = "2.71828", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005BF0A87427F01, |
| .want__e = "2.7182818e+00", |
| .want__f = "2.7182818", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005BF0A8B4949CB, |
| .want__e = "2.71828183e+00", |
| .want__f = "2.71828183", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005BF0AA21A719B, |
| .want__e = "2.718282e+00", |
| .want__f = "2.718282", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005BF141205BC02, |
| .want__e = "2.7183e+00", |
| .want__f = "2.7183", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.718", |
| .want_4g = "2.718", |
| }, |
| { |
| .x = 0x4005C28F5C28F5C3, |
| .want__e = "2.72e+00", |
| .want__f = "2.72", |
| .want_0g = "3", |
| .want_2e = "2.72e+00", |
| .want_3f = "2.720", |
| .want_4g = "2.72", |
| }, |
| { |
| .x = 0x4008000000000000, |
| .want__e = "3e+00", |
| .want__f = "3", |
| .want_0g = "3", |
| .want_2e = "3.00e+00", |
| .want_3f = "3.000", |
| .want_4g = "3", |
| }, |
| { |
| .x = 0x400921F9F01B866E, |
| .want__e = "3.14159e+00", |
| .want__f = "3.14159", |
| .want_0g = "3", |
| .want_2e = "3.14e+00", |
| .want_3f = "3.142", |
| .want_4g = "3.142", |
| }, |
| { |
| .x = 0x400921FB54442D11, |
| .want__e = "3.14159265358979e+00", |
| .want__f = "3.14159265358979", |
| .want_0g = "3", |
| .want_2e = "3.14e+00", |
| .want_3f = "3.142", |
| .want_4g = "3.142", |
| }, |
| { |
| .x = 0x400921FB54442D18, |
| .want__e = "3.141592653589793e+00", |
| .want__f = "3.141592653589793", |
| .want_0g = "3", |
| .want_2e = "3.14e+00", |
| .want_3f = "3.142", |
| .want_4g = "3.142", |
| }, |
| { |
| .x = 0x400C000000000000, |
| .want__e = "3.5e+00", |
| .want__f = "3.5", |
| .want_0g = "4", |
| .want_2e = "3.50e+00", |
| .want_3f = "3.500", |
| .want_4g = "3.5", |
| }, |
| { |
| .x = 0x4014000000000000, |
| .want__e = "5e+00", |
| .want__f = "5", |
| .want_0g = "5", |
| .want_2e = "5.00e+00", |
| .want_3f = "5.000", |
| .want_4g = "5", |
| }, |
| { |
| .x = 0x4036000000000000, |
| .want__e = "2.2e+01", |
| .want__f = "22", |
| .want_0g = "2e+01", |
| .want_2e = "2.20e+01", |
| .want_3f = "22.000", |
| .want_4g = "22", |
| }, |
| { |
| .x = 0x4037000000000000, |
| .want__e = "2.3e+01", |
| .want__f = "23", |
| .want_0g = "2e+01", |
| .want_2e = "2.30e+01", |
| .want_3f = "23.000", |
| .want_4g = "23", |
| }, |
| { |
| .x = 0x4038000000000000, |
| .want__e = "2.4e+01", |
| .want__f = "24", |
| .want_0g = "2e+01", |
| .want_2e = "2.40e+01", |
| .want_3f = "24.000", |
| .want_4g = "24", |
| }, |
| { |
| .x = 0x405E9AA48FBB2888, |
| .want__e = "1.2241629403378658e+02", |
| .want__f = "122.41629403378658", |
| .want_0g = "1e+02", |
| .want_2e = "1.22e+02", |
| .want_3f = "122.416", |
| .want_4g = "122.4", |
| }, |
| { |
| .x = 0x40FE240C9FCB0C02, |
| .want__e = "1.23456789012e+05", |
| .want__f = "123456.789012", |
| .want_0g = "1e+05", |
| .want_2e = "1.23e+05", |
| .want_3f = "123456.789", |
| .want_4g = "1.235e+05", |
| }, |
| { |
| .x = 0x41E0246690000001, |
| .want__e = "2.1665680640000005e+09", |
| .want__f = "2166568064.0000005", |
| .want_0g = "2e+09", |
| .want_2e = "2.17e+09", |
| .want_3f = "2166568064.000", |
| .want_4g = "2.167e+09", |
| }, |
| { |
| .x = 0x4202A05F20000000, |
| .want__e = "1e+10", |
| .want__f = "10000000000", |
| .want_0g = "1e+10", |
| .want_2e = "1.00e+10", |
| .want_3f = "10000000000.000", |
| .want_4g = "1e+10", |
| }, |
| { |
| .x = 0x4330000000000000, |
| .want__e = "4.503599627370496e+15", |
| .want__f = "4503599627370496", |
| .want_0g = "5e+15", |
| .want_2e = "4.50e+15", |
| .want_3f = "4503599627370496.000", |
| .want_4g = "4.504e+15", |
| }, |
| { |
| .x = 0x4330000000000001, |
| .want__e = "4.503599627370497e+15", |
| .want__f = "4503599627370497", |
| .want_0g = "5e+15", |
| .want_2e = "4.50e+15", |
| .want_3f = "4503599627370497.000", |
| .want_4g = "4.504e+15", |
| }, |
| { |
| .x = 0x4330000000000002, |
| .want__e = "4.503599627370498e+15", |
| .want__f = "4503599627370498", |
| .want_0g = "5e+15", |
| .want_2e = "4.50e+15", |
| .want_3f = "4503599627370498.000", |
| .want_4g = "4.504e+15", |
| }, |
| { |
| .x = 0x433FFFFFFFFFFFFE, |
| .want__e = "9.00719925474099e+15", |
| .want__f = "9007199254740990", |
| .want_0g = "9e+15", |
| .want_2e = "9.01e+15", |
| .want_3f = "9007199254740990.000", |
| .want_4g = "9.007e+15", |
| }, |
| { |
| .x = 0x433FFFFFFFFFFFFF, |
| .want__e = "9.007199254740991e+15", |
| .want__f = "9007199254740991", |
| .want_0g = "9e+15", |
| .want_2e = "9.01e+15", |
| .want_3f = "9007199254740991.000", |
| .want_4g = "9.007e+15", |
| }, |
| { |
| .x = 0x4340000000000000, |
| .want__e = "9.007199254740992e+15", |
| .want__f = "9007199254740992", |
| .want_0g = "9e+15", |
| .want_2e = "9.01e+15", |
| .want_3f = "9007199254740992.000", |
| .want_4g = "9.007e+15", |
| }, |
| { |
| .x = 0x4340000000000001, |
| .want__e = "9.007199254740994e+15", |
| .want__f = "9007199254740994", |
| .want_0g = "9e+15", |
| .want_2e = "9.01e+15", |
| .want_3f = "9007199254740994.000", |
| .want_4g = "9.007e+15", |
| }, |
| { |
| .x = 0x4340000000000002, |
| .want__e = "9.007199254740996e+15", |
| .want__f = "9007199254740996", |
| .want_0g = "9e+15", |
| .want_2e = "9.01e+15", |
| .want_3f = "9007199254740996.000", |
| .want_4g = "9.007e+15", |
| }, |
| { |
| .x = 0x4370000000000000, |
| .want__e = "7.205759403792794e+16", |
| .want__f = "72057594037927940", |
| .want_0g = "7e+16", |
| .want_2e = "7.21e+16", |
| .want_3f = "72057594037927936.000", |
| .want_4g = "7.206e+16", |
| }, |
| { |
| .x = 0x43E158E460913D00, |
| .want__e = "1e+19", |
| .want__f = "10000000000000000000", |
| .want_0g = "1e+19", |
| .want_2e = "1.00e+19", |
| .want_3f = "10000000000000000000.000", |
| .want_4g = "1e+19", |
| }, |
| { |
| .x = 0x43F002F1776DDA67, |
| .want__e = "1.8459999196907205e+19", |
| .want__f = "18459999196907205000", |
| .want_0g = "2e+19", |
| .want_2e = "1.85e+19", |
| .want_3f = "18459999196907204608.000", |
| .want_4g = "1.846e+19", |
| }, |
| { |
| .x = 0x4415AF1D78B58C40, |
| .want__e = "1e+20", |
| .want__f = "100000000000000000000", |
| .want_0g = "1e+20", |
| .want_2e = "1.00e+20", |
| .want_3f = "100000000000000000000.000", |
| .want_4g = "1e+20", |
| }, |
| { |
| .x = 0x44B52D02C7E14AF6, |
| .want__e = "1e+23", |
| .want__f = "100000000000000000000000", |
| .want_0g = "1e+23", |
| .want_2e = "1.00e+23", |
| .want_3f = "99999999999999991611392.000", |
| .want_4g = "1e+23", |
| }, |
| { |
| .x = 0x44DFC3842BD1F072, |
| .want__e = "6e+23", |
| .want__f = "600000000000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.00e+23", |
| .want_3f = "600000000000000016777216.000", |
| .want_4g = "6e+23", |
| }, |
| { |
| .x = 0x44DFDE9F10A8D361, |
| .want__e = "6.02e+23", |
| .want__f = "602000000000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "601999999999999995805696.000", |
| .want_4g = "6.02e+23", |
| }, |
| { |
| .x = 0x44DFE154F457EA13, |
| .want__e = "6.022e+23", |
| .want__f = "602200000000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602200000000000027262976.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x44DFE177A620AB35, |
| .want__e = "6.0221e+23", |
| .want__f = "602210000000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602209999999999995281408.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x44DFE18586D75EDC, |
| .want__e = "6.02214e+23", |
| .want__f = "602214000000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602213999999999969067008.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x44DFE185CA57C517, |
| .want__e = "6.02214076e+23", |
| .want__f = "602214076000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602214075999999987023872.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x44DFE185CDE543BC, |
| .want__e = "6.0221408e+23", |
| .want__f = "602214080000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602214080000000002097152.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x44DFE185DFA8BCF4, |
| .want__e = "6.022141e+23", |
| .want__f = "602214100000000000000000", |
| .want_0g = "6e+23", |
| .want_2e = "6.02e+23", |
| .want_3f = "602214100000000010354688.000", |
| .want_4g = "6.022e+23", |
| }, |
| { |
| .x = 0x46293E5939A08CEA, |
| .want__e = "1e+30", |
| .want__f = "1000000000000000000000000000000", |
| .want_0g = "1e+30", |
| .want_2e = "1.00e+30", |
| .want_3f = "1000000000000000019884624838656.000", |
| .want_4g = "1e+30", |
| }, |
| { |
| .x = 0x54B249AD2594C37D, |
| .want__e = "1e+100", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "0", |
| .want_0g = "1e+100", |
| .want_2e = "1.00e+100", |
| .want_3f = "10000000000000000159028911097599180468360808563945" |
| "28138978132755774783877217038106081346998585681510" |
| "4.000", |
| .want_4g = "1e+100", |
| }, |
| { |
| .x = 0x7BBA44DF832B8D46, |
| .want__e = "1e+288", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "000000000000000000000000000000000000000", |
| .want_0g = "1e+288", |
| .want_2e = "1.00e+288", |
| .want_3f = "10000000000000000076304735395750356605147783355117" |
| "10750780086664439969510636494954611131549135839186" |
| "51398345555539522089568786054480958499982972526059" |
| "48732710873996264866061464425509888400169173946264" |
| "49536395208620267012778077787723395914064607119962" |
| "069483324573977857832138825282954985472.000", |
| .want_4g = "1e+288", |
| }, |
| { |
| .x = 0x7BF06B0BB1FB384C, |
| .want__e = "1e+289", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "0000000000000000000000000000000000000000", |
| .want_0g = "1e+289", |
| .want_2e = "1.00e+289", |
| .want_3f = "10000000000000000617278335278671568869943723109630" |
| "11258310052850538813376539671558942539170944464796" |
| "69431045845149126131034590785433956171738211535366" |
| "98722855425910210916188218613474303381375362727338" |
| "59602462772449948462578903480308154011242367042019" |
| "1213257583185130503608895092113260150784.000", |
| .want_4g = "1e+289", |
| }, |
| { |
| .x = 0x7C2485CE9E7A065F, |
| .want__e = "1e+290", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000", |
| .want_0g = "1e+290", |
| .want_2e = "1.00e+290", |
| .want_3f = "10000000000000000617278335278671568869943723109630" |
| "11258310052850538813376539671558942539170944464796" |
| "69431045845149126131034590785433956171738211535366" |
| "98722855425910210916188218613474303381375362727338" |
| "59602462772449948462578903480308154011242367042019" |
| "12132575831851305036088950921132601507840.000", |
| .want_4g = "1e+290", |
| }, |
| { |
| .x = 0x7FAC7B1F3CAC7433, |
| .want__e = "1e+307", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000", |
| .want_0g = "1e+307", |
| .want_2e = "1.00e+307", |
| .want_3f = "99999999999999998603105976025645777170026418381263" |
| "63875249660735883565852672743849064846414228960666" |
| "78637928039265461539335317285025210333627595237061" |
| "53970107306916646893751785690398510731463396416232" |
| "66071126720011020169553304018596457812688561947201" |
| "17148846117292182213906692985128212200267666775002" |
| "1070848.000", |
| .want_4g = "1e+307", |
| }, |
| { |
| .x = 0x7FE1CCF385EBC8A0, |
| .want__e = "1e+308", |
| .want__f = "10000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "000000000", |
| .want_0g = "1e+308", |
| .want_2e = "1.00e+308", |
| .want_3f = "10000000000000000109790636294404554174049230967731" |
| "18463368106829031575854049114915371633289784946888" |
| "99061249669721172515611590283743140088328307009198" |
| "14604603127166450293302718569748969958855904333838" |
| "44661650011784268976262129451776280911957867074581" |
| "22783970171784415105291802893207873272974885715430" |
| "223118336.000", |
| .want_4g = "1e+308", |
| }, |
| { |
| .x = 0x7FEFFFFFFFFFFFFF, |
| .want__e = "1.7976931348623157e+308", |
| .want__f = "17976931348623157000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "00000000000000000000000000000000000000000000000000" |
| "000000000", |
| .want_0g = "2e+308", |
| .want_2e = "1.80e+308", |
| .want_3f = "17976931348623157081452742373170435679807056752584" |
| "49965989174768031572607800285387605895586327668781" |
| "71540458953514382464234321326889464182768467546703" |
| "53751698604991057655128207624549009038932894407586" |
| "85084551339423045832369032229481658085593321233482" |
| "74797826204144723168738177180919299881250404026184" |
| "124858368.000", |
| .want_4g = "1.798e+308", |
| }, |
| { |
| .x = 0x7FF0000000000000, |
| .want__e = "Inf", |
| .want__f = "Inf", |
| .want_0g = "Inf", |
| .want_2e = "Inf", |
| .want_3f = "Inf", |
| .want_4g = "Inf", |
| }, |
| { |
| .x = 0x7FFFFFFFFFFFFFFF, |
| .want__e = "NaN", |
| .want__f = "NaN", |
| .want_0g = "NaN", |
| .want_2e = "NaN", |
| .want_3f = "NaN", |
| .want_4g = "NaN", |
| }, |
| { |
| .x = 0x8000000000000000, |
| .want__e = "-0e+00", |
| .want__f = "-0", |
| .want_0g = "-0", |
| .want_2e = "-0.00e+00", |
| .want_3f = "-0.000", |
| .want_4g = "-0", |
| }, |
| { |
| .x = 0xC008000000000000, |
| .want__e = "-3e+00", |
| .want__f = "-3", |
| .want_0g = "-3", |
| .want_2e = "-3.00e+00", |
| .want_3f = "-3.000", |
| .want_4g = "-3", |
| }, |
| { |
| .x = 0xFFF0000000000000, |
| .want__e = "-Inf", |
| .want__f = "-Inf", |
| .want_0g = "-Inf", |
| .want_2e = "-Inf", |
| .want_3f = "-Inf", |
| .want_4g = "-Inf", |
| }, |
| { |
| .x = 0xFFFFFFFFFFFFFFFF, |
| .want__e = "NaN", |
| .want__f = "NaN", |
| .want_0g = "NaN", |
| .want_2e = "NaN", |
| .want_3f = "NaN", |
| .want_4g = "NaN", |
| }, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| double f64 = wuffs_base__ieee_754_bit_representation__from_u64_to_f64( |
| test_cases[tc].x); |
| for (int o = 0; o < 6; o++) { |
| uint32_t precision = 0; |
| uint32_t options = 0; |
| const char* want = NULL; |
| if (o == 0) { |
| options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT | |
| WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION; |
| want = test_cases[tc].want__e; |
| } else if (o == 1) { |
| options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT | |
| WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION; |
| want = test_cases[tc].want__f; |
| } else if (o == 2) { |
| precision = 0; |
| options = 0; |
| want = test_cases[tc].want_0g; |
| } else if (o == 3) { |
| precision = 2; |
| options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT; |
| want = test_cases[tc].want_2e; |
| } else if (o == 4) { |
| precision = 3; |
| options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT; |
| want = test_cases[tc].want_3f; |
| } else if (o == 5) { |
| precision = 4; |
| options = 0; |
| want = test_cases[tc].want_4g; |
| } |
| |
| size_t n = wuffs_base__render_number_f64(g_have_slice_u8, f64, precision, |
| options); |
| if (n == 0) { |
| RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: could not render", |
| test_cases[tc].x, o); |
| } else if (n >= g_have_slice_u8.len) { |
| RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: n is too large", |
| test_cases[tc].x, o); |
| } |
| g_have_slice_u8.ptr[n] = 0x00; |
| if (strcmp((const char*)(g_have_slice_u8.ptr), want) != 0) { |
| RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: have \"%s\", want \"%s\"", |
| test_cases[tc].x, o, g_have_slice_u8.ptr, want); |
| } |
| } |
| } |
| |
| // Test WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA. |
| { |
| for (int o = 0; o < 2; o++) { |
| uint8_t dst[8] = {0}; |
| const double f64 = 1.75; |
| const uint32_t precision = 2; |
| size_t n = wuffs_base__render_number_f64( |
| wuffs_base__make_slice_u8(&dst[0], WUFFS_TESTLIB_ARRAY_SIZE(dst)), |
| f64, precision, |
| WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT | |
| (o ? WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA |
| : 0)); |
| if (n != 4) { |
| RETURN_FAIL("DECIMAL_SEPARATOR_IS_A_COMMA, o=%d: n != 4", o); |
| } |
| uint8_t have = dst[1]; |
| uint8_t want = o ? ',' : '.'; |
| if (have != want) { |
| RETURN_FAIL( |
| "DECIMAL_SEPARATOR_IS_A_COMMA, o=%d: have 0x%02X, want 0x%02X", o, |
| (int)have, (int)want); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_render_number_i64() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| int64_t x; |
| const char* want; |
| } test_cases[] = { |
| {.x = +0x0000000000000000ll, .want = "0"}, |
| {.x = +0x0000000000000009ll, .want = "9"}, |
| {.x = +0x000000000000000All, .want = "10"}, |
| {.x = +0x000000000000004All, .want = "74"}, |
| {.x = +0x0000000000000063ll, .want = "99"}, |
| {.x = +0x0000000000000064ll, .want = "100"}, |
| {.x = +0x000000000000007Cll, .want = "124"}, |
| {.x = +0x00000000000001F4ll, .want = "500"}, |
| {.x = +0x000000000000036Cll, .want = "876"}, |
| {.x = +0x000000000000036Fll, .want = "879"}, |
| {.x = +0x0000000000000929ll, .want = "2345"}, |
| {.x = +0x0000000000010932ll, .want = "67890"}, |
| {.x = +0x00000000FFFFFFFFll, .want = "4294967295"}, |
| {.x = +0x0000000100000000ll, .want = "4294967296"}, |
| {.x = +0x0123456789ABCDEFll, .want = "81985529216486895"}, |
| {.x = +0x7FFFFFFFFFFFFFFFll, .want = "9223372036854775807"}, |
| |
| {.x = -0x0000000000000009ll, .want = "-9"}, |
| {.x = -0x000000000000000All, .want = "-10"}, |
| {.x = -0x000000000000004All, .want = "-74"}, |
| {.x = -0x0000000000000063ll, .want = "-99"}, |
| {.x = -0x0000000000000064ll, .want = "-100"}, |
| {.x = -0x000000000000007Cll, .want = "-124"}, |
| {.x = -0x00000000000001F4ll, .want = "-500"}, |
| {.x = -0x000000000000036Cll, .want = "-876"}, |
| {.x = -0x000000000000036Fll, .want = "-879"}, |
| {.x = -0x0000000000000929ll, .want = "-2345"}, |
| {.x = -0x0000000000010932ll, .want = "-67890"}, |
| {.x = -0x00000000FFFFFFFFll, .want = "-4294967295"}, |
| {.x = -0x0000000100000000ll, .want = "-4294967296"}, |
| {.x = -0x0123456789ABCDEFll, .want = "-81985529216486895"}, |
| {.x = -0x7FFFFFFFFFFFFFFFll, .want = "-9223372036854775807"}, |
| {.x = -0x8000000000000000ll, .want = "-9223372036854775808"}, |
| }; |
| |
| if (g_have_slice_u8.len < WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL) { |
| return "g_have_slice_u8.len is too short"; |
| } |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| size_t n = wuffs_base__render_number_i64( |
| g_have_slice_u8, test_cases[tc].x, |
| WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS); |
| if (n == 0) { |
| RETURN_FAIL("%" PRId64 ": could not render", test_cases[tc].x); |
| } else if (n >= g_have_slice_u8.len) { |
| RETURN_FAIL("%" PRId64 ": n is too large", test_cases[tc].x); |
| } |
| g_have_slice_u8.ptr[n] = 0x00; |
| if (strcmp((const char*)(g_have_slice_u8.ptr), test_cases[tc].want) != 0) { |
| RETURN_FAIL("%" PRId64 ": have \"%s\", want \"%s\"", test_cases[tc].x, |
| g_have_slice_u8.ptr, test_cases[tc].want); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| test_wuffs_strconv_render_number_u64() { |
| CHECK_FOCUS(__func__); |
| |
| struct { |
| uint64_t x; |
| const char* want; |
| } test_cases[] = { |
| {.x = 0x0000000000000000, .want = "0"}, |
| {.x = 0x0000000000000009, .want = "9"}, |
| {.x = 0x000000000000000A, .want = "10"}, |
| {.x = 0x000000000000004A, .want = "74"}, |
| {.x = 0x0000000000000063, .want = "99"}, |
| {.x = 0x0000000000000064, .want = "100"}, |
| {.x = 0x000000000000007C, .want = "124"}, |
| {.x = 0x00000000000001F4, .want = "500"}, |
| {.x = 0x000000000000036C, .want = "876"}, |
| {.x = 0x000000000000036F, .want = "879"}, |
| {.x = 0x0000000000000929, .want = "2345"}, |
| {.x = 0x0000000000010932, .want = "67890"}, |
| {.x = 0x00000000FFFFFFFF, .want = "4294967295"}, |
| {.x = 0x0000000100000000, .want = "4294967296"}, |
| {.x = 0x0123456789ABCDEF, .want = "81985529216486895"}, |
| {.x = 0x7FFFFFFFFFFFFFFF, .want = "9223372036854775807"}, |
| {.x = 0x8000000000000000, .want = "9223372036854775808"}, |
| {.x = 0xFFFFFFFFFFFFFFF9, .want = "18446744073709551609"}, |
| {.x = 0xFFFFFFFFFFFFFFFA, .want = "18446744073709551610"}, |
| {.x = 0xFFFFFFFFFFFFFFFE, .want = "18446744073709551614"}, |
| {.x = 0xFFFFFFFFFFFFFFFF, .want = "18446744073709551615"}, |
| }; |
| |
| if (g_have_slice_u8.len < WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL) { |
| return "g_have_slice_u8.len is too short"; |
| } |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| size_t n = wuffs_base__render_number_u64( |
| g_have_slice_u8, test_cases[tc].x, |
| WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS); |
| if (n == 0) { |
| RETURN_FAIL("%" PRIu64 ": could not render", test_cases[tc].x); |
| } else if (n >= g_have_slice_u8.len) { |
| RETURN_FAIL("%" PRIu64 ": n is too large", test_cases[tc].x); |
| } |
| g_have_slice_u8.ptr[n] = 0x00; |
| if (strcmp((const char*)(g_have_slice_u8.ptr), test_cases[tc].want) != 0) { |
| RETURN_FAIL("%" PRIu64 ": have \"%s\", want \"%s\"", test_cases[tc].x, |
| g_have_slice_u8.ptr, test_cases[tc].want); |
| } |
| } |
| |
| // Test dst slice is too short. |
| { |
| uint8_t dst[5]; |
| size_t n = wuffs_base__render_number_u64( |
| wuffs_base__make_slice_u8(&dst[0], sizeof(dst)), 123456, |
| WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS); |
| if (n != 0) { |
| RETURN_FAIL("dst too short: have %zu, want 0", n); |
| } |
| } |
| |
| // Test options. |
| { |
| uint8_t dst[8]; |
| memcpy(&dst[0], "ABCDEFG\x00", 8); |
| size_t n = wuffs_base__render_number_u64( |
| wuffs_base__make_slice_u8(&dst[0], sizeof(dst) - 1), 1234, |
| WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT | |
| WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN); |
| if (n != 5) { |
| RETURN_FAIL("ALIGN_RIGHT | LEADING_PLUS_SIGN: have %zu, want 5", n); |
| } |
| uint64_t have = wuffs_base__peek_u64be__no_bounds_check(&dst[0]); |
| uint64_t want = 0x41422B3132333400; // "AB+1234\x00". |
| if (have != want) { |
| RETURN_FAIL("ALIGN_RIGHT | LEADING_PLUS_SIGN: have 0x%" PRIX64 |
| ", want 0x%" PRIX64, |
| have, want); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- |
| |
| const char* // |
| test_wuffs_strconv_utf_8_next() { |
| CHECK_FOCUS(__func__); |
| |
| // Special case the "\x00" string, which is valid UTF-8 but its strlen is |
| // zero, not one. |
| uint8_t the_nul_byte[1]; |
| the_nul_byte[0] = '\x00'; |
| |
| struct { |
| // The uint32_t want is packed as: |
| // - the high 8 bits are the byte length. |
| // - the low 24 bits are the code point. |
| uint32_t want0; // For wuffs_base__utf_8__next. |
| uint32_t want1; // For wuffs_base__utf_8__next_from_end. |
| const char* str; |
| } test_cases[] = { |
| {.want0 = 0x00000000, .want1 = 0x00000000, .str = ""}, |
| {.want0 = 0x01000000, .want1 = 0x01000000, .str = "The <NUL> byte"}, |
| {.want0 = 0x01000009, .want1 = 0x01000009, .str = "\t"}, |
| {.want0 = 0x01000041, .want1 = 0x01000041, .str = "A"}, |
| {.want0 = 0x01000061, .want1 = 0x0100006A, .str = "abdefghij"}, |
| {.want0 = 0x0100007F, .want1 = 0x0100007F, .str = "\x7F"}, |
| {.want0 = 0x02000080, .want1 = 0x02000080, .str = "\xC2\x80"}, |
| {.want0 = 0x020007FF, .want1 = 0x020007FF, .str = "\xDF\xBF"}, |
| {.want0 = 0x03000800, .want1 = 0x03000800, .str = "\xE0\xA0\x80"}, |
| {.want0 = 0x0300FFFD, .want1 = 0x0300FFFD, .str = "\xEF\xBF\xBD"}, |
| {.want0 = 0x0300FFFF, .want1 = 0x0300FFFF, .str = "\xEF\xBF\xBF"}, |
| {.want0 = 0x04010000, .want1 = 0x04010000, .str = "\xF0\x90\x80\x80"}, |
| {.want0 = 0x0410FFFF, .want1 = 0x0410FFFF, .str = "\xF4\x8F\xBF\xBF"}, |
| |
| // U+00000394 GREEK CAPITAL LETTER DELTA. |
| {.want0 = 0x02000394, .want1 = 0x02000394, .str = "\xCE\x94"}, |
| {.want0 = 0x02000394, .want1 = 0x01000070, .str = "\xCE\x94p"}, |
| {.want0 = 0x02000394, .want1 = 0x01000071, .str = "\xCE\x94pq"}, |
| {.want0 = 0x02000394, .want1 = 0x01000072, .str = "\xCE\x94pqr"}, |
| {.want0 = 0x02000394, .want1 = 0x01000073, .str = "\xCE\x94pqrs"}, |
| {.want0 = 0x02000394, .want1 = 0x0100FFFD, .str = "\xCE\x94\x80"}, |
| {.want0 = 0x02000394, .want1 = 0x0100FFFD, .str = "\xCE\x94\x80\x81"}, |
| {.want0 = 0x02000394, .want1 = 0x0100FFFD, .str = "\xCE\x94\x80\x81\x82"}, |
| {.want0 = 0x02000394, |
| .want1 = 0x0100FFFD, |
| .str = "\xCE\x94\x80\x81\x82\x83"}, |
| {.want0 = 0x01000070, .want1 = 0x02000394, .str = "p\xCE\x94"}, |
| |
| // U+00002603 SNOWMAN. |
| {.want0 = 0x03002603, .want1 = 0x03002603, .str = "\xE2\x98\x83"}, |
| {.want0 = 0x03002603, .want1 = 0x01000070, .str = "\xE2\x98\x83p"}, |
| {.want0 = 0x03002603, .want1 = 0x01000071, .str = "\xE2\x98\x83pq"}, |
| {.want0 = 0x03002603, .want1 = 0x01000072, .str = "\xE2\x98\x83pqr"}, |
| {.want0 = 0x03002603, .want1 = 0x01000073, .str = "\xE2\x98\x83pqrs"}, |
| {.want0 = 0x03002603, .want1 = 0x0100FFFD, .str = "\xE2\x98\x83\xFF"}, |
| {.want0 = 0x01000070, .want1 = 0x03002603, .str = "p\xE2\x98\x83"}, |
| |
| // U+0001F4A9 PILE OF POO. |
| {.want0 = 0x0401F4A9, .want1 = 0x0401F4A9, .str = "\xF0\x9F\x92\xA9"}, |
| {.want0 = 0x0401F4A9, .want1 = 0x01000070, .str = "\xF0\x9F\x92\xA9p"}, |
| {.want0 = 0x0401F4A9, .want1 = 0x01000071, .str = "\xF0\x9F\x92\xA9pq"}, |
| {.want0 = 0x0401F4A9, .want1 = 0x01000072, .str = "\xF0\x9F\x92\xA9pqr"}, |
| {.want0 = 0x0401F4A9, .want1 = 0x01000073, .str = "\xF0\x9F\x92\xA9pqrs"}, |
| {.want0 = 0x0401F4A9, .want1 = 0x0100FFFD, .str = "\xF0\x9F\x92\xA9\xFF"}, |
| {.want0 = 0x01000070, .want1 = 0x0401F4A9, .str = "p\xF0\x9F\x92\xA9"}, |
| |
| // Invalid. |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\x80"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xBF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xC0\x80"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xC1\xBF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xC2"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100007F, .str = "\xC2\x7F"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xC2\xC0"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xC2\xFF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xCE"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xDF\xC0"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xDF\xFF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xE0\x80"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xE0\x80\x81"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xE0\x9F\xBF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xE2"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF0"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF0\x80\x81"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF0\x80\x81\x82"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF0\x8F\xBF\xBF"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF4\x90\x81\x82"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF5"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF6\x80"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF7\x80\x81"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xF8\x90\x91\x92\x93"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xFF\xFF\xFF\xFF"}, |
| |
| // Invalid. UTF-8 cannot contain the surrogates U+D800 ..= U+DFFF. |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xED\xA0\x80"}, |
| {.want0 = 0x0100FFFD, .want1 = 0x0100FFFD, .str = "\xED\xBF\xBF"}, |
| }; |
| |
| for (size_t tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) { |
| wuffs_base__slice_u8 s = wuffs_base__make_slice_u8( |
| (void*)test_cases[tc].str, strlen(test_cases[tc].str)); |
| // Override "The <NUL> byte" with "\x00". |
| if (test_cases[tc].want0 == 0x01000000) { |
| s = wuffs_base__make_slice_u8(&the_nul_byte[0], 1); |
| } |
| |
| // Test wuffs_base__utf_8__next. |
| { |
| uint32_t want_bl = test_cases[tc].want0 >> 24; |
| uint32_t want_cp = test_cases[tc].want0 & 0xFFFFFF; |
| wuffs_base__utf_8__next__output have = |
| wuffs_base__utf_8__next(s.ptr, s.len); |
| if ((have.code_point != want_cp) || (have.byte_length != want_bl)) { |
| RETURN_FAIL("next(\"%s\"): have cp=0x%" PRIX32 " bl=%" PRIu32 |
| ", want cp=0x%" PRIX32 " bl=%" PRIu32, |
| test_cases[tc].str, have.code_point, have.byte_length, |
| want_cp, want_bl); |
| } |
| } |
| |
| // Test wuffs_base__utf_8__next_from_end. |
| { |
| uint32_t want_bl = test_cases[tc].want1 >> 24; |
| uint32_t want_cp = test_cases[tc].want1 & 0xFFFFFF; |
| wuffs_base__utf_8__next__output have = |
| wuffs_base__utf_8__next_from_end(s.ptr, s.len); |
| if ((have.code_point != want_cp) || (have.byte_length != want_bl)) { |
| RETURN_FAIL("next_from_end(\"%s\"): have cp=0x%" PRIX32 " bl=%" PRIu32 |
| ", want cp=0x%" PRIX32 " bl=%" PRIu32, |
| test_cases[tc].str, have.code_point, have.byte_length, |
| want_cp, want_bl); |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ---------------- Golden Tests |
| |
| golden_test g_json_australian_abc_gt = { |
| .want_filename = "test/data/australian-abc-local-stations.tokens", |
| .src_filename = "test/data/australian-abc-local-stations.json", |
| }; |
| |
| golden_test g_json_file_sizes_gt = { |
| .src_filename = "test/data/file-sizes.json", |
| }; |
| |
| golden_test g_json_github_tags_gt = { |
| .src_filename = "test/data/github-tags.json", |
| }; |
| |
| golden_test g_json_json_things_unformatted_gt = { |
| .want_filename = "test/data/json-things.unformatted.tokens", |
| .src_filename = "test/data/json-things.unformatted.json", |
| }; |
| |
| golden_test g_json_json_quirks_gt = { |
| .want_filename = "test/data/json-quirks.tokens", |
| .src_filename = "test/data/json-quirks.json", |
| }; |
| |
| golden_test g_json_nobel_prizes_gt = { |
| .src_filename = "test/data/nobel-prizes.json", |
| }; |
| |
| // ---------------- JSON Tests |
| |
| const char* // |
| test_wuffs_json_decode_interface() { |
| CHECK_FOCUS(__func__); |
| |
| { |
| wuffs_json__decoder dec; |
| CHECK_STATUS("initialize", |
| wuffs_json__decoder__initialize( |
| &dec, sizeof dec, WUFFS_VERSION, |
| WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED)); |
| CHECK_STRING(do_test__wuffs_base__token_decoder( |
| wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec), |
| &g_json_json_things_unformatted_gt)); |
| } |
| |
| { |
| wuffs_json__decoder dec; |
| CHECK_STATUS("initialize", |
| wuffs_json__decoder__initialize( |
| &dec, sizeof dec, WUFFS_VERSION, |
| WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED)); |
| CHECK_STRING(do_test__wuffs_base__token_decoder( |
| wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec), |
| &g_json_australian_abc_gt)); |
| } |
| |
| { |
| uint32_t quirks[] = { |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_A, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_CAPITAL_U, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_E, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_QUESTION_MARK, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_SINGLE_QUOTE, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_V, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X_AS_CODE_POINTS, |
| WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_ZERO, |
| WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK, |
| WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE, |
| WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA, |
| WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS, |
| WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR, |
| WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK, |
| WUFFS_JSON__QUIRK_ALLOW_TRAILING_FILLER, |
| WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE, |
| 0, |
| }; |
| |
| wuffs_json__decoder dec; |
| CHECK_STATUS("initialize", |
| wuffs_json__decoder__initialize( |
| &dec, sizeof dec, WUFFS_VERSION, |
| WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED)); |
| for (size_t i = 0; quirks[i]; i++) { |
| wuffs_json__decoder__set_quirk_enabled(&dec, quirks[i], true); |
| } |
| CHECK_STRING(do_test__wuffs_base__token_decoder( |
| wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec), |
| &g_json_json_quirks_gt)); |
| } |
| |
| return NULL; |
| } |
| |
| const char* // |
| wuffs_json_decode(wuffs_base__token_buffer* tok, |
| wuffs_base__io_buffer* src, |
| uint32_t wuffs_initialize_flags, |
| uint64_t wlimit, |
| uint64_t rlimit) { |
| wuffs_json__decoder dec; |
| CHECK_STATUS("initialize", |
| wuffs_json__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION, |
| wuffs_initialize_flags)); |
| |
| while (true) { |
| wuffs_base__token_buffer limited_tok = |
| make_limited_token_writer(*tok, wlimit); |
| wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit); |
| |
| wuffs_base__status status = wuffs_json__decoder__decode_tokens( |
| &dec, &limited_tok, &limited_src, g_work_slice_u8); |
| |
| tok->meta.wi += limited_tok.meta.wi; |
| src->meta.ri += limited_src.meta.ri; |
| |
| if (((wlimit < UINT64_MAX) && |
| (status.repr == wuffs_base__suspension__short_write)) || |
| ((rlimit < UINT64_MAX) && |
| (status.repr == wuffs_base__suspension__short_read))) { |
| continue; |
| } |
| return status.repr; |
| } |
| } |
| |
| const char* // |
| test_wuffs_json_decode_end_of_data() { |
| CHECK_FOCUS(__func__); |
| |
| for (int i = 0; i < 2; i++) { |
| uint8_t* src_ptr = (uint8_t*)("123null89"); |
| size_t src_len = i ? 3 : 9; |
| |
| wuffs_json__decoder dec; |
| CHECK_STATUS("initialize", |
| wuffs_json__decoder__initialize( |
| &dec, sizeof dec, WUFFS_VERSION, |
| WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED)); |
| |
| wuffs_base__token_buffer tok = |
| wuffs_base__slice_token__writer(g_have_slice_token); |
| wuffs_base__io_buffer src = |
| wuffs_base__ptr_u8__reader(src_ptr, src_len, true); |
| CHECK_STATUS("decode_tokens", wuffs_json__decoder__decode_tokens( |
| &dec, &tok, &src, g_work_slice_u8)); |
| if (src.meta.ri != 3) { |
| RETURN_FAIL("src.meta.ri: have %zu, want 3", src.meta.ri); |
| } |
| |
| const char* have = |
| wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8) |
| .repr; |
| if (have != wuffs_base__note__end_of_data) { |
|