/* * Copyright 2022-present MongoDB, Inc. * * 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 * * http://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. */ #include "test-mongocrypt.h" #include "mc-check-conversions-private.h" #include "mc-range-encoding-private.h" #include <float.h> // DBL_MAX #include <math.h> // INFINITY, NAN typedef struct { mc_getTypeInfo32_args_t args; mc_OSTType_Int32 expect; const char *expectError; } Int32Test; static void _test_RangeTest_Encode_Int32(_mongocrypt_tester_t *tester) { Int32Test tests[] = { /* Test cases copied from server Int32_NoBounds test ... begin */ {.args = {.value = INT32_C(2147483647)}, .expect = {.value = UINT32_C(4294967295), .min = 0, .max = UINT32_MAX}}, {.args = {.value = 1}, .expect = {.value = UINT32_C(2147483649), .min = 0, .max = UINT32_MAX}}, {.args = {.value = 0}, .expect = {.value = UINT32_C(2147483648), .min = 0, .max = UINT32_MAX}}, {.args = {.value = -1}, .expect = {.value = UINT32_C(2147483647), .min = 0, .max = UINT32_MAX}}, {.args = {.value = -2}, .expect = {.value = UINT32_C(2147483646), .min = 0, .max = UINT32_MAX}}, {.args = {.value = INT32_C(-2147483647)}, .expect = {.value = 1, .min = 0, .max = UINT32_MAX}}, {.args = {.value = INT32_MIN}, .expect = {.value = 0, .min = 0, .max = UINT32_MAX}}, /* Test cases copied from server Int32_NoBounds test ... end */ /* Test cases copied from server Int32_Bounds test .. begin */ {.args = {.value = 1, .min = OPT_I32(1), .max = OPT_I32(3)}, .expect = {.value = 0, 0, .max = 2}}, {.args = {.value = 0, .min = OPT_I32(0), .max = OPT_I32(1)}, .expect = {.value = 0, .min = 0, .max = 1}}, {.args = {.value = -1, .min = OPT_I32(-1), .max = OPT_I32(0)}, .expect = {.value = 0, .min = 0, .max = 1}}, {.args = {.value = -2, .min = OPT_I32(-2), .max = OPT_I32(0)}, .expect = {.value = 0, .min = 0, .max = 2}}, {.args = {.value = INT32_C(-2147483647), .min = OPT_I32(INT32_MIN), .max = OPT_I32(1)}, .expect = {.value = 1, .min = 0, .max = UINT32_C(2147483649)}}, {.args = {.value = INT32_MIN, .min = OPT_I32(INT32_MIN), .max = OPT_I32(0)}, .expect = {.value = 0, .min = 0, .max = UINT32_C(2147483648)}}, {.args = {.value = 0, .min = OPT_I32(INT32_MIN), .max = OPT_I32(1)}, .expect = {.value = UINT32_C(2147483648), .min = 0, .max = UINT32_C(2147483649)}}, {.args = {.value = 1, .min = OPT_I32(INT32_MIN), .max = OPT_I32(2)}, .expect = {.value = UINT32_C(2147483649), .min = 0, .max = UINT32_C(2147483650)}}, {.args = {.value = INT32_C(2147483647), .min = OPT_I32(-2147483647), .max = OPT_I32(2147483647)}, .expect = {.value = UINT32_C(4294967294), .min = 0, .max = UINT32_C(4294967294)}}, {.args = {.value = INT32_C(2147483647), .min = OPT_I32(INT32_MIN), .max = OPT_I32(2147483647)}, .expect = {.value = UINT32_C(4294967295), .min = 0, .max = UINT32_C(4294967295)}}, {.args = {.value = 15, .min = OPT_I32(10), .max = OPT_I32(26)}, .expect = {.value = 5, .min = 0, .max = 16}}, {.args = {.value = 15, .min = OPT_I32(-10), .max = OPT_I32(55)}, .expect = {.value = 25, .min = 0, .max = 65}}, /* Test cases copied from server Int32_Bounds test ... end */ /* Test cases copied from server Int32_Errors test ... begin */ {.args = {.value = 1, .max = OPT_I32(2)}, .expectError = "Must specify both a lower and upper bound or no bounds."}, {.args = {.value = 1, .min = OPT_I32(0)}, .expectError = "Must specify both a lower and upper bound or no bounds."}, {.args = {.value = 1, .min = OPT_I32(2), .max = OPT_I32(1)}, .expectError = "The minimum value must be less than the maximum value"}, {.args = {.value = 1, .min = OPT_I32(2), .max = OPT_I32(3)}, .expectError = "Value must be greater than or equal to the minimum " "value and less than or equal to the maximum value"}, {.args = {.value = 4, .min = OPT_I32(2), .max = OPT_I32(3)}, .expectError = "Value must be greater than or equal to the minimum " "value and less than or equal to the maximum value"}, {.args = {.value = 4, .min = OPT_I32(INT32_MIN), .max = OPT_I32(INT32_MIN)}, .expectError = "The minimum value must be less than the maximum value"}, /* Test cases copied from server Int32_Errors test ... end */ }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { Int32Test *test = tests + i; mongocrypt_status_t *const status = mongocrypt_status_new(); // Print a description of the test case. printf("_test_RangeTest_Encode_Int32: value=%" PRId32, test->args.value); if (test->args.min.set) { printf(" min=%" PRId32, test->args.min.value); } if (test->args.max.set) { printf(" max=%" PRId32, test->args.max.value); } printf("\n"); mc_OSTType_Int32 got; const bool ok = mc_getTypeInfo32(test->args, &got, status); if (test->expectError) { ASSERT_OR_PRINT_MSG(!ok, "expected error, but got none"); ASSERT_STATUS_CONTAINS(status, test->expectError); } else { ASSERT_OK_STATUS(ok, status); ASSERT_CMPUINT32(got.value, ==, test->expect.value); ASSERT_CMPUINT32(got.min, ==, test->expect.min); ASSERT_CMPUINT32(got.max, ==, test->expect.max); } mongocrypt_status_destroy(status); } } typedef struct { mc_getTypeInfo64_args_t args; mc_OSTType_Int64 expect; const char *expectError; } Int64Test; static void _test_RangeTest_Encode_Int64(_mongocrypt_tester_t *tester) { Int64Test tests[] = { /* Test cases copied from server Int64_NoBounds test ... begin */ {.args = {.value = INT64_C(9223372036854775807)}, .expect = {.value = UINT64_C(18446744073709551615), .min = 0, .max = UINT64_MAX}}, {.args = {.value = 1}, .expect = {.value = UINT64_C(9223372036854775809), .min = 0, .max = UINT64_MAX}}, {.args = {.value = 0}, .expect = {.value = UINT64_C(9223372036854775808), .min = 0, .max = UINT64_MAX}}, {.args = {.value = -1}, .expect = {.value = UINT64_C(9223372036854775807), .min = 0, .max = UINT64_MAX}}, {.args = {.value = -2}, .expect = {.value = UINT64_C(9223372036854775806), .min = 0, .max = UINT64_MAX}}, {.args = {.value = INT64_C(-9223372036854775807)}, .expect = {.value = 1, .min = 0, .max = UINT64_MAX}}, {.args = {.value = INT64_MIN}, .expect = {.value = 0, .min = 0, .max = UINT64_MAX}}, /* Test cases copied from server Int64_NoBounds test ... end */ /* Test cases copied from server Int64_Bounds test ... begin */ {.args = {.value = 1, .min = OPT_I64(1), .max = OPT_I64(2)}, .expect = {.value = 0, .min = 0, .max = 1}}, {.args = {.value = 0, .min = OPT_I64(0), .max = OPT_I64(1)}, .expect = {.value = 0, .min = 0, .max = 1}}, {.args = {.value = -1, .min = OPT_I64(-1), .max = OPT_I64(0)}, .expect = {.value = 0, .min = 0, .max = 1}}, {.args = {.value = -2, .min = OPT_I64(-2), .max = OPT_I64(0)}, .expect = {.value = 0, .min = 0, .max = 2}}, {.args = {.value = INT64_C(-9223372036854775807), .min = OPT_I64(INT64_MIN), .max = OPT_I64(1)}, .expect = {.value = 1, .min = 0, .max = UINT64_C(9223372036854775809)}}, {.args = {.value = INT64_MIN, .min = OPT_I64(INT64_MIN), .max = OPT_I64(0)}, .expect = {.value = 0, .min = 0, .max = UINT64_C(9223372036854775808)}}, {.args = {.value = 0, .min = OPT_I64(INT64_MIN), .max = OPT_I64(37)}, .expect = {.value = UINT64_C(9223372036854775808), .min = 0, .max = UINT64_C(9223372036854775845)}}, {.args = {.value = 1, .min = OPT_I64(INT64_MIN), .max = OPT_I64(42)}, .expect = {.value = UINT64_C(9223372036854775809), .min = 0, .max = UINT64_C(9223372036854775850)}}, {.args = {.value = INT64_C(9223372036854775807), .min = OPT_I64(-9223372036854775807), .max = OPT_I64(9223372036854775807)}, .expect = {.value = UINT64_C(18446744073709551614), .min = 0, .max = UINT64_C(18446744073709551614)}}, {.args = {.value = INT64_C(9223372036854775807), .min = OPT_I64(INT64_MIN), .max = OPT_I64(9223372036854775807)}, .expect = {.value = UINT64_C(18446744073709551615), .min = 0, .max = UINT64_C(18446744073709551615)}}, {.args = {.value = 15, .min = OPT_I64(10), .max = OPT_I64(26)}, .expect = {.value = 5, .min = 0, .max = 16}}, {.args = {.value = 15, .min = OPT_I64(-10), .max = OPT_I64(55)}, .expect = {.value = 25, .min = 0, .max = 65}}, /* Test cases copied from server Int64_Bounds test ... end */ /* Test cases copied from server Int64_Errors test ... begin */ {.args = {.value = 1, .max = OPT_I64(2)}, .expectError = "Must specify both a lower and upper bound or no bounds."}, {.args = {.value = 1, .min = OPT_I64(0)}, .expectError = "Must specify both a lower and upper bound or no bounds."}, {.args = {.value = 1, .min = OPT_I64(2), .max = OPT_I64(1)}, .expectError = "The minimum value must be less than the maximum value"}, {.args = {.value = 1, .min = OPT_I64(2), .max = OPT_I64(3)}, .expectError = "Value must be greater than or equal to the minimum " "value and less than or equal to the maximum value"}, {.args = {.value = 4, .min = OPT_I64(2), .max = OPT_I64(3)}, .expectError = "Value must be greater than or equal to the minimum " "value and less than or equal to the maximum value"}, {.args = {.value = 4, .min = OPT_I64(INT64_MIN), .max = OPT_I64(INT64_MIN)}, .expectError = "The minimum value must be less than the maximum value"}, /* Test cases copied from server Int64_Errors test ... end */ }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { Int64Test *test = tests + i; mongocrypt_status_t *const status = mongocrypt_status_new(); // Print a description of the test case. printf("_test_RangeTest_Encode_Int64: value=%" PRId64, test->args.value); if (test->args.min.set) { printf(" min=%" PRId64, test->args.min.value); } if (test->args.max.set) { printf(" max=%" PRId64, test->args.max.value); } printf("\n"); mc_OSTType_Int64 got; const bool ok = mc_getTypeInfo64(test->args, &got, status); if (test->expectError) { ASSERT_OR_PRINT_MSG(!ok, "expected error, but got none"); ASSERT_STATUS_CONTAINS(status, test->expectError); } else { ASSERT_OK_STATUS(ok, status); ASSERT_CMPUINT64(got.value, ==, test->expect.value); ASSERT_CMPUINT64(got.min, ==, test->expect.min); ASSERT_CMPUINT64(got.max, ==, test->expect.max); } mongocrypt_status_destroy(status); } } typedef struct { double value; mc_optional_double_t min; mc_optional_double_t max; mc_optional_uint32_t precision; uint64_t expect; mc_optional_uint64_t expectMax; const char *expectError; } DoubleTest; static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) { DoubleTest tests[] = {/* Test cases copied from server Double_Bounds test ... begin */ // Larger numbers map to larger uint64 {.value = -1111, .expect = UINT64_C(4570770991734587392)}, {.value = -111, .expect = UINT64_C(4585860689314185216)}, {.value = -11, .expect = UINT64_C(4600989969312382976)}, {.value = -10, .expect = UINT64_C(4601552919265804288)}, {.value = -3, .expect = UINT64_C(4609434218613702656)}, {.value = -2, .expect = UINT64_C(4611686018427387904)}, {.value = -1, .expect = UINT64_C(4616189618054758400)}, {.value = 1, .expect = UINT64_C(13830554455654793216)}, {.value = 22, .expect = UINT64_C(13850257704024539136)}, {.value = 333, .expect = UINT64_C(13867937850999177216)}, // Larger exponents map to larger uint64 {.value = 33E56, .expect = UINT64_C(14690973652625833878)}, {.value = 22E57, .expect = UINT64_C(14703137697061005818)}, {.value = 11E58, .expect = UINT64_C(14713688953586463292)}, // Smaller exponents map to smaller uint64 {.value = 1E-6, .expect = UINT64_C(13740701229962882445)}, {.value = 1E-7, .expect = UINT64_C(13725520251343122248)}, {.value = 1E-8, .expect = UINT64_C(13710498295186492474)}, {.value = 1E-56, .expect = UINT64_C(12992711961033031890)}, {.value = 1E-57, .expect = UINT64_C(12977434315086142017)}, {.value = 1E-58, .expect = UINT64_C(12962510038552207822)}, // Smaller negative exponents map to smaller uint64 {.value = -1E-06, .expect = UINT64_C(4706042843746669171)}, {.value = -1E-07, .expect = UINT64_C(4721223822366429368)}, {.value = -1E-08, .expect = UINT64_C(4736245778523059142)}, {.value = -1E-56, .expect = UINT64_C(5454032112676519726)}, {.value = -1E-57, .expect = UINT64_C(5469309758623409599)}, {.value = -1E-58, .expect = UINT64_C(5484234035157343794)}, // Larger exponents map to larger uint64 {.value = -33E+56, .expect = UINT64_C(3755770421083717738)}, {.value = -22E+57, .expect = UINT64_C(3743606376648545798)}, {.value = -11E+58, .expect = UINT64_C(3733055120123088324)}, {.value = 0, .expect = UINT64_C(9223372036854775808)}, {.value = -0.0, .expect = UINT64_C(9223372036854775808)}, /* Test cases copied from server Double_Bounds test ... end */ /* Test cases copied from server Double_Errors test ... begin */ {.value = INFINITY, .expectError = "Infinity and NaN double values are not supported."}, {.value = NAN, .expectError = "Infinity and NaN double values are not supported."}, /* Test cases copied from server Double_Errors test ... end */ /* Test cases copied from Double_Bounds_Precision ... begin */ {.value = 3.141592653589, .precision = OPT_U32_C(1), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = UINT64_C(1000031), .expectMax = OPT_U64_C(2097151)}, {.value = 3.141592653589, .precision = OPT_U32_C(2), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 10000314, .expectMax = OPT_U64_C(33554431)}, {.value = 3.141592653589, .precision = OPT_U32_C(3), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 100003141, .expectMax = OPT_U64_C(268435455)}, {.value = 3.141592653589, .precision = OPT_U32_C(4), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 1000031415, .expectMax = OPT_U64_C(2147483647)}, {.value = 3.141592653589, .precision = OPT_U32_C(5), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 10000314159, .expectMax = OPT_U64_C(34359738367)}, {.value = 3.141592653589, .precision = OPT_U32_C(6), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 100003141592, .expectMax = OPT_U64_C(274877906943)}, {.value = 3.141592653589, .precision = OPT_U32_C(7), .min = OPT_DOUBLE_C(-100000), .max = OPT_DOUBLE_C(100000), .expect = 1000031415926, .expectMax = OPT_U64_C(2199023255551)}, {.value = 0, .max = OPT_DOUBLE_C(1), .min = OPT_DOUBLE_C(-1), .precision = OPT_U32_C(3), .expect = 1000, .expectMax = OPT_U64_C(4095)}, {.value = 0, .max = OPT_DOUBLE_C(1), .min = OPT_DOUBLE_C(-1E5), .precision = OPT_U32_C(3), .expect = 100000000, .expectMax = OPT_U64_C(134217727)}, {.value = -1E-33, .max = OPT_DOUBLE_C(1), .min = OPT_DOUBLE_C(-1E5), .precision = OPT_U32_C(3), .expect = 100000000, .expectMax = OPT_U64_C(134217727)}, {.value = 0, .max = OPT_DOUBLE_C(DBL_MAX), .min = OPT_DOUBLE_C(-DBL_MAX), .precision = OPT_U32_C(3), .expect = UINT64_C(9223372036854775808), // Expect precision not to be used. .expectMax = OPT_U64_C(UINT64_MAX)}, {.value = 3.141592653589, .max = OPT_DOUBLE_C(5), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(0), .expect = 3, .expectMax = OPT_U64_C(7)}, {.value = 3.141592653589, .max = OPT_DOUBLE_C(5), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(1), .expect = 31, .expectMax = OPT_U64_C(63)}, {.value = 3.141592653589, .max = OPT_DOUBLE_C(5), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(2), .expect = 314, .expectMax = OPT_U64_C(1023)}, {.value = 3.141592653589, .max = OPT_DOUBLE_C(5), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(3), .expect = 3141, .expectMax = OPT_U64_C(8191)}, {.value = 3.141592653589, .max = OPT_DOUBLE_C(5), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(16), .expect = 31415926535890000, .expectMax = OPT_U64_C(72057594037927935)}, {.value = -5, .max = OPT_DOUBLE_C(-1), .min = OPT_DOUBLE_C(-10), .precision = OPT_U32_C(3), .expect = 5000, .expectMax = OPT_U64_C(16383)}, {.value = 1E100, .max = OPT_DOUBLE_C(DBL_MAX), .min = OPT_DOUBLE_C(-DBL_MAX), .precision = OPT_U32_C(3), .expect = 15326393489903895421ULL, // Expect precision not to be used. .expectMax = OPT_U64_C(UINT64_MAX)}, {.value = 1E9, .max = OPT_DOUBLE_C(1E10), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(3), .expect = 1000000000000, .expectMax = OPT_U64_C(17592186044415)}, {.value = 1E9, .max = OPT_DOUBLE_C(1E10), .min = OPT_DOUBLE_C(0), .precision = OPT_U32_C(0), .expect = 1000000000, .expectMax = OPT_U64_C(17179869183)}, {.value = -5, .max = OPT_DOUBLE_C(10), .min = OPT_DOUBLE_C(-10), .precision = OPT_U32_C(0), .expect = 5, .expectMax = OPT_U64_C(31)}, {.value = -5, .max = OPT_DOUBLE_C(10), .min = OPT_DOUBLE_C(-10), .precision = OPT_U32_C(2), .expect = 500, .expectMax = OPT_U64_C(4095)}, {.value = 1E-30, .max = OPT_DOUBLE_C(10E-30), .min = OPT_DOUBLE_C(1E-30), .precision = OPT_U32_C(35), .expect = 13381399884061196960ULL, // Expect precision not to be used. .expectMax = OPT_U64_C(UINT64_MAX)}, /* Test cases copied from Double_Bounds_Precision ... end */ {.value = -1, .min = OPT_DOUBLE_C(0), .max = OPT_DOUBLE_C(200), .precision = OPT_U32_C(1), .expectError = "greater than or equal to the minimum value"}, {.value = -1, .min = OPT_DOUBLE_C(0), .max = OPT_DOUBLE_C(201), .precision = OPT_U32_C(1), .expectError = "less than or equal to the maximum value"}}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { DoubleTest *test = tests + i; mongocrypt_status_t *const status = mongocrypt_status_new(); if (test->min.set && test->max.set && test->precision.set) { printf("_test_RangeTest_Encode_Double: value=%f, min=%f, max=%f, " "precision=%" PRIu32 "\n", test->value, test->min.value, test->max.value, test->precision.value); } else { printf("_test_RangeTest_Encode_Double: value=%f\n", test->value); } mc_OSTType_Double got; const bool ok = mc_getTypeInfoDouble((mc_getTypeInfoDouble_args_t){.value = test->value, .min = test->min, .max = test->max, .precision = test->precision}, &got, status); if (test->expectError) { ASSERT_OR_PRINT_MSG(!ok, "expected error, but got none"); ASSERT_STATUS_CONTAINS(status, test->expectError); } else { ASSERT_OK_STATUS(ok, status); ASSERT_CMPUINT64(got.value, ==, test->expect); ASSERT_CMPUINT64(got.min, ==, 0); ASSERT_CMPUINT64(got.max, ==, test->expectMax.set ? test->expectMax.value : UINT64_MAX); } mongocrypt_status_destroy(status); } } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT typedef struct { mc_dec128 value; mc_optional_dec128_t min; mc_optional_dec128_t max; mc_optional_uint32_t precision; mlib_int128 expect; const char *expectError; } Decimal128Test; static void _test_RangeTest_Encode_Decimal128(_mongocrypt_tester_t *tester) { Decimal128Test tests[] = { #define CASE(Value, ExpectStr) \ (Decimal128Test){.value = mc_dec128_from_string(#Value), .expect = mlib_int128_from_string(ExpectStr, NULL)} /* Test cases copied from server Decimal128_Bounds test ... begin */ // Larger numbers map to larger int128 CASE(-1234567890E7, "108549948892579231731687303715884111887"), CASE(-1234567890E6, "108559948892579231731687303715884111886"), CASE(-1234567890E5, "108569948892579231731687303715884111885"), CASE(-1234567890E4, "108579948892579231731687303715884111884"), CASE(-1234567890E3, "108589948892579231731687303715884111883"), CASE(-1234567890E2, "108599948892579231731687303715884111882"), CASE(-1234567890E1, "108609948892579231731687303715884111881"), CASE(-123456789012345, "108569948892579108281687303715884111885"), CASE(-12345678901234, "108579948892579108331687303715884111884"), CASE(-1234567890123, "108589948892579108731687303715884111883"), CASE(-123456789012, "108599948892579111731687303715884111882"), CASE(-12345678901, "108609948892579131731687303715884111881"), CASE(-1234567890, "108619948892579231731687303715884111880"), CASE(-99999999, "108631183460569231731687303715884111878"), CASE(-8888888, "108642294572469231731687303715884111877"), CASE(-777777, "108653405690469231731687303715884111876"), CASE(-66666, "108664516860469231731687303715884111875"), CASE(-5555, "108675628460469231731687303715884111874"), CASE(-444, "108686743460469231731687303715884111873"), CASE(-334, "108687843460469231731687303715884111873"), CASE(-333, "108687853460469231731687303715884111873"), CASE(-44, "108696783460469231731687303715884111872"), CASE(-33, "108697883460469231731687303715884111872"), CASE(-22, "108698983460469231731687303715884111872"), CASE(-5, "108706183460469231731687303715884111871"), CASE(-4, "108707183460469231731687303715884111871"), CASE(-3, "108708183460469231731687303715884111871"), CASE(-2, "108709183460469231731687303715884111871"), CASE(-1, "108710183460469231731687303715884111871"), CASE(0, "170141183460469231731687303715884105728"), CASE(1, "231572183460469231731687303715884099585"), CASE(2, "231573183460469231731687303715884099585"), CASE(3, "231574183460469231731687303715884099585"), CASE(4, "231575183460469231731687303715884099585"), CASE(5, "231576183460469231731687303715884099585"), CASE(22, "231583383460469231731687303715884099584"), CASE(33, "231584483460469231731687303715884099584"), CASE(44, "231585583460469231731687303715884099584"), CASE(333, "231594513460469231731687303715884099583"), CASE(334, "231594523460469231731687303715884099583"), CASE(444, "231595623460469231731687303715884099583"), CASE(5555, "231606738460469231731687303715884099582"), CASE(66666, "231617850060469231731687303715884099581"), CASE(777777, "231628961230469231731687303715884099580"), CASE(8888888, "231640072348469231731687303715884099579"), CASE(33E56, "232144483460469231731687303715884099528"), CASE(22E57, "232153383460469231731687303715884099527"), CASE(11E58, "232162283460469231731687303715884099526"), // Smaller exponents map to smaller int128 CASE(1E-6, "231512183460469231731687303715884099591"), CASE(1E-7, "231502183460469231731687303715884099592"), CASE(1E-8, "231492183460469231731687303715884099593"), CASE(1E-56, "231012183460469231731687303715884099641"), CASE(1E-57, "231002183460469231731687303715884099642"), CASE(1E-58, "230992183460469231731687303715884099643"), // Smaller negative exponents map to smaller int128 CASE(-1E-6, "108770183460469231731687303715884111865"), CASE(-1E-7, "108780183460469231731687303715884111864"), CASE(-1E-8, "108790183460469231731687303715884111863"), CASE(-1E-56, "109270183460469231731687303715884111815"), CASE(-1E-57, "109280183460469231731687303715884111814"), CASE(-1E-58, "109290183460469231731687303715884111813"), // Larger exponents map to larger int128 CASE(-33E56, "108137883460469231731687303715884111928"), CASE(-22E57, "108128983460469231731687303715884111929"), CASE(-11E58, "108120083460469231731687303715884111930"), (Decimal128Test){.value = MC_DEC128_LARGEST_POSITIVE, .expect = mlib_int128_from_string("293021183460469231731687303715884093440", NULL)}, (Decimal128Test){.value = MC_DEC128_SMALLEST_POSITIVE, .expect = mlib_int128_from_string("170141183460469231731687303715884105729", NULL)}, (Decimal128Test){.value = MC_DEC128_LARGEST_NEGATIVE, .expect = mlib_int128_from_string("47261183460469231731687303715884118016", NULL)}, (Decimal128Test){.value = MC_DEC128_SMALLEST_NEGATIVE, .expect = mlib_int128_from_string("170141183460469231731687303715884105727", NULL)}, (Decimal128Test){.value = MC_DEC128_NORMALIZED_ZERO, .expect = mlib_int128_from_string("170141183460469231731687303715884105728", NULL)}, (Decimal128Test){.value = MC_DEC128_NEGATIVE_EXPONENT_ZERO, .expect = mlib_int128_from_string("170141183460469231731687303715884105728", NULL)}, /* Test cases copied from server Decimal128_Bounds test ... end */ #define ERROR_CASE(Value, Min, Max, Precision, ErrorString) \ (Decimal128Test){ \ .value = Value, \ .min = Min, \ .max = Max, \ .precision = Precision, \ .expectError = ErrorString, \ } ERROR_CASE(MC_DEC128_C(1), OPT_NULLOPT, OPT_MC_DEC128(MC_DEC128_C(2)), OPT_U32(5), "min, max, and precision must all be set or must all be unset"), ERROR_CASE(MC_DEC128_C(1), OPT_MC_DEC128(MC_DEC128_C(0)), OPT_NULLOPT, OPT_U32(5), "min, max, and precision must all be set or must all be unset"), ERROR_CASE(MC_DEC128_C(1), OPT_MC_DEC128(MC_DEC128_C(2)), OPT_MC_DEC128(MC_DEC128_C(1)), OPT_U32(5), "The minimum value must be less than the maximum value"), ERROR_CASE(MC_DEC128_C(1), OPT_MC_DEC128(MC_DEC128_C(2)), OPT_MC_DEC128(MC_DEC128_C(3)), OPT_U32(5), "Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value"), ERROR_CASE(MC_DEC128_C(4), OPT_MC_DEC128(MC_DEC128_C(2)), OPT_MC_DEC128(MC_DEC128_C(3)), OPT_U32(5), "Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value"), ERROR_CASE(MC_DEC128_POSITIVE_INFINITY, OPT_NULLOPT, OPT_NULLOPT, OPT_NULLOPT, "Infinity and Nan Decimal128 values are not supported."), ERROR_CASE(MC_DEC128_NEGATIVE_INFINITY, OPT_NULLOPT, OPT_NULLOPT, OPT_NULLOPT, "Infinity and Nan Decimal128 values are not supported."), ERROR_CASE(MC_DEC128_POSITIVE_NAN, OPT_NULLOPT, OPT_NULLOPT, OPT_NULLOPT, "Infinity and Nan Decimal128 values are not supported."), ERROR_CASE(MC_DEC128_NEGATIVE_NAN, OPT_NULLOPT, OPT_NULLOPT, OPT_NULLOPT, "Infinity and Nan Decimal128 values are not supported."), /* Test cases copied from Decimal128_Bounds_Precision ... begin */ #define ASSERT_EIBP(Value, Precision, Expect) \ (Decimal128Test){ \ .value = mc_dec128_from_string(Value), \ .min = OPT_MC_DEC128(MC_DEC128_C(-100000)), \ .max = OPT_MC_DEC128(MC_DEC128_C(100000)), \ .precision = OPT_U32(Precision), \ .expect = MLIB_INT128(Expect), \ } ASSERT_EIBP("3.141592653589E-1", 10, 1000003141592653), ASSERT_EIBP("31.41592653589E-2", 10, 1000003141592653), ASSERT_EIBP("314.1592653589E-3", 10, 1000003141592653), ASSERT_EIBP("3141.592653589E-4", 10, 1000003141592653), ASSERT_EIBP("31415.92653589E-5", 10, 1000003141592653), ASSERT_EIBP("314159.2653589E-6", 10, 1000003141592653), ASSERT_EIBP("3141592.653589E-7", 10, 1000003141592653), ASSERT_EIBP("31415926.53589E-8", 10, 1000003141592653), #undef ASSERT_EIBP #define ASSERT_EIBPL(Value, Precision, Expect) \ (Decimal128Test){ \ .value = mc_dec128_from_string(Value), \ .min = OPT_MC_DEC128(MC_DEC128_C(-100000)), \ .max = OPT_MC_DEC128(mc_dec128_from_string("1E22")), \ .precision = OPT_U32(Precision), \ .expect = mlib_int128_from_string(Expect, NULL), \ } ASSERT_EIBPL("3.1415926535897932384626433832795E20", 5, "31415926535897942384626433"), ASSERT_EIBPL("3.1415926535897932384626433832795E20", 6, "314159265358979423846264338"), ASSERT_EIBPL("3.1415926535897932384626433832795E20", 7, "3141592653589794238462643383"), ASSERT_EIBPL("3.1415926535897932384626433832795E20", 8, "31415926535897942384626433832"), #undef ASSERT_EIBPL #define ASSERT_EIBP(Value, Precision, Expect) \ (Decimal128Test){ \ .value = mc_dec128_from_string(#Value), \ .min = OPT_MC_DEC128(MC_DEC128_C(-100000)), \ .max = OPT_MC_DEC128(MC_DEC128_C(100000)), \ .precision = OPT_U32(Precision), \ .expect = MLIB_INT128_CAST(Expect), \ } ASSERT_EIBP(3.141592653589, 1, 1000031), ASSERT_EIBP(3.141592653589, 2, 10000314), ASSERT_EIBP(3.141592653589, 3, 100003141), ASSERT_EIBP(3.141592653589, 4, 1000031415), ASSERT_EIBP(3.141592653589, 5, 10000314159), ASSERT_EIBP(3.141592653589, 6, 100003141592), ASSERT_EIBP(3.141592653589, 7, 1000031415926), #undef ASSERT_EIBP #define ASSERT_EIBB(Val, Max, Min, Precision, Expect) \ (Decimal128Test){ \ .value = mc_dec128_from_string(#Val), \ .min = OPT_MC_DEC128(mc_dec128_from_string(#Min)), \ .max = OPT_MC_DEC128(mc_dec128_from_string(#Max)), \ .precision = OPT_U32(Precision), \ .expect = MLIB_INT128_CAST(Expect), \ } #define ASSERT_EIBB_OVERFLOW(Val, Max, Min, Precision, Expect) \ (Decimal128Test) { \ .value = mc_dec128_from_string(#Val), .min = OPT_MC_DEC128(mc_dec128_from_string(#Min)), \ .max = OPT_MC_DEC128(mc_dec128_from_string(#Max)), .precision = OPT_U32(Precision), .expect = Expect, \ } ASSERT_EIBB(0, 1, -1, 3, 1000), ASSERT_EIBB(0, 1, -1E5, 3, 100000000), ASSERT_EIBB(-1E-33, 1, -1E5, 3, 100000000), ASSERT_EIBB_OVERFLOW(0, MC_DEC128_LARGEST_POSITIVE, MC_DEC128_LARGEST_NEGATIVE, 3, mlib_int128_from_string("170141183460469231731687303715884105728", NULL)), ASSERT_EIBB_OVERFLOW(0, DBL_MAX, DBL_MIN, 3, mlib_int128_from_string("170141183460469231731687303715884105728", NULL)), ASSERT_EIBB(3.141592653589, 5, 0, 0, 3), ASSERT_EIBB(3.141592653589, 5, 0, 1, 31), ASSERT_EIBB(3.141592653589, 5, 0, 2, 314), ASSERT_EIBB(3.141592653589, 5, 0, 3, 3141), ASSERT_EIBB(3.141592653589, 5, 0, 16, 31415926535890000), ASSERT_EIBB(-5, -1, -10, 3, 5000), ASSERT_EIBB_OVERFLOW(1E100, DBL_MAX, DBL_MIN, 3, mlib_int128_from_string("232572183460469231731687303715884099485", NULL)), ASSERT_EIBB(1E9, 1E10, 0, 3, 1000000000000), ASSERT_EIBB(1E9, 1E10, 0, 0, 1000000000), ASSERT_EIBB(-5, 10, -10, 0, 5), ASSERT_EIBB(-5, 10, -10, 2, 500), ASSERT_EIBB(5E-30, 10E-30, 1E-30, 35, 400000), // Test a range that requires > 64 bits. ASSERT_EIBB(5, 18446744073709551616, .1, 1, 49), // Test a range that requires > 64 bits. // min has more places after the decimal than precision. ASSERT_EIBB(5, 18446744073709551616, .01, 1, 49), #undef ASSERT_EIBB #undef ASSERT_EIBB_OVERFLOW /* Test cases copied from Decimal128_Bounds_Precision ... end */ }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { Decimal128Test *test = tests + i; mongocrypt_status_t *const status = mongocrypt_status_new(); if (test->min.set && test->max.set && test->precision.set) { printf("_test_RangeTest_Encode_Decimal128: value=%s, min=%s, max=%s, " "precision=%" PRIu32 "\n", mc_dec128_to_string(test->value).str, mc_dec128_to_string(test->min.value).str, mc_dec128_to_string(test->max.value).str, test->precision.value); } else { printf("_test_RangeTest_Encode_Decimal128: value=%s\n", mc_dec128_to_string(test->value).str); } fflush(stdout); mc_OSTType_Decimal128 got; const bool ok = mc_getTypeInfoDecimal128((mc_getTypeInfoDecimal128_args_t){.value = test->value, .min = test->min, .max = test->max, .precision = test->precision}, &got, status); if (test->expectError) { ASSERT_OR_PRINT_MSG(!ok, "expected error, but got none"); ASSERT_STATUS_CONTAINS(status, test->expectError); } else { ASSERT_OK_STATUS(ok, status); ASSERT_CMPINT128_EQ(got.value, test->expect); ASSERT_CMPINT128_EQ(got.min, MLIB_INT128(0)); } mongocrypt_status_destroy(status); } } #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT void _mongocrypt_tester_install_range_encoding(_mongocrypt_tester_t *tester) { INSTALL_TEST(_test_RangeTest_Encode_Int32); INSTALL_TEST(_test_RangeTest_Encode_Int64); INSTALL_TEST(_test_RangeTest_Encode_Double); #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT INSTALL_TEST(_test_RangeTest_Encode_Decimal128); #endif }