Newer
Older
Warehouse / tests / Domain.UnitTests / Partners / PartnerTests.cs
@Derek Comartin Derek Comartin on 22 Aug 2023 7 KB Init
using FluentAssertions;
using MyWarehouse.Domain.Partners;
using MyWarehouse.Domain.Products;
using MyWarehouse.Domain.Transactions;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace MyWarehouse.Domain.UnitTests.Partners
{
    public class PartnerTests
    {
        [Test]
        public void NewPartner_Throws_WhenNameIsNullOrEmpty()
        {
            var partnerAddress = TestHelper.NewValidAddress;

            FluentActions.Invoking(() => new Partner(null, partnerAddress)).Should().
                ThrowExactly<ArgumentException>("null");

            FluentActions.Invoking(() => new Partner("", partnerAddress)).Should().
                ThrowExactly<ArgumentException>("empty");

            FluentActions.Invoking(() => new Partner("      ", partnerAddress)).Should().
                ThrowExactly<ArgumentException>("whitespace");
        }

        [Test]
        public void NewPartner_Throws_WhenNameIsEmpty()
        {
            FluentActions.Invoking(() => new Partner(null, TestHelper.NewValidAddress)).Should().
                ThrowExactly<ArgumentException>("null").WithMessage("*name*");

            FluentActions.Invoking(() => new Partner("", TestHelper.NewValidAddress)).Should().
                ThrowExactly<ArgumentException>("empty").WithMessage("*name*");

            FluentActions.Invoking(() => new Partner("   ", TestHelper.NewValidAddress)).Should().
                ThrowExactly<ArgumentException>("whitespace").WithMessage("*name*");
        }

        [Test]
        public void NewPartner_Throws_WhenAddressIsNull()
        {
            Action act = () => new Partner("John Test", null);

            FluentActions.Invoking(act).Should()
                .ThrowExactly<ArgumentNullException>();
        }

        [Test]
        public void NewPartner_HasAllPropertiesAssigned()
        {
            var partnerAddress = TestHelper.NewValidAddress;
            var partner = new Partner("John Test", partnerAddress);

            partner.Name.Should().Be("John Test");
            partner.Address.Should().NotBeNull()
                .And.BeSameAs(partnerAddress);
            partner.Transactions.Should()
                .NotBeNull().And
                .BeEmpty();
        }

        [Test]
        public void UpdateName_Throws_WhenNameIsNullOrEmpty()
        {
            var partner = TestHelper.NewValidPartner;

            FluentActions.Invoking(() => partner.UpdateName(null)).Should().
                ThrowExactly<ArgumentException>("null").WithMessage("*name*");

            FluentActions.Invoking(() => partner.UpdateName("")).Should().
                ThrowExactly<ArgumentException>("empty").WithMessage("*name*");

            FluentActions.Invoking(() => partner.UpdateName("      ")).Should().
                ThrowExactly<ArgumentException>("whitespace").WithMessage("*name*");
        }

        [Test]
        public void UpdateAddress_Throws_WhenAddressIsNull()
        {
            var partner = TestHelper.NewValidPartner;

            FluentActions.Invoking(() => partner.UpdateAddress(null)).Should().
                ThrowExactly<ArgumentNullException>();
        }

        [Test]
        public void SellTo_Throws_WhenLinesAreNullOrEmpty()
        {
            var partner = TestHelper.NewValidPartner;

            FluentActions.Invoking(() => partner.SellTo(null)).Should().
                ThrowExactly<ArgumentNullException>("null");

            FluentActions.Invoking(() => partner.SellTo(Enumerable.Empty<(Product, int)>())).Should().
                ThrowExactly<ArgumentException>("empty");
        }

        [Test]
        public void SellTo_Throws_WhenProductIsNull()
        {
            var partner = TestHelper.NewValidPartner;

            var lines = new List<(Product, int)>() {
                (null, 1)
            };

            FluentActions.Invoking(() => partner.SellTo(lines)).Should().
                ThrowExactly<ArgumentException>().WithMessage("*product*");
        }

        [Test]
        public void SellTo_Throws_WhenProductQuantityIsZeroOrLess()
        {
            var partner = TestHelper.NewValidPartner;

            var lines = new List<(Product, int)>() {
                (TestHelper.NewValidProduct_NoStock, 0)
            };

            FluentActions.Invoking(() => partner.SellTo(lines)).Should().
                ThrowExactly<ArgumentException>().WithMessage("*quantit*");
        }

        [Test]
        public void SellTo_Throws_WhenProductHasNoStock()
        {
            var partner = TestHelper.NewValidPartner;

            var lines = new List<(Product, int)>() {
                (TestHelper.NewValidProduct_NoStock, 2)
            };

            FluentActions.Invoking(() => partner.SellTo(lines)).Should().
                Throw<Exception>().WithMessage("*stock*");
        }

        [Test]
        public void SellTo_CreatesTransaction_WhenProductIsStocked()
        {
            var partner = TestHelper.NewValidPartner;
            var stockedProduct = TestHelper.NewValidProduct_WithStock(5);
            var lines = new List<(Product, int)>() {
                (stockedProduct, 2)
            };

            FluentActions.Invoking(() => partner.SellTo(lines)).Should()
                .NotThrow();

            partner.Transactions.Should().HaveCount(1)
                .And.Subject.First().TransactionType.Should().Be(TransactionType.Sales);
            partner.Transactions.First().TransactionLines.Should().HaveCount(1)
                .And.Subject.First().Should().Match<TransactionLine>(tl =>
                    tl.Product == stockedProduct && 
                    tl.Quantity == 2);

            stockedProduct.NumberInStock.Should().Be(5 - 2);
        }

        [Test]
        public void ProcureFrom_Throws_WhenLinesAreNullOrEmpty()
        {
            var partner = TestHelper.NewValidPartner;

            FluentActions.Invoking(() => partner.ProcureFrom(null)).Should().
                ThrowExactly<ArgumentNullException>("null");

            FluentActions.Invoking(() => partner.ProcureFrom(Enumerable.Empty<(Product, int)>())).Should().
                ThrowExactly<ArgumentException>("empty");
        }

        [Test]
        public void ProcureFrom_Throws_WhenProductIsNull()
        {
            var partner = TestHelper.NewValidPartner;

            var lines = new List<(Product, int)>() {
                (null, 1)
            };

            FluentActions.Invoking(() => partner.ProcureFrom(lines)).Should().
                ThrowExactly<ArgumentException>().WithMessage("*product*");
        }

        [Test]
        public void ProcureFrom_Throws_WhenProductQuantityIsZeroOrLess()
        {
            var partner = TestHelper.NewValidPartner;

            var lines = new List<(Product, int)>() {
                (TestHelper.NewValidProduct_NoStock, 0)
            };

            FluentActions.Invoking(() => partner.ProcureFrom(lines)).Should().
                ThrowExactly<ArgumentException>().WithMessage("*quantit*");
        }

        [Test]
        public void ProcureFrom_CreatesTransaction()
        {
            var partner = TestHelper.NewValidPartner;
            var product1 = TestHelper.NewValidProduct_NoStock;
            var product2 = TestHelper.NewValidProduct_NoStock;
            var lines = new List<(Product, int)>() {
                (product1, 2),
                (product2, 5)
            };

            FluentActions.Invoking(() => partner.ProcureFrom(lines)).Should()
                .NotThrow();

            partner.Transactions.Should().HaveCount(1)
                .And.Subject.First().TransactionType.Should().Be(TransactionType.Procurement);
            partner.Transactions.First().TransactionLines.Should().HaveCount(2)
                .And.BeEquivalentTo(new[] {
                    new { Product = product1, Quantity = 2 },
                    new { Product = product2, Quantity = 5 },
                }, o => o.ExcludingMissingMembers());

            product1.NumberInStock.Should().Be(2);
            product2.NumberInStock.Should().Be(5);
        }
    }
}