예제 #1
0
 public void Money_Should_Be_Serializable_To_Json()
 {
     JsonConvert
     .SerializeObject(UMoney.Create(10, 5))
     .Should()
     .Be("\"10.00000\"");
 }
예제 #2
0
 public void Money_Should_Be_Deserializable_From_Json()
 {
     JsonConvert
     .DeserializeObject <UMoney>("\"10.00000\"")
     .Should()
     .Be(UMoney.Create(10, 5));
 }
        public void CompareTo__Decimal_Value_Passed__Returns_Correct_Result()
        {
            var money = new UMoney(42, 0);

            (money < 43m).Should().BeTrue();
            (money > 41m).Should().BeTrue();
            (money <= 43m).Should().BeTrue();
            (money >= 41m).Should().BeTrue();
            (money <= 42m).Should().BeTrue();
            (money >= 42m).Should().BeTrue();

            (43m > money).Should().BeTrue();
            (41m < money).Should().BeTrue();
            (43m >= money).Should().BeTrue();
            (41m <= money).Should().BeTrue();
            (42m <= money).Should().BeTrue();
            (42m >= money).Should().BeTrue();

            money
            .CompareTo(41m)
            .Should()
            .BePositive();

            money
            .CompareTo(42m)
            .Should()
            .Be(0);

            money
            .CompareTo(43m)
            .Should()
            .BeNegative();
        }
예제 #4
0
        private static async Task <object> BuildInvalidTransactionAsync(ITransactionsExecutorApi client)
        {
            Console.WriteLine("Building the invalid transaction...");

            return(await client.BuildTransferAmountTransactionAsync
                   (
                       new BuildTransferAmountTransactionRequest
                       (
                           new[]
            {
                new Transfer
                (
                    new Asset("STEEM"),
                    UMoney.Create(100, 3),
                    "Test:c021d892538b4a7a8520ae46f368c00f",
                    "Test:0662c0c7b9954373a5803fab41d97774"
                ),
                new Transfer
                (
                    new Asset("STEEM"),
                    UMoney.Create(50, 3),
                    "Test:c021d892538b4a7a8520ae46f368c00f",
                    "Test:0662c0c7b9954373a5803fab41d97774"
                )
            },
                           new []
            {
                new Fee(new Asset("STEEM"), UMoney.Create(0.001m, 3))
            }
                       )
                   ));
        }
예제 #5
0
        public void Test_that_coins_to_receive_should_be_numbers_in_a_row_starting_from_zero(string coinsToReceiveNumbers, bool shouldThrow)
        {
            var coinToSpend = new CoinToSpend
                              (
                new CoinId("1", 1),
                new Asset("KIN"),
                UMoney.Create(100, 3),
                "A"
                              );
            var coinsToReceive = coinsToReceiveNumbers
                                 .Split(',')
                                 .Select(x => new CoinToReceive
                                         (
                                             int.Parse(x),
                                             new Asset("KIN"),
                                             UMoney.Create(1, 3),
                                             "B"
                                         ))
                                 .ToArray();

            if (shouldThrow)
            {
                Assert.Throws <RequestValidationException>(() => TransactionCoinsValidator.Validate(new[] { coinToSpend }, coinsToReceive));
            }
            else
            {
                Assert.DoesNotThrow(() => TransactionCoinsValidator.Validate(new[] { coinToSpend }, coinsToReceive));
            }
        }
 public override object ConvertFrom(
     ITypeDescriptorContext context,
     CultureInfo culture,
     object value)
 {
     return(UMoney.Parse((string)value));
 }
예제 #7
0
        private static IEnumerable <UMoney> Values()
        {
            yield return(UMoney.Create(10.0000m));

            yield return(UMoney.Create(13.00m));

            yield return(UMoney.Create(10.300000m));
        }
        public UMoneyFormatterTests()
        {
            _expectedDeserializedValue = UMoney.Parse("42.0");
            _expectedSerializedValue   = new byte[] { 146, 196, 2, 164, 1, 1 };
            _formatterResolver         = new TestFormatterResolver();

            _formatterResolver
            .SetFormatter(new UMoneyFormatter());
        }
