From 8156c30af3c6ee051855513c8781c6f4fe6a0edf Mon Sep 17 00:00:00 2001 From: Daniel Grounin Date: Fri, 4 Oct 2024 23:05:07 +0300 Subject: [PATCH] feat: add bigInt function to Number module --- include/faker-cxx/number.h | 568 ++++++++++++++++++---------------- src/modules/number.cpp | 259 +++++++++------- tests/modules/number_test.cpp | 543 +++++++++++++++++--------------- 3 files changed, 721 insertions(+), 649 deletions(-) diff --git a/include/faker-cxx/number.h b/include/faker-cxx/number.h index a989b852..076c1365 100644 --- a/include/faker-cxx/number.h +++ b/include/faker-cxx/number.h @@ -1,275 +1,293 @@ -#pragma once - -#include -#include -#include -#include - -#include "faker-cxx/export.h" -#include "faker-cxx/types/hex.h" - -namespace faker::number -{ - -/** - * @brief Generates a random integer number in the given range, bounds included. - * - * @param min The minimum value of the range. - * @param max The maximum value of the range. - * - * @tparam I the type of the generated number, must be an integral type (int, long, long long, etc.). - * - * @throws std::invalid_argument if min is greater than max. - * - * @return T a random integer number - * - * @code - * faker::number::integer(5, 10) // 7 - * @endcode - */ -template -I integer(I min, I max) -{ - if (min > max) - { - throw std::invalid_argument("Minimum value must be smaller than maximum value."); - } - - static std::mt19937 pseudoRandomGenerator{std::random_device{}()}; - - std::uniform_int_distribution distribution(min, max); - - return distribution(pseudoRandomGenerator); -} - -/** - * @brief Generates a random integer between 0 and the given maximum value, bounds included. - * - * @tparam I the type of the generated number, must be an integral type (int, long, long long, etc.). - * @param max the maximum value of the range. - * - * @throws std::invalid_argument if min is greater than max. - * - * @see integer(I) - * - * @return T a random integer number - * - * @code - * faker::number::integer(10) // 5 - * @endcode - */ -template -I integer(I max) -{ - return integer(static_cast(0), max); -} - -/** - * @brief Generates a random decimal number in the given range, bounds included. - * - * @tparam F the type of the generated number, must be a floating point type (float, double, long double). - * - * @param min The minimum value of the range. - * @param max The maximum value of the range. - * - * @throws std::invalid_argument if min is greater than max. - * - * @return F a random decimal number. - * - * @code - * faker::number::decimal(10.2, 17.7) // 15.6 - * @encode - */ -template -F decimal(F min, F max) -{ - if (min > max) - { - throw std::invalid_argument("Minimum value must be smaller than maximum value."); - } - - static std::mt19937 pseudoRandomGenerator{std::random_device{}()}; - std::uniform_real_distribution distribution(min, max); - - return distribution(pseudoRandomGenerator); -} - -/** - * @brief Generates a random decimal number between 0 and the given maximum value, bounds included. - * - * @tparam F The type of the generated number, must be a floating point type (float, double, long double). - * @param max The maximum value of the range. - * - * @throws std::invalid_argument if max is less than 0. - * - * @see decimal(F) - * - * @return F, a random decimal number. - * - * @code - * faker::number::decimal(20.5) // 17.2 - * @encode - */ -template -F decimal(F max) -{ - return decimal(static_cast(0.), max); -} - -/** - * @brief Generates a number following a normal distribution given a mean and standard deviation. - * - * @tparam F the type of the generated number, must be a floating point type (float, double, long double). - * - * @param mean The mean value of the normal distribution - * @param standard_deviation the standard deviation of the normal distribution - * - * @throws std::invalid_argument if standard deviation is negative or infinity, or if mean is infinity - * - * @return F, a random floating point number following the specified normal distribution - * - * @code - * faker::number::normalDistribution(10, 3) // 12.374 - * @encode - */ - -template -F normalDistribution(F mean, F standardDeviation) -{ - if (standardDeviation < 0 || standardDeviation == INFINITY || mean == INFINITY) - { - throw std::invalid_argument("Standard Deviation cannot be negative"); - } - else if (standardDeviation == 0) - { - return mean; - } - - std::random_device randDev; - std::mt19937 PSRNG(randDev()); - - std::normal_distribution dist(mean, standardDeviation); - return dist(PSRNG); -} - -/** - * @brief Generates a number following a normal distribution within the specified range - * - * @tparam F the type of the generated number, must be a floating point type (float, double, long double). - * - * @param mean The mean value of the normal distribution - * @param standard_deviation The standard deviation of the normal distribution - * @param min The lowest possible output - * @param max The highest possible output - * - * @return F, a random floating point number following the specified normal distribution within the specified range - * - * @throws std::invalid_argument if min is greater than max - * - * @see normalDistribution(F, F) - * - * @code - * faker::number::normalDistribution(10, 3, 9, 11) // 9 - * @encode - */ - -template -F normalDistribution(F mean, F standardDeviation, F min, F max) -{ - if (min > max) - { - throw std::invalid_argument("min cannot be larger than max"); - } - - F sample = normalDistribution(mean, standardDeviation); - - if (sample > max) - { - sample = max; - } - else if (sample < min) - { - sample = min; - } - - return sample; -} - -/** - * @brief Generates a hexadecimal string. - * - * @param length The number of digits to generate. Defaults to `1`. - * @param casing Casing of the generated string. Defaults to `HexCasing::Lower`. - * @param prefix Prefix for the generated string. Defaults to `0x`. - * - * @returns Hexadecimal string. - * - * @code - * faker::string::hexadecimal() // "0xb" - * faker::string::hexadecimal(10) // "0xae13d044cb" - * faker::string::hexadecimal(6, HexCasing::Upper, HexPrefix::Hash) // "#E3F380" - * faker::string::hexadecimal(6, HexCasing::Lower, HexPrefix::None) // "e3f380" - * @endcode - */ -FAKER_CXX_EXPORT std::string hexadecimal(unsigned length = 1, HexCasing casing = HexCasing::Lower, - HexPrefix prefix = HexPrefix::ZeroX); - -/** - * @brief Returns a lowercase hexadecimal number. - * - * @param min Optional parameter for lower bound of generated number. - * @param max Optional parameter for upper bound of generated number. - * - * @return A lowercase hexadecimal number. - * - * @code - * faker::string::hexadecimal() // "b" - * faker::string::hexadecimal(0, 255) // "9d" - * @endcode - */ -FAKER_CXX_EXPORT std::string hexadecimal(std::optional min = std::nullopt, std::optional max = std::nullopt); - -/** - * @brief Generates an octal string. - * - * @param length The number of digits to generate. Defaults to `1`. - * - * @returns Octal string. - * - * @code - * faker::string::octal(8) // "0o52561721" - * @endcode - */ -FAKER_CXX_EXPORT std::string octal(unsigned length = 1); - -/** - * @brief Generates a binary string of a specified length - * - * @param length The number of digits to generate. Defaults to `1`. - * - * @returns Binary string. - * - * @throws std::invalid_argument, if length is negative - * - * @code - * faker::string::binary(8) // "0b01110101" - * @endcode - */ -FAKER_CXX_EXPORT std::string binary(int length = 1); - -/** - * @brief Generates a random binary string which has its decimal equivalent between min and max inclusive - * - * @param min the minimum possible decimal equivalent of the output - * @param max the maximum possible decimal equivalent of the output - * - * @returns Binary string. - * - * @throws std::invalid_argument, if min > max, std::invalid_argument if min or max are negative - * - * @code - * faker::string::binary(0, 1024) // "0b10110" - * @endcode - */ -FAKER_CXX_EXPORT std::string binary(int min, int max); -} +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "faker-cxx/export.h" +#include "faker-cxx/types/hex.h" + +namespace faker::number +{ + +/** + * @brief Generates a random integer number in the given range, bounds included. + * + * @param min The minimum value of the range. + * @param max The maximum value of the range. + * + * @tparam I the type of the generated number, must be an integral type (int, long, long long, etc.). + * + * @throws std::invalid_argument if min is greater than max. + * + * @return T a random integer number + * + * @code + * faker::number::integer(5, 10) // 7 + * @endcode + */ +template +I integer(I min, I max) +{ + if (min > max) + { + throw std::invalid_argument("Minimum value must be smaller than maximum value."); + } + + static std::mt19937 pseudoRandomGenerator{std::random_device{}()}; + + std::uniform_int_distribution distribution(min, max); + + return distribution(pseudoRandomGenerator); +} + +/** + * @brief Generates a random integer between 0 and the given maximum value, bounds included. + * + * @tparam I the type of the generated number, must be an integral type (int, long, long long, etc.). + * @param max the maximum value of the range. + * + * @throws std::invalid_argument if min is greater than max. + * + * @see integer(I) + * + * @return T a random integer number + * + * @code + * faker::number::integer(10) // 5 + * @endcode + */ +template +I integer(I max) +{ + return integer(static_cast(0), max); +} + +/** + * @brief Generates a random decimal number in the given range, bounds included. + * + * @tparam F the type of the generated number, must be a floating point type (float, double, long double). + * + * @param min The minimum value of the range. + * @param max The maximum value of the range. + * + * @throws std::invalid_argument if min is greater than max. + * + * @return F a random decimal number. + * + * @code + * faker::number::decimal(10.2, 17.7) // 15.6 + * @encode + */ +template +F decimal(F min, F max) +{ + if (min > max) + { + throw std::invalid_argument("Minimum value must be smaller than maximum value."); + } + + static std::mt19937 pseudoRandomGenerator{std::random_device{}()}; + std::uniform_real_distribution distribution(min, max); + + return distribution(pseudoRandomGenerator); +} + +/** + * @brief Generates a random decimal number between 0 and the given maximum value, bounds included. + * + * @tparam F The type of the generated number, must be a floating point type (float, double, long double). + * @param max The maximum value of the range. + * + * @throws std::invalid_argument if max is less than 0. + * + * @see decimal(F) + * + * @return F, a random decimal number. + * + * @code + * faker::number::decimal(20.5) // 17.2 + * @encode + */ +template +F decimal(F max) +{ + return decimal(static_cast(0.), max); +} + +/** + * @brief Generates a number following a normal distribution given a mean and standard deviation. + * + * @tparam F the type of the generated number, must be a floating point type (float, double, long double). + * + * @param mean The mean value of the normal distribution + * @param standard_deviation the standard deviation of the normal distribution + * + * @throws std::invalid_argument if standard deviation is negative or infinity, or if mean is infinity + * + * @return F, a random floating point number following the specified normal distribution + * + * @code + * faker::number::normalDistribution(10, 3) // 12.374 + * @encode + */ + +template +F normalDistribution(F mean, F standardDeviation) +{ + if (standardDeviation < 0 || standardDeviation == INFINITY || mean == INFINITY) + { + throw std::invalid_argument("Standard Deviation cannot be negative"); + } + else if (standardDeviation == 0) + { + return mean; + } + + std::random_device randDev; + std::mt19937 PSRNG(randDev()); + + std::normal_distribution dist(mean, standardDeviation); + return dist(PSRNG); +} + +/** + * @brief Generates a number following a normal distribution within the specified range + * + * @tparam F the type of the generated number, must be a floating point type (float, double, long double). + * + * @param mean The mean value of the normal distribution + * @param standard_deviation The standard deviation of the normal distribution + * @param min The lowest possible output + * @param max The highest possible output + * + * @return F, a random floating point number following the specified normal distribution within the specified range + * + * @throws std::invalid_argument if min is greater than max + * + * @see normalDistribution(F, F) + * + * @code + * faker::number::normalDistribution(10, 3, 9, 11) // 9 + * @encode + */ + +template +F normalDistribution(F mean, F standardDeviation, F min, F max) +{ + if (min > max) + { + throw std::invalid_argument("min cannot be larger than max"); + } + + F sample = normalDistribution(mean, standardDeviation); + + if (sample > max) + { + sample = max; + } + else if (sample < min) + { + sample = min; + } + + return sample; +} + +/** + * @brief Generates a hexadecimal string. + * + * @param length The number of digits to generate. Defaults to `1`. + * @param casing Casing of the generated string. Defaults to `HexCasing::Lower`. + * @param prefix Prefix for the generated string. Defaults to `0x`. + * + * @returns Hexadecimal string. + * + * @code + * faker::string::hexadecimal() // "0xb" + * faker::string::hexadecimal(10) // "0xae13d044cb" + * faker::string::hexadecimal(6, HexCasing::Upper, HexPrefix::Hash) // "#E3F380" + * faker::string::hexadecimal(6, HexCasing::Lower, HexPrefix::None) // "e3f380" + * @endcode + */ +FAKER_CXX_EXPORT std::string hexadecimal(unsigned length = 1, HexCasing casing = HexCasing::Lower, + HexPrefix prefix = HexPrefix::ZeroX); + +/** + * @brief Returns a lowercase hexadecimal number. + * + * @param min Optional parameter for lower bound of generated number. + * @param max Optional parameter for upper bound of generated number. + * + * @return A lowercase hexadecimal number. + * + * @code + * faker::string::hexadecimal() // "b" + * faker::string::hexadecimal(0, 255) // "9d" + * @endcode + */ +FAKER_CXX_EXPORT std::string hexadecimal(std::optional min = std::nullopt, std::optional max = std::nullopt); + +/** + * @brief Generates an octal string. + * + * @param length The number of digits to generate. Defaults to `1`. + * + * @returns Octal string. + * + * @code + * faker::string::octal(8) // "0o52561721" + * @endcode + */ +FAKER_CXX_EXPORT std::string octal(unsigned length = 1); + +/** + * @brief Generates a binary string of a specified length + * + * @param length The number of digits to generate. Defaults to `1`. + * + * @returns Binary string. + * + * @throws std::invalid_argument, if length is negative + * + * @code + * faker::string::binary(8) // "0b01110101" + * @endcode + */ +FAKER_CXX_EXPORT std::string binary(int length = 1); + +/** + * @brief Generates a random binary string which has its decimal equivalent between min and max inclusive + * + * @param min the minimum possible decimal equivalent of the output + * @param max the maximum possible decimal equivalent of the output + * + * @returns Binary string. + * + * @throws std::invalid_argument, if min > max, std::invalid_argument if min or max are negative + * + * @code + * faker::string::binary(0, 1024) // "0b10110" + * @endcode + */ +FAKER_CXX_EXPORT std::string binary(int min, int max); + + +/** + * @brief Generates a random big integer number in the given range, bounds included. + * + * @param min The minimum value of the range. + * @param max The maximum value of the range. + * + * @return A random big integer number. + * + * @code + * faker::number::bigInt(1000000000, 9999999999) // Example output: 4593830193 + * @endcode + */ +FAKER_CXX_EXPORT std::optional bigInt(std::optional min = std::nullopt, std::optional max = std::nullopt); + +} diff --git a/src/modules/number.cpp b/src/modules/number.cpp index 76a3c0ba..380bd74f 100644 --- a/src/modules/number.cpp +++ b/src/modules/number.cpp @@ -1,118 +1,141 @@ -#include "faker-cxx/number.h" - -#include - -#include "common/format_helper.h" -#include "faker-cxx/helper.h" -#include "faker-cxx/types/hex.h" -#include "number_data.h" - -namespace faker::number -{ -namespace -{ -const std::map hexCasingToCharactersMapping{ - {HexCasing::Lower, hexLowerCharacters}, - {HexCasing::Upper, hexUpperCharacters}, -}; -const std::map hexPrefixToStringMapping{ - {HexPrefix::ZeroX, "0x"}, - {HexPrefix::Hash, "#"}, - {HexPrefix::None, ""}, -}; -} - -std::string hexadecimal(unsigned int length, HexCasing casing, HexPrefix prefix) -{ - const auto& hexadecimalCharacters = hexCasingToCharactersMapping.at(casing); - - const auto& hexadecimalPrefix = hexPrefixToStringMapping.at(prefix); - - std::string hexadecimal{hexadecimalPrefix}; - - for (unsigned i = 0; i < length; i++) - { - hexadecimal += helper::randomElement(hexadecimalCharacters); - } - - return hexadecimal; -} - -std::string hexadecimal(std::optional min, std::optional max) -{ - int defaultMin = 0; - int defaultMax = 15; - - if (min.has_value()) - { - defaultMin = min.value(); - } - - if (max.has_value()) - { - defaultMax = max.value(); - } - - return common::format("{:x}", number::integer(defaultMin, defaultMax)); -} - -std::string octal(unsigned int length) -{ - std::string octalNumber; - - for (unsigned int i = 0; i < length; ++i) - { - octalNumber += static_cast(number::integer(7)); - } - - return "0o" + octalNumber; -} - -std::string binary(int length) -{ - if (length < 0) - { - throw std::invalid_argument("The length of a binary number cannot be negative"); - } - - std::string binaryNumber; - - for (int i = 0; i < length; ++i) - { - binaryNumber += static_cast(number::integer(1)); - } - - return "0b" + binaryNumber; -} - -std::string binary(int min, int max) -{ - if (min > max) - { - throw std::invalid_argument("min cannot be greater than max"); - } - - if (min < 0 || max < 0) - { - throw std::invalid_argument("The output binary string cannot be negative"); - } - - int num = number::integer(min, max); - - if (num == 0) - { - return "0b0"; - } - - std::string output; - - while (num > 0) - { - int remainder = num % 2; - output = std::to_string(remainder) + output; - num /= 2; - } - - return "0b" + output; -} -} +#include "faker-cxx/number.h" + +#include + +#include "common/format_helper.h" +#include "faker-cxx/helper.h" +#include "faker-cxx/types/hex.h" +#include "number_data.h" + +namespace faker::number +{ +namespace +{ +const std::map hexCasingToCharactersMapping{ + {HexCasing::Lower, hexLowerCharacters}, + {HexCasing::Upper, hexUpperCharacters}, +}; +const std::map hexPrefixToStringMapping{ + {HexPrefix::ZeroX, "0x"}, + {HexPrefix::Hash, "#"}, + {HexPrefix::None, ""}, +}; +} + +std::string hexadecimal(unsigned int length, HexCasing casing, HexPrefix prefix) +{ + const auto& hexadecimalCharacters = hexCasingToCharactersMapping.at(casing); + + const auto& hexadecimalPrefix = hexPrefixToStringMapping.at(prefix); + + std::string hexadecimal{hexadecimalPrefix}; + + for (unsigned i = 0; i < length; i++) + { + hexadecimal += helper::randomElement(hexadecimalCharacters); + } + + return hexadecimal; +} + +std::string hexadecimal(std::optional min, std::optional max) +{ + int defaultMin = 0; + int defaultMax = 15; + + if (min.has_value()) + { + defaultMin = min.value(); + } + + if (max.has_value()) + { + defaultMax = max.value(); + } + + return common::format("{:x}", number::integer(defaultMin, defaultMax)); +} + +std::string octal(unsigned int length) +{ + std::string octalNumber; + + for (unsigned int i = 0; i < length; ++i) + { + octalNumber += static_cast(number::integer(7)); + } + + return "0o" + octalNumber; +} + +std::string binary(int length) +{ + if (length < 0) + { + throw std::invalid_argument("The length of a binary number cannot be negative"); + } + + std::string binaryNumber; + + for (int i = 0; i < length; ++i) + { + binaryNumber += static_cast(number::integer(1)); + } + + return "0b" + binaryNumber; +} + +std::string binary(int min, int max) +{ + if (min > max) + { + throw std::invalid_argument("min cannot be greater than max"); + } + + if (min < 0 || max < 0) + { + throw std::invalid_argument("The output binary string cannot be negative"); + } + + int num = number::integer(min, max); + + if (num == 0) + { + return "0b0"; + } + + std::string output; + + while (num > 0) + { + int remainder = num % 2; + output = std::to_string(remainder) + output; + num /= 2; + } + + return "0b" + output; +} + +std::optional bigInt(std::optional min, std::optional max) +{ + const long long DEFAULT_MAX = 9999999999999999LL; + const long long DEFAULT_MIN = 1LL; + + long long actualMin = min.value_or(DEFAULT_MIN); + long long actualMax = max.value_or(DEFAULT_MAX); + + if (actualMin > actualMax) + { + throw std::invalid_argument("min cannot be greater than max"); + } + + static std::mt19937_64 gen(std::random_device{}()); + std::uniform_int_distribution dist(actualMin, actualMax); + + return dist(gen); +} + + + +} + diff --git a/tests/modules/number_test.cpp b/tests/modules/number_test.cpp index c097b9bf..22f02177 100644 --- a/tests/modules/number_test.cpp +++ b/tests/modules/number_test.cpp @@ -1,256 +1,287 @@ -#include -#include - -#include "gtest/gtest.h" - -#include "faker-cxx/number.h" -#include "number_data.h" - -using namespace ::testing; -using namespace faker; -using namespace faker::number; - -class NumberTest : public Test -{ -public: -}; - -TEST_F(NumberTest, integer_givenInvalidRangeArguments_shouldThrowInvalidArgument) -{ - ASSERT_THROW(integer(10, 2), std::invalid_argument); -} - -TEST_F(NumberTest, givenRangeWithSameNumbers_shouldGenerateThisNumber) -{ - const int actualRandomNumber = integer(2, 2); - - ASSERT_EQ(actualRandomNumber, 2); -} - -TEST_F(NumberTest, givenValidRange_shouldGenerateNumberWithinGivenRange) -{ - const int actualRandomNumber = integer(2, 10); - - ASSERT_TRUE(actualRandomNumber >= 2); - ASSERT_TRUE(actualRandomNumber <= 10); -} - -TEST_F(NumberTest, givenSingleArgument_shouldCorrectlyResolveToTwoArgsOverload) -{ - const int randomNumber = integer(10); - - ASSERT_TRUE(randomNumber >= 0); - ASSERT_TRUE(randomNumber <= 10); -} - -TEST_F(NumberTest, decimal_givenInvalidRangeArguments_shouldThrowInvalidArgument) -{ - ASSERT_THROW(decimal(10.f, 2.f), std::invalid_argument); -} - -TEST_F(NumberTest, givenValidRangeArguments_shouldGenerateDecimalNumberThatIsInGivenRange) -{ - const std::floating_point auto actualRandomNumber = decimal(2.f, 10.f); - - ASSERT_TRUE(actualRandomNumber >= 2.f); - ASSERT_TRUE(actualRandomNumber <= 10.f); -} - -TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateThisNumberForDecimal) -{ - const std::floating_point auto actualRandomNumber = decimal(2.f, 2.f); - - ASSERT_EQ(actualRandomNumber, 2.f); -} - -TEST_F(NumberTest, normalDistribution_givenInvalidStandardDeviation_shouldThrowInvalidArgument) -{ - ASSERT_THROW(normalDistribution(10.f, -0.01f), std::invalid_argument); -} - -TEST_F(NumberTest, givenStandardDeviationOfINFINITY_shouldThrowInvalidArgument) -{ - ASSERT_THROW(normalDistribution(0.f, INFINITY), std::invalid_argument); -} - -TEST_F(NumberTest, givenMeanOfINFINITY_shouldThrowInvalidArgument) -{ - ASSERT_THROW(normalDistribution(INFINITY, 3.f), std::invalid_argument); -} - -TEST_F(NumberTest, givenStandardDeviationOf0_shouldGenerateMean) -{ - const std::floating_point auto normalDistributionNumber = normalDistribution(0.f, 0.f); - - ASSERT_EQ(normalDistributionNumber, 0.f); -} - -TEST_F(NumberTest, givenInvalidRangeArguments_shouldThrowInvalidArgument) -{ - ASSERT_THROW(normalDistribution(10.f, 3.f, 11.f, 10.f), std::invalid_argument); -} - -TEST_F(NumberTest, givenValidRangeArguments_shouldGenerateDecimalInGivenRange) -{ - const std::floating_point auto normalDistributionNumber = normalDistribution(10.f, 1000.f, 9.9f, 11.1f); - - ASSERT_TRUE(normalDistributionNumber <= 11.1f); - ASSERT_TRUE(normalDistributionNumber >= 9.9f); -} - -TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateTheExactNumber) -{ - const std::floating_point auto normalDistributionNumber = normalDistribution(10.f, 1000.f, 12.f, 12.f); - - ASSERT_TRUE(normalDistributionNumber == 12.f); -} - -TEST_F(NumberTest, givenHighRange_shouldGenerateMin) -{ - const std::floating_point auto normalDistributionNumber = normalDistribution(-100, .0001f, 10000.f, 10001.f); - - ASSERT_TRUE(normalDistributionNumber == 10000.f); -} - -TEST_F(NumberTest, givenHighRange_shouldGenerateMax) -{ - const std::floating_point auto normalDistributionNum = normalDistribution(10000, .0001f, -10001.f, -10000.f); - - ASSERT_TRUE(normalDistributionNum == -10000.f); -} - -TEST_F(NumberTest, shouldGenerateHexadecimal) -{ - const auto hexadecimalLength = 8; - - const auto generatedHexadecimal = hexadecimal(hexadecimalLength); - - const auto prefix = generatedHexadecimal.substr(0, 2); - const auto hexNumber = generatedHexadecimal.substr(2); - - ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength + 2); - ASSERT_EQ(prefix, "0x"); - ASSERT_TRUE(std::ranges::any_of(hexNumber, [hexNumber](char hexNumberCharacter) - { return hexLowerCharacters.find(hexNumberCharacter) != std::string::npos; })); -} - -TEST_F(NumberTest, shouldGenerateHexadecimalWithHashPrefix) -{ - const auto hexadecimalLength = 8; - - const auto generatedHexadecimal = hexadecimal(hexadecimalLength, HexCasing::Upper, HexPrefix::Hash); - - const auto prefix = generatedHexadecimal.substr(0, 1); - const auto hexNumber = generatedHexadecimal.substr(1); - - ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength + 1); - ASSERT_EQ(prefix, "#"); - ASSERT_TRUE(std::ranges::any_of(hexNumber, [](char hexNumberCharacter) - { return hexUpperCharacters.find(hexNumberCharacter) != std::string::npos; })); -} - -TEST_F(NumberTest, shouldGenerateHexadecimalWithoutPrefix) -{ - const auto hexadecimalLength = 8; - - const auto generatedHexadecimal = hexadecimal(hexadecimalLength, HexCasing::Upper, HexPrefix::None); - - ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength); - ASSERT_TRUE(std::ranges::any_of(generatedHexadecimal, [](char hexNumberCharacter) - { return hexUpperCharacters.find(hexNumberCharacter) != std::string::npos; })); -} - -TEST_F(NumberTest, shouldGenerateHexNumber) -{ - auto result = hexadecimal(100, 255); - ASSERT_EQ(result.size(), 2); - ASSERT_TRUE(std::isxdigit(result[0])); - ASSERT_TRUE(std::isxdigit(result[1])); - - result = hexadecimal(10, 15); - ASSERT_EQ(result.size(), 1); - ASSERT_TRUE(std::isxdigit(result[0])); - - result = hexadecimal(30, 40); - ASSERT_EQ(result.size(), 2); - ASSERT_TRUE(std::isxdigit(result[0])); - ASSERT_TRUE(std::isxdigit(result[1])); -} - -TEST_F(NumberTest, shouldGenerateOctalWithPrefix) -{ - const auto octalLength = 8; - - const auto generatedOctal = octal(octalLength); - - const auto prefix = generatedOctal.substr(0, 2); - const auto octalNumber = generatedOctal.substr(2); - - ASSERT_EQ(generatedOctal.size(), octalLength + 2); - ASSERT_EQ(prefix, "0o"); - ASSERT_TRUE( - std::ranges::any_of(generatedOctal, [](char octalNumberCharacter) - { return std::string("01234567").find(octalNumberCharacter) != std::string::npos; })); -} - -TEST_F(NumberTest, shouldGenerateBinary) -{ - const auto binaryLength = 8; - - const auto generatedBinary = binary(binaryLength); - - const auto prefix = generatedBinary.substr(0, 2); - const auto binaryNumber = generatedBinary.substr(2); - - ASSERT_EQ(generatedBinary.size(), binaryLength + 2); - ASSERT_EQ(prefix, "0b"); - ASSERT_TRUE(std::ranges::any_of(generatedBinary, [](char binaryNumberCharacter) - { return std::string("01").find(binaryNumberCharacter) != std::string::npos; })); -} - -TEST_F(NumberTest, givenValidArguments_shouldGenerateBinaryNumberInRange) -{ - const std::string generatedBinary = binary(1234, 1236); - int n = 1; - int decimalEquivalent = 0; - - for (int i = static_cast(generatedBinary.size() - 1); i >= 0; i--) - { - if (generatedBinary[static_cast(i)] == '1') - { - decimalEquivalent += n; - } - - n *= 2; - } - - ASSERT_EQ(generatedBinary[0], '0'); - ASSERT_EQ(generatedBinary[1], 'b'); - - ASSERT_TRUE(decimalEquivalent >= 1234); - ASSERT_TRUE(decimalEquivalent <= 1236); -} - -TEST_F(NumberTest, shouldGenerateBinaryFor0) -{ - const auto generatedBinary = binary(0, 0); - - ASSERT_EQ(generatedBinary, "0b0"); -} - -TEST_F(NumberTest, shouldGenerateBinaryFor7) -{ - const auto generatedBinary = binary(7, 7); - - ASSERT_EQ(generatedBinary, "0b111"); -} - -TEST_F(NumberTest, givenNegativeArguments_shouldThrowInvalidArgument) -{ - ASSERT_THROW(binary(INT_MIN, -1), std::invalid_argument); -} - -TEST_F(NumberTest, givenMinBiggerThanMax_shouldThrowInvalidArgument) -{ - ASSERT_THROW(binary(10, 1), std::invalid_argument); -} +#include +#include + +#include "gtest/gtest.h" + +#include "faker-cxx/number.h" +#include "number_data.h" + +using namespace ::testing; +using namespace faker; +using namespace faker::number; + +class NumberTest : public Test +{ +public: +}; + +TEST_F(NumberTest, integer_givenInvalidRangeArguments_shouldThrowInvalidArgument) +{ + ASSERT_THROW(integer(10, 2), std::invalid_argument); +} + +TEST_F(NumberTest, givenRangeWithSameNumbers_shouldGenerateThisNumber) +{ + const int actualRandomNumber = integer(2, 2); + + ASSERT_EQ(actualRandomNumber, 2); +} + +TEST_F(NumberTest, givenValidRange_shouldGenerateNumberWithinGivenRange) +{ + const int actualRandomNumber = integer(2, 10); + + ASSERT_TRUE(actualRandomNumber >= 2); + ASSERT_TRUE(actualRandomNumber <= 10); +} + +TEST_F(NumberTest, givenSingleArgument_shouldCorrectlyResolveToTwoArgsOverload) +{ + const int randomNumber = integer(10); + + ASSERT_TRUE(randomNumber >= 0); + ASSERT_TRUE(randomNumber <= 10); +} + +TEST_F(NumberTest, decimal_givenInvalidRangeArguments_shouldThrowInvalidArgument) +{ + ASSERT_THROW(decimal(10.f, 2.f), std::invalid_argument); +} + +TEST_F(NumberTest, givenValidRangeArguments_shouldGenerateDecimalNumberThatIsInGivenRange) +{ + const std::floating_point auto actualRandomNumber = decimal(2.f, 10.f); + + ASSERT_TRUE(actualRandomNumber >= 2.f); + ASSERT_TRUE(actualRandomNumber <= 10.f); +} + +TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateThisNumberForDecimal) +{ + const std::floating_point auto actualRandomNumber = decimal(2.f, 2.f); + + ASSERT_EQ(actualRandomNumber, 2.f); +} + +TEST_F(NumberTest, normalDistribution_givenInvalidStandardDeviation_shouldThrowInvalidArgument) +{ + ASSERT_THROW(normalDistribution(10.f, -0.01f), std::invalid_argument); +} + +TEST_F(NumberTest, givenStandardDeviationOfINFINITY_shouldThrowInvalidArgument) +{ + ASSERT_THROW(normalDistribution(0.f, INFINITY), std::invalid_argument); +} + +TEST_F(NumberTest, givenMeanOfINFINITY_shouldThrowInvalidArgument) +{ + ASSERT_THROW(normalDistribution(INFINITY, 3.f), std::invalid_argument); +} + +TEST_F(NumberTest, givenStandardDeviationOf0_shouldGenerateMean) +{ + const std::floating_point auto normalDistributionNumber = normalDistribution(0.f, 0.f); + + ASSERT_EQ(normalDistributionNumber, 0.f); +} + +TEST_F(NumberTest, givenInvalidRangeArguments_shouldThrowInvalidArgument) +{ + ASSERT_THROW(normalDistribution(10.f, 3.f, 11.f, 10.f), std::invalid_argument); +} + +TEST_F(NumberTest, givenValidRangeArguments_shouldGenerateDecimalInGivenRange) +{ + const std::floating_point auto normalDistributionNumber = normalDistribution(10.f, 1000.f, 9.9f, 11.1f); + + ASSERT_TRUE(normalDistributionNumber <= 11.1f); + ASSERT_TRUE(normalDistributionNumber >= 9.9f); +} + +TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateTheExactNumber) +{ + const std::floating_point auto normalDistributionNumber = normalDistribution(10.f, 1000.f, 12.f, 12.f); + + ASSERT_TRUE(normalDistributionNumber == 12.f); +} + +TEST_F(NumberTest, givenHighRange_shouldGenerateMin) +{ + const std::floating_point auto normalDistributionNumber = normalDistribution(-100, .0001f, 10000.f, 10001.f); + + ASSERT_TRUE(normalDistributionNumber == 10000.f); +} + +TEST_F(NumberTest, givenHighRange_shouldGenerateMax) +{ + const std::floating_point auto normalDistributionNum = normalDistribution(10000, .0001f, -10001.f, -10000.f); + + ASSERT_TRUE(normalDistributionNum == -10000.f); +} + +TEST_F(NumberTest, shouldGenerateHexadecimal) +{ + const auto hexadecimalLength = 8; + + const auto generatedHexadecimal = hexadecimal(hexadecimalLength); + + const auto prefix = generatedHexadecimal.substr(0, 2); + const auto hexNumber = generatedHexadecimal.substr(2); + + ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength + 2); + ASSERT_EQ(prefix, "0x"); + ASSERT_TRUE(std::ranges::any_of(hexNumber, [hexNumber](char hexNumberCharacter) + { return hexLowerCharacters.find(hexNumberCharacter) != std::string::npos; })); +} + +TEST_F(NumberTest, shouldGenerateHexadecimalWithHashPrefix) +{ + const auto hexadecimalLength = 8; + + const auto generatedHexadecimal = hexadecimal(hexadecimalLength, HexCasing::Upper, HexPrefix::Hash); + + const auto prefix = generatedHexadecimal.substr(0, 1); + const auto hexNumber = generatedHexadecimal.substr(1); + + ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength + 1); + ASSERT_EQ(prefix, "#"); + ASSERT_TRUE(std::ranges::any_of(hexNumber, [](char hexNumberCharacter) + { return hexUpperCharacters.find(hexNumberCharacter) != std::string::npos; })); +} + +TEST_F(NumberTest, shouldGenerateHexadecimalWithoutPrefix) +{ + const auto hexadecimalLength = 8; + + const auto generatedHexadecimal = hexadecimal(hexadecimalLength, HexCasing::Upper, HexPrefix::None); + + ASSERT_EQ(generatedHexadecimal.size(), hexadecimalLength); + ASSERT_TRUE(std::ranges::any_of(generatedHexadecimal, [](char hexNumberCharacter) + { return hexUpperCharacters.find(hexNumberCharacter) != std::string::npos; })); +} + +TEST_F(NumberTest, shouldGenerateHexNumber) +{ + auto result = hexadecimal(100, 255); + ASSERT_EQ(result.size(), 2); + ASSERT_TRUE(std::isxdigit(result[0])); + ASSERT_TRUE(std::isxdigit(result[1])); + + result = hexadecimal(10, 15); + ASSERT_EQ(result.size(), 1); + ASSERT_TRUE(std::isxdigit(result[0])); + + result = hexadecimal(30, 40); + ASSERT_EQ(result.size(), 2); + ASSERT_TRUE(std::isxdigit(result[0])); + ASSERT_TRUE(std::isxdigit(result[1])); +} + +TEST_F(NumberTest, shouldGenerateOctalWithPrefix) +{ + const auto octalLength = 8; + + const auto generatedOctal = octal(octalLength); + + const auto prefix = generatedOctal.substr(0, 2); + const auto octalNumber = generatedOctal.substr(2); + + ASSERT_EQ(generatedOctal.size(), octalLength + 2); + ASSERT_EQ(prefix, "0o"); + ASSERT_TRUE( + std::ranges::any_of(generatedOctal, [](char octalNumberCharacter) + { return std::string("01234567").find(octalNumberCharacter) != std::string::npos; })); +} + +TEST_F(NumberTest, shouldGenerateBinary) +{ + const auto binaryLength = 8; + + const auto generatedBinary = binary(binaryLength); + + const auto prefix = generatedBinary.substr(0, 2); + const auto binaryNumber = generatedBinary.substr(2); + + ASSERT_EQ(generatedBinary.size(), binaryLength + 2); + ASSERT_EQ(prefix, "0b"); + ASSERT_TRUE(std::ranges::any_of(generatedBinary, [](char binaryNumberCharacter) + { return std::string("01").find(binaryNumberCharacter) != std::string::npos; })); +} + +TEST_F(NumberTest, givenValidArguments_shouldGenerateBinaryNumberInRange) +{ + const std::string generatedBinary = binary(1234, 1236); + int n = 1; + int decimalEquivalent = 0; + + for (int i = static_cast(generatedBinary.size() - 1); i >= 0; i--) + { + if (generatedBinary[static_cast(i)] == '1') + { + decimalEquivalent += n; + } + + n *= 2; + } + + ASSERT_EQ(generatedBinary[0], '0'); + ASSERT_EQ(generatedBinary[1], 'b'); + + ASSERT_TRUE(decimalEquivalent >= 1234); + ASSERT_TRUE(decimalEquivalent <= 1236); +} + +TEST_F(NumberTest, shouldGenerateBinaryFor0) +{ + const auto generatedBinary = binary(0, 0); + + ASSERT_EQ(generatedBinary, "0b0"); +} + +TEST_F(NumberTest, shouldGenerateBinaryFor7) +{ + const auto generatedBinary = binary(7, 7); + + ASSERT_EQ(generatedBinary, "0b111"); +} + +TEST_F(NumberTest, givenNegativeArguments_shouldThrowInvalidArgument) +{ + ASSERT_THROW(binary(INT_MIN, -1), std::invalid_argument); +} + +TEST_F(NumberTest, givenMinBiggerThanMax_shouldThrowInvalidArgument) +{ + ASSERT_THROW(binary(10, 1), std::invalid_argument); +} + +TEST_F(NumberTest, givenValidRange_shouldGenerateBigIntWithinRange) +{ + const long min = 1000000000000000L; + const long max = 9999999999999999L; + + const long actualRandomBigInt = bigInt(min, max).value(); + + ASSERT_GE(actualRandomBigInt, min); + ASSERT_LE(actualRandomBigInt, max); +} + +TEST_F(NumberTest, givenNegativeRange_shouldGenerateBigIntWithinRange) +{ + const long min = -1000000000000000L; + const long max = -1L; + + const long actualRandomBigInt = bigInt(min, max).value(); + + ASSERT_GE(actualRandomBigInt, min); + ASSERT_LE(actualRandomBigInt, max); +} + +TEST_F(NumberTest, givenSameRange_shouldGenerateExactBigInt) +{ + const long minMax = 5000000000000000L; + + const long actualRandomBigInt = bigInt(minMax, minMax).value(); + + ASSERT_EQ(actualRandomBigInt, minMax); +}