// // bigdecimal_test.cpp // bigdecimal // // Created by Sam Jaffe on 5/18/18. // #include "bignumber_test_printers.h" #include "xcode_gtest_helper.h" TEST(BigDecimalTest, ConstructIntegerAsDecimal) { EXPECT_THAT(math::bigdecimal(1000, 2).to_string(), "1000.00"); } TEST(BigDecimalTest, ConstructDecimal) { EXPECT_THAT(math::bigdecimal("1000.10").to_string(), "1000.10"); EXPECT_THAT(math::bigdecimal("1000.0000000001").to_string(), "1000.0000000001"); } TEST(BigDecimalTest, FormatsWithCommaOnlyBeforeDecimal) { math::number_format fmt{.separate_thousands = true, .decimal_precision = size_t(-1)}; EXPECT_THAT(math::bigdecimal("1000000.0000000001").to_string(fmt), "1,000,000.0000000001"); } TEST(BigDecimalTest, CanTruncate) { math::number_format fmt{.decimal_precision = 2}; EXPECT_THAT(math::bigdecimal("1000000.0000000001").to_string(fmt), "1000000.00"); } TEST(BigDecimalTest, ConstructIntWithScaleAndStep) { EXPECT_THAT(math::bigdecimal(1000000000, -2).to_string(), "1000000000"); } TEST(BigDecimalTest, RescalePositiveAddsDecimalPlaces) { math::bigdecimal dec(100); EXPECT_THAT(dec.scale(), 0); dec.rescale(2); EXPECT_THAT(dec.to_string(), "100.00"); } TEST(BigDecimalTest, RescaleNegativeDropsLowerOrderElements) { math::bigdecimal dec(111); EXPECT_THAT(dec.scale(), 0); dec.rescale(-2); EXPECT_THAT(dec.to_string(), "100"); } TEST(BigDecimalTest, RescaleDownPermanantlyDropsLowOrderElements) { math::bigdecimal dec("100.10"); EXPECT_THAT(dec.scale(), 2); dec.rescale(0); dec.rescale(2); EXPECT_THAT(dec.to_string(), "100.00"); } TEST(BigDecimalTest, ScaleCtorCanBeLossy) { math::bigdecimal dec("123", -2); EXPECT_THAT(dec.to_string(), "100"); } TEST(BigDecimalTest, NonLossyScaleCtorEqualsNoScaleCtor) { math::bigdecimal scl(100, -2); math::bigdecimal nc(100); EXPECT_THAT(scl, nc); } TEST(BigDecimalTest, ScaleBelowNegSegDoesntLoseAnything) { math::bigdecimal dec("1000000000", -9); EXPECT_THAT(dec.to_string(), "1000000000"); } TEST(BigDecimalTest, AddingEqualScalesDoesNotAddTrailingDigitsOrLoseData) { math::bigdecimal a("1000.10"); math::bigdecimal b("1000.01"); EXPECT_THAT(a.scale(), b.scale()); EXPECT_THAT((a + b).to_string(), "2000.11"); } TEST(BigDecimalTest, AdditionNormalizeScaleToHighest) { math::bigdecimal a("1000.10"); math::bigdecimal b("1000"); EXPECT_THAT(a.scale(), testing::Gt(b.scale())); EXPECT_THAT((a + b).scale(), a.scale()); } TEST(BigDecimalTest, InverseOfNumberCarriesSameScale) { math::bigdecimal a("1.001"); EXPECT_THAT(a.scale(), (-a).scale()); } TEST(BigDecimalTest, SubtractionNormalizeScaleToHighest) { math::bigdecimal a("900.10"); math::bigdecimal b("1000"); EXPECT_THAT(a.scale(), testing::Gt(b.scale())); EXPECT_THAT((a - b).scale(), a.scale()); EXPECT_THAT((b - a).scale(), a.scale()); } class MultiplicationScaleTest : public testing::TestWithParam {}; TEST_P(MultiplicationScaleTest, ScaleIsSumOfOperAndMultipScales) { auto tup = GetParam(); auto out = tup.lhs * tup.rhs; EXPECT_THAT(out.scale(), tup.lhs.scale() + tup.rhs.scale()); EXPECT_THAT(out.to_string(), tup.expected); } class DivisionScaleTest : public testing::TestWithParam {}; TEST_P(DivisionScaleTest, ScaleIsDifferenceOfNumAndDenomScales) { auto tup = GetParam(); auto out = tup.lhs / tup.rhs; EXPECT_THAT(out.scale(), tup.lhs.scale() - tup.rhs.scale()); EXPECT_THAT(out.to_string(), tup.expected); } TEST(MultiplicationTest, ProperlyScales) { math::bigdecimal num("6565.000000"); math::bigdecimal den("185749.82"); EXPECT_THAT(num / den, math::bigdecimal("0.035343237", 4)); } class EqTest : public testing::TestWithParam {}; TEST_P(EqTest, DecimalsAreEqualEvenIfScalesAreNot) { auto pair = GetParam(); EXPECT_THAT(pair.lhs, pair.rhs); } class DecimalLtTest : public testing::TestWithParam {}; TEST_P(DecimalLtTest, IsLessThanEvenWithDifferentScales) { auto pair = GetParam(); EXPECT_THAT(pair.lhs, testing::Lt(pair.rhs)); } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" INSTANTIATE_TEST_SUITE_P( BigDecimal, MultiplicationScaleTest, testing::Values(ArithTuple{{1, 1}, {1, 0}, "1.0"}, ArithTuple{{1, 0}, {1, 1}, "1.0"}, ArithTuple{{1, 0}, {10, 0}, "10"}, ArithTuple{{1, 1}, {10, 0}, "10.0"}, ArithTuple{ {1, 1}, {10, -1}, "10", }, ArithTuple{{"1.1"}, {"1.1"}, "1.21"}, ArithTuple{{"0.01"}, {100, -2}, "1"}, ArithTuple{{1, 5}, {1, 5}, "1.0000000000"}, ArithTuple{{1, 5}, {1000000000, -9}, "1000000000"}, ArithTuple{{100, -2}, {1000000000, -9}, "100000000000"}, ArithTuple{{10000, -4}, {100000, -5}, "1000000000"})); INSTANTIATE_TEST_SUITE_P( BigDecimal, DivisionScaleTest, testing::Values( ArithTuple{{1, 1}, {1, 0}, "1.0"}, ArithTuple{{1, 0}, {1, 1}, "0"}, ArithTuple{{1, 0}, {10, 0}, "0"}, ArithTuple{{1, 1}, {10, 0}, "0.1"}, ArithTuple{{1, 1}, {10, -1}, "0.10"}, ArithTuple{{"1.1"}, {"1.1"}, "1"}, ArithTuple{{"0.01"}, {100, -2}, "0.0001"}, ArithTuple{{1, 5}, {1, 5}, "1"}, ArithTuple{{1, 5}, {1000000000, -9}, "0.00000000100000"}, ArithTuple{{100, -2}, {1000000000, -9}, "0.0000001"}, ArithTuple{{10000, -4}, {100000, -5}, "0.1"}, ArithTuple{{"11.0"}, {"1.10"}, "10"})); INSTANTIATE_TEST_SUITE_P( BigDecimal, EqTest, testing::Values(BigDecPair{{0}, {0, 4}}, BigDecPair{{100}, {100, -2}}, BigDecPair{{1000000000, -4}, {1000000000, -9}}, BigDecPair{{"0.1", 1}, {"0.10", 2}})); INSTANTIATE_TEST_SUITE_P( BigDecimal, DecimalLtTest, testing::Values(BigDecPair{{0, 0}, {1, 4}}, BigDecPair{{0, 4}, {1, 0}}, BigDecPair{{0, 4}, {1, 4}}, BigDecPair{{-1, 4}, {1, 4}}, BigDecPair{{-2, 0}, {-1, 4}}, BigDecPair{{-2, 4}, {-1, 0}}, BigDecPair{{-2, 4}, {-1, 4}})); #pragma clang diagnostic pop