예제 #9
0
        public int Test_comparison(string a, string b)
        {
            var aParts = a.Split(':');
            var bParts = b.Split(':');

            var aFee = new Fee(new Asset(aParts[0]), UMoney.Parse(aParts[1]));
            var bFee = new Fee(new Asset(bParts[0]), UMoney.Parse(bParts[1]));

            return(aFee.CompareTo(bFee));
        }
예제 #10
0
        public bool Test_equation(string a, string b)
        {
            var aParts = a.Split(':');
            var bParts = b.Split(':');

            var aFee = new Fee(new Asset(aParts[0]), UMoney.Parse(aParts[1]));
            var bFee = new Fee(new Asset(bParts[0]), UMoney.Parse(bParts[1]));

            return(Equals(aFee, bFee));
        }
예제 #11
0
        public bool Test_hash_code_equation(string a, string b)
        {
            var aParts = a.Split(':');
            var bParts = b.Split(':');

            var aFee = new Fee(new Asset(aParts[0]), UMoney.Parse(aParts[1]));
            var bFee = new Fee(new Asset(bParts[0]), UMoney.Parse(bParts[1]));

            return(aFee.GetHashCode() == bFee.GetHashCode());
        }
예제 #12
0
        public async Task Estimate_transfer_coins_transaction()
        {
            //ARRANGE
            var fees = new[]
            {
                new Fee(new Asset("asset"), UMoney.Create(1000, 4))
            };

            var client = PrepareClient <AppSettings>((options) =>
            {
                var aggregator = CreateMocksAndSetupFactories(options);

                options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Estimate_transfer_coins_transaction)}";
                aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease);
                aggregator.TransferCoinsTransactionsEstimator
                .Setup(x => x.EstimateTransferCoinsAsync(It.IsAny <EstimateTransferCoinsTransactionRequest>()))
                .ReturnsAsync(new EstimateTransactionResponse(fees));
            });

            //ACT
            var coinsToSpend = new[]
            {
                new CoinToSpend(new CoinId("tx1", 0),
                                new Asset("assetId"),
                                UMoney.Create(1000, 4),
                                new Address("0x1"),
                                Base64String.Encode("context"),
                                1),
            };
            var coinsToReceive = new[]
            {
                new CoinToReceive(0,
                                  new Asset("assetId"),
                                  UMoney.Create(1000, 4),
                                  new Address("0x2"),
                                  new AddressTag("tag"),
                                  AddressTagType.Text
                                  ),
            };

            var request = new EstimateTransferCoinsTransactionRequest(coinsToSpend, coinsToReceive);
            var result  = await client.EstimateTransferCoinsTransactionAsync(request);

            //ASSERT
            Assert.NotNull(result);

            var estimation = result.EstimatedFees.SingleOrDefault();

            Assert.NotNull(estimation);
            Assert.AreEqual(new Asset("asset"), estimation.Asset);
            Assert.AreEqual(UMoney.Create(1000, 4), estimation.Amount);
        }
예제 #13
0
 public void Test_that_single_transfer_is_allowed()
 {
     TransactionTransfersValidator.Validate(new List <Transfer>
     {
         new Transfer
         (
             new Asset("STEEM"),
             UMoney.Create(100, 3),
             "A",
             "B"
         )
     });
 }
예제 #14
0
 /// <summary>
 /// Coin to spend for the transaction.
 /// </summary>
 /// <param name="coinId">Reference to the coin which should be spend.</param>
 /// <param name="asset">Asset of the coin.</param>
 /// <param name="value">Coin value to spend.</param>
 /// <param name="address">Address that owns the coin.</param>
 /// <param name="addressContext">
 /// Optional.
 /// Address context associated with the owner address.
 /// </param>
 /// <param name="addressNonce">
 /// Optional.
 /// Nonce number of the transaction for the owner address.
 /// </param>
 public CoinToSpend(
     CoinId coinId,
     Asset asset,
     UMoney value,
     Address address,
     Base64String addressContext = null,
     long?addressNonce           = null)
 {
     Coin           = coinId ?? throw RequestValidationException.ShouldBeNotNull(nameof(coinId));
     Asset          = asset ?? throw RequestValidationException.ShouldBeNotNull(nameof(asset));
     Value          = value;
     Address        = address ?? throw RequestValidationException.ShouldBeNotNull(nameof(address));
     AddressContext = addressContext;
     AddressNonce   = addressNonce;
 }
예제 #15
0
        public async Task Build_transfer_coins_transaction()
        {
            //ARRANGE
            string transactionResponse = "transactionResponse";

            var client = PrepareClient <AppSettings>((options) =>
            {
                var aggregator = CreateMocksAndSetupFactories(options);

                options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Build_transfer_coins_transaction)}";
                aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease);
                aggregator.TransferCoinsTransactionsBuilder
                .Setup(x => x.BuildTransferCoinsAsync(It.IsAny <BuildTransferCoinsTransactionRequest>()))
                .ReturnsAsync(new BuildTransactionResponse(Base64String.Encode(transactionResponse)));
            });

            //ACT
            var coinsToSpend = new[]
            {
                new CoinToSpend(new CoinId("tx1", 0),
                                new Asset("assetId"),
                                UMoney.Create(1000, 4),
                                new Address("0x1"),
                                Base64String.Encode("context"),
                                1),
            };
            var coinsToReceive = new[]
            {
                new CoinToReceive(0,
                                  new Asset("assetId"),
                                  UMoney.Create(1000, 4),
                                  new Address("0x2"),
                                  new AddressTag("tag"),
                                  AddressTagType.Text
                                  ),
            };
            var expirationOptions = new ExpirationOptions(DateTime.Now + TimeSpan.FromDays(1));

            var request = new BuildTransferCoinsTransactionRequest(coinsToSpend, coinsToReceive, expirationOptions);
            var result  = await client.BuildTransferCoinsTransactionAsync(request);

            //ASSERT

            Assert.True(result != null);
            Assert.True(result.TransactionContext.DecodeToString() == transactionResponse);
        }
예제 #16
0
        public void Bad_request_transfer_coins_transaction()
        {
            //ARRANGE

            var client = PrepareClient <AppSettings>((options) =>
            {
                var aggregator = CreateMocksAndSetupFactories(options);

                options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Bad_request_transfer_coins_transaction)}";
                aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease);
                aggregator.TransferCoinsTransactionsBuilder
                .Setup(x => x.BuildTransferCoinsAsync(It.IsAny <BuildTransferCoinsTransactionRequest>()))
                .ThrowsAsync(new TransactionBuildingException(TransactionBuildingError.RetryLater, "some error"));
            });

            //ACT && ASSERT
            var coinsToSpend = new[]
            {
                new CoinToSpend(new CoinId("tx1", 0),
                                new Asset("assetId"),
                                UMoney.Create(1000, 4),
                                new Address("0x1"),
                                Base64String.Encode("context"),
                                1),
            };
            var coinsToReceive = new[]
            {
                new CoinToReceive(0,
                                  new Asset("assetId"),
                                  UMoney.Create(1000, 4),
                                  new Address("0x2"),
                                  new AddressTag("tag"),
                                  AddressTagType.Text
                                  ),
            };
            var expirationOptions = new ExpirationOptions(DateTime.Now + TimeSpan.FromDays(1));

            Assert.ThrowsAsync <TransactionBuildingWebApiException>(async() =>
            {
                var request = new BuildTransferCoinsTransactionRequest(coinsToSpend, coinsToReceive, expirationOptions);
                await client.BuildTransferCoinsTransactionAsync(request);
            });
        }
예제 #17
0
        public void Internal_server_error_estimate_transfer_coins_transaction()
        {
            //ARRANGE
            var client = PrepareClient <AppSettings>((options) =>
            {
                var aggregator = CreateMocksAndSetupFactories(options);

                options.IntegrationName =
                    $"{nameof(TransactionExecutorClientTests)}+{nameof(Internal_server_error_estimate_transfer_coins_transaction)}";
                aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease);
                aggregator.TransferCoinsTransactionsEstimator
                .Setup(x => x.EstimateTransferCoinsAsync(It.IsAny <EstimateTransferCoinsTransactionRequest>()))
                .ThrowsAsync(new Exception("some error"));
            });

            //ACT && ASSERT
            var coinsToSpend = new[]
            {
                new CoinToSpend(new CoinId("tx1", 0),
                                new Asset("assetId"),
                                UMoney.Create(1000, 4),
                                new Address("0x1"),
                                Base64String.Encode("context"),
                                1),
            };
            var coinsToReceive = new[]
            {
                new CoinToReceive(0,
                                  new Asset("assetId"),
                                  UMoney.Create(1000, 4),
                                  new Address("0x2"),
                                  new AddressTag("tag"),
                                  AddressTagType.Text
                                  ),
            };

            Assert.ThrowsAsync <InternalServerErrorWebApiException>(async() =>
            {
                var request = new EstimateTransferCoinsTransactionRequest(coinsToSpend, coinsToReceive);
                await client.EstimateTransferCoinsTransactionAsync(request);
            });
        }
예제 #18
0
        public async Task ReadBlockAsync(long blockNumber, IBlockListener listener)
        {
            var blockId         = Guid.NewGuid().ToString("N");
            var previousBlockId = Guid.NewGuid().ToString("N");

            listener.HandleRawBlock("raw-block".ToBase64(), blockId);

            var transactionsListener = listener.StartBlockTransactionsHandling
                                       (
                new BlockHeaderReadEvent
                (
                    blockNumber,
                    blockId,
                    DateTime.UtcNow,
                    100,
                    1,
                    previousBlockId
                )
                                       );

            var transactionId = new TransactionId(Guid.NewGuid().ToString("N"));

            await transactionsListener.HandleRawTransactionAsync("raw-transaction".ToBase64(), transactionId);

            transactionsListener.HandleExecutedTransaction
            (
                new TransferAmountExecutedTransaction
                (
                    transactionNumber: 1,
                    transactionId: transactionId,
                    balanceChanges: new[]
            {
                new BalanceChange("1", new Asset("STEEM"), Money.Create(123, 4), "abc")
            },
                    fees: new[]
            {
                new Fee(new Asset("STEEM"), UMoney.Create(0.0001m, 4)),
            },
                    isIrreversible: true
                )
            );
        }
        public void Equals__Integer_Value_Passed__Return_Correct_Result()
        {
            var money = new UMoney(42, 0);

            (money == 42).Should().BeTrue();
            (money != 41).Should().BeTrue();

            (42 == money).Should().BeTrue();
            (41 != money).Should().BeTrue();

            money
            .Equals(42)
            .Should()
            .BeTrue();

            money
            .Equals(41)
            .Should()
            .BeFalse();
        }
        public void Equals__Decimal_Value_Passed__Return_Correct_Result()
        {
            var money = new UMoney(42, 0);

            (money == 42m).Should().BeTrue();
            (money != 41m).Should().BeTrue();

            (42m == money).Should().BeTrue();
            (41m != money).Should().BeTrue();

            money
            .Equals(42m)
            .Should()
            .BeTrue();

            money
            .Equals(41m)
            .Should()
            .BeFalse();
        }
예제 #21
0
        public void Nullable_Money_Should_Be_Serializable_To_Json()
        {
            // ReSharper disable once JoinDeclarationAndInitializer
            UMoney?value;

            value = UMoney.Create(10, 5);

            JsonConvert
            .SerializeObject(value)
            .Should()
            .Be("\"10.00000\"");

            value = null;

            JsonConvert
            // ReSharper disable once ExpressionIsAlwaysNull
            .SerializeObject(value)
            .Should()
            .Be("null");
        }
        public void Equals__Money_Value_Passed__Return_Correct_Result()
        {
            var money = new UMoney(42, 0);

            (money == Money.Create(42m)).Should().BeTrue();
            (money != Money.Create(41m)).Should().BeTrue();

            (Money.Create(42m) == money).Should().BeTrue();
            (Money.Create(41m) != money).Should().BeTrue();

            money
            .Equals(Money.Create(42m))
            .Should()
            .BeTrue();

            money
            .Equals(Money.Create(41m))
            .Should()
            .BeFalse();
        }
예제 #23
0
        public void Test_that_empty_collections_are_not_allowed()
        {
            // Arrange

            var coinToSpend = new CoinToSpend
                              (
                new CoinId("1", 1),
                new Asset("KIN"),
                UMoney.Create(100, 3),
                "A"
                              );
            var coinToReceive = new CoinToReceive
                                (
                0,
                new Asset("KIN"),
                UMoney.Create(100, 3),
                "A"
                                );

            // Act, Throw

            Assert.Throws <RequestValidationException>
            (
                () => TransactionCoinsValidator.Validate(null, new[] { coinToReceive })
            );

            Assert.Throws <RequestValidationException>
            (
                () => TransactionCoinsValidator.Validate(Array.Empty <CoinToSpend>(), new[] { coinToReceive })
            );

            Assert.Throws <RequestValidationException>
            (
                () => TransactionCoinsValidator.Validate(new[] { coinToSpend }, null)
            );

            Assert.Throws <RequestValidationException>
            (
                () => TransactionCoinsValidator.Validate(new[] { coinToSpend }, Array.Empty <CoinToReceive>())
            );
        }
예제 #24
0
        public Task <EstimateTransactionResponse> EstimateTransferAmountAsync(EstimateTransferAmountTransactionRequest request)
        {
            if (request.Transfers.Count > 1)
            {
                throw new RequestValidationException("Only single transfer is supported", request.Transfers.Count, nameof(request.Transfers.Count));
            }

            var fee = (UMoney)(request.Transfers.Single().Amount * 0.00001M);

            return(Task.FromResult(new EstimateTransactionResponse
                                   (
                                       new[]
            {
                new Fee
                (
                    request.Transfers.Single().Asset,
                    UMoney.Round(fee, 6)
                )
            }
                                   )));
        }
예제 #25
0
        public void Test_that_duplicated_transfers_are_not_allowed()
        {
            var transfers = new List <Transfer>
            {
                new Transfer
                (
                    new Asset("XRP"),
                    UMoney.Create(100, 3),
                    "A",
                    "B"
                ),
                new Transfer
                (
                    new Asset("XRP"),
                    UMoney.Create(80, 5),
                    "A",
                    "B"
                )
            };

            Assert.Throws <RequestValidationException>(() => TransactionTransfersValidator.Validate(transfers));
        }
예제 #26
0
        public async Task Estimate_transfer_amount_transaction()
        {
            //ARRANGE
            var fees = new[]
            {
                new Fee(new Asset("asset"), UMoney.Create(1000, 4))
            };

            var client = PrepareClient <AppSettings>((options) =>
            {
                var aggregator = CreateMocksAndSetupFactories(options);

                options.IntegrationName = $"{nameof(TransactionExecutorClientTests)}+{nameof(Estimate_transfer_amount_transaction)}";
                aggregator.HealthProvider.Setup(x => x.GetDiseaseAsync()).ReturnsAsync(Disease);
                aggregator.TransactionEstimator.Setup(x => x.EstimateTransferAmountAsync(It.IsAny <EstimateTransferAmountTransactionRequest>()))
                .ReturnsAsync(new EstimateTransactionResponse(fees));
            });

            //ACT
            var transfers = new[]
            {
                new Transfer(
                    new Asset("asset"),
                    UMoney.Create(1000000000, 4),
                    new Address("x1"),
                    new Address("x2")),
            };
            var request = new EstimateTransferAmountTransactionRequest(transfers);
            var result  = await client.EstimateTransferAmountTransactionAsync(request);

            //ASSERT
            Assert.NotNull(result);

            var estimation = result.EstimatedFees.SingleOrDefault();

            Assert.NotNull(estimation);
            Assert.AreEqual(new Asset("asset"), estimation.Asset);
            Assert.AreEqual(UMoney.Create(1000, 4), estimation.Amount);
        }
예제 #27
0
        public void Test_that_sum_of_coins_to_send_equal_or_greater_than_sum_to_receive_for_each_assets(string assetsToSpend, string assetsToReceive, bool shouldThrow)
        {
            // Arrange

            var coinsToSpend = assetsToSpend
                               .Split(',')
                               .Select(x => x.Split(':'))
                               .Select(x => new CoinToSpend
                                       (
                                           new CoinId("1", 1),
                                           new Asset(x[0]),
                                           UMoney.Create(int.Parse(x[1]), 3),
                                           "A"
                                       ))
                               .ToArray();
            var coinsToReceive = assetsToReceive
                                 .Split(',')
                                 .Select(x => x.Split(':'))
                                 .Select((x, i) => new CoinToReceive
                                         (
                                             i,
                                             new Asset(x[0]),
                                             UMoney.Create(int.Parse(x[1]), 3),
                                             "A"
                                         ))
                                 .ToArray();

            // Act, Throw

            if (shouldThrow)
            {
                Assert.Throws <RequestValidationException>(() => TransactionCoinsValidator.Validate(coinsToSpend, coinsToReceive));
            }
            else
            {
                Assert.DoesNotThrow(() => TransactionCoinsValidator.Validate(coinsToSpend, coinsToReceive));
            }
        }
예제 #28
0
 public void Test_that_multiple_transfers_are_allowed(
     string asset1,
     string asset2,
     string asset3,
     string source1,
     string source2,
     string source3,
     string destination1,
     string destination2,
     string destination3)
 {
     TransactionTransfersValidator.Validate(new List <Transfer>
     {
         new Transfer
         (
             new Asset(asset1),
             UMoney.Create(100, 3),
             source1,
             destination1
         ),
         new Transfer
         (
             new Asset(asset2),
             UMoney.Create(80, 5),
             source2,
             destination2
         ),
         new Transfer
         (
             new Asset(asset3),
             UMoney.Create(80, 5),
             source3,
             destination3
         )
     });
 }
예제 #29
0
        /// <summary>
        /// Transfer of the transaction.
        /// </summary>
        /// <param name="asset">Asset to transfer.</param>
        /// <param name="amount">Amount to transfer from the source address to the destination address.</param>
        /// <param name="sourceAddress">Address to transfer from.</param>
        /// <param name="destinationAddress">Address to transfer to.</param>
        /// <param name="sourceAddressContext">
        /// Optional.
        /// Source address context associated with the address.
        /// </param>
        /// <param name="sourceAddressNonce">
        /// Optional.
        /// Nonce number of the transaction for the source address.
        /// </param>
        /// <param name="destinationAddressTag">
        /// Optional.
        /// Destination address tag.
        /// </param>
        /// <param name="destinationAddressTagType">
        /// Optional.
        /// Type of the destination address tag.
        /// </param>
        public Transfer(
            Asset asset,
            UMoney amount,
            Address sourceAddress,
            Address destinationAddress,
            Base64String sourceAddressContext        = null,
            long?sourceAddressNonce                  = null,
            AddressTag destinationAddressTag         = null,
            AddressTagType?destinationAddressTagType = null)
        {
            if (destinationAddressTagType.HasValue && destinationAddressTag == null)
            {
                throw new RequestValidationException("If the tag type is specified, the tag should be specified too", new [] { nameof(destinationAddressTagType), nameof(destinationAddressTag) });
            }

            Asset                     = asset ?? throw RequestValidationException.ShouldBeNotNull(nameof(asset));
            Amount                    = amount;
            SourceAddress             = sourceAddress ?? throw RequestValidationException.ShouldBeNotNull(nameof(sourceAddress));
            SourceAddressContext      = sourceAddressContext;
            SourceAddressNonce        = sourceAddressNonce;
            DestinationAddress        = destinationAddress ?? throw RequestValidationException.ShouldBeNotNull(nameof(destinationAddress));
            DestinationAddressTag     = destinationAddressTag;
            DestinationAddressTagType = destinationAddressTagType;
        }
        public void CompareTo__Integer_Value_Passed__Returns_Correct_Result()
        {
            var money = new UMoney(42, 0);


            (money > -1).Should().BeTrue();
            (money < 43).Should().BeTrue();
            (money > 41).Should().BeTrue();
            (money <= 43).Should().BeTrue();
            (money >= 41).Should().BeTrue();
            (money <= 42).Should().BeTrue();
            (money >= 42).Should().BeTrue();

            (-1 < money).Should().BeTrue();
            (43 > money).Should().BeTrue();
            (41 < money).Should().BeTrue();
            (43 >= money).Should().BeTrue();
            (41 <= money).Should().BeTrue();
            (42 <= money).Should().BeTrue();
            (42 >= money).Should().BeTrue();

            money
            .CompareTo(41)
            .Should()
            .BePositive();

            money
            .CompareTo(42)
            .Should()
            .Be(0);

            money
            .CompareTo(43)
            .Should()
            .BeNegative();
        }