public void AddFineThrowsArgumentExceptionIfNegative()
        {
            var member = new Member("test", "member", "phone", "email", 1);

            var ex = Assert.Throws<ArgumentException>(() => member.AddFine(-5.00f));

            Assert.Equal("Fine must not be negative value", ex.Message);
        }
        public void CanAddFineToMember()
        {
            var member = new Member("test", "member", "phone", "email", 1);

            const float fine1 = 5.50f;
            const float fine2 = 2.00f;

            // Has no fines after being created.
            Assert.Equal(0, member.FineAmount);

            // Can add a fine.
            member.AddFine(fine1);

            Assert.Equal(fine1, member.FineAmount);

            // Make sure it will increment by additional amount.
            member.AddFine(fine2);

            Assert.Equal(fine1 + fine2, member.FineAmount);
        }
        public void WhenBorrowingAllowedAndFinePaidBorrowingAllowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            Assert.False(member.HasReachedLoanLimit);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);

            member.AddFine(5.00f);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);

            member.PayFine(5.00f);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);
        }
        public void WhenBorrowingAllowedAndFinedMoreThanMaxBorrowingDisallowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            var fineAmount = BookConstants.FINE_LIMIT + 1.00f;

            Assert.False(member.HasReachedLoanLimit);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);

            member.AddFine(fineAmount);

            Assert.True(member.HasReachedFineLimit);

            Assert.True(fineAmount > BookConstants.FINE_LIMIT);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndLoanRemovedButHasFinesBorrowingDisallowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            while (!member.HasReachedLoanLimit)
            {
                var loan = Substitute.For<ILoan>();

                member.AddLoan(loan);
            }

            member.AddFine(BookConstants.FINE_LIMIT + 1.00f);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            // Remove the first one that isn't the overdue mock.
            member.RemoveLoan(member.Loans[0]);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndFinePaidButStillOverFineLimitBorrowingDisallowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            var fineAmount = BookConstants.FINE_LIMIT + 5.00f;

            member.AddFine(fineAmount);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            member.PayFine(fineAmount - BookConstants.FINE_LIMIT);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndFinePaidButLoanLimitStillReachedBorrowingDisallowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            var fineAmount = BookConstants.FINE_LIMIT + 5.00f;

            while (!member.HasReachedLoanLimit)
            {
                var loan = Substitute.For<ILoan>();

                member.AddLoan(loan);
            }

            member.AddFine(fineAmount);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            member.PayFine(fineAmount);

            Assert.True(member.HasReachedLoanLimit);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndFinePaidButHasOverdueLoansBorrowingDisallowed()
        {
            var member = new Member("firstName", "lastName", "contactPhone", "emailAddress", 1);

            var loan = Substitute.For<ILoan>();

            var fineAmount = BookConstants.FINE_LIMIT + 5.00f;

            member.AddLoan(loan);

            member.AddFine(fineAmount);

            loan.IsOverDue.Returns(true);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            member.PayFine(fineAmount);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndLoanRemovedButHasFinesBorrowingDisallowed()
        {
            var book = new Book("author", "title", "call number", 1);

            var member = new Member("first", "last", "phone", "email", 1);

            while (!member.HasReachedLoanLimit)
            {
                var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7)) { State = LoanState.CURRENT };

                member.AddLoan(loan);
            }

            member.AddFine(BookConstants.FINE_LIMIT + 1.00f);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            // Remove the first one that isn't the overdue mock.
            member.RemoveLoan(member.Loans[0]);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndFinePaidButLoanLimitStillReachedBorrowingDisallowed()
        {
            var book = new Book("author", "title", "call number", 1);

            var member = new Member("first", "last", "phone", "email", 1);

            var fineAmount = BookConstants.FINE_LIMIT + 5.00f;

            while (!member.HasReachedLoanLimit)
            {
                var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7)) { State = LoanState.CURRENT };

                member.AddLoan(loan);
            }

            member.AddFine(fineAmount);

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            member.PayFine(fineAmount);

            Assert.True(member.HasReachedLoanLimit);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndFinePaidButHasOverdueLoansBorrowingDisallowed()
        {
            var book = new Book("author", "title", "call number", 1);

            var member = new Member("first", "last", "phone", "email", 1);

            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7)) { State = LoanState.CURRENT };

            var fineAmount = BookConstants.FINE_LIMIT + 5.00f;

            member.AddLoan(loan);

            member.AddFine(fineAmount);

            foreach (var l in member.Loans) l.CheckOverDue(DateTime.Today.AddMonths(1));

            // Borrowing state disallowed.
            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);

            member.PayFine(fineAmount);

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void PayFineThrowsArgumentExceptionIfPaymentExceedsFines()
        {
            const float fine = 5.50f;
            const float payment = 6.00f;

            var member = new Member("test", "member", "phone", "email", 1);

            member.AddFine(fine);

            Assert.Equal(fine, member.FineAmount);

            var fineAmount = member.FineAmount;

            var ex = Assert.Throws<ArgumentException>(() => member.PayFine(payment));

            Assert.Equal($"Payment must not exceed fines of {fineAmount}", ex.Message);
        }
        public void PayFineThrowsArgumentExceptionIfNegative()
        {
            const float fine = 5.50f;
            const float payment = -1.00f;

            var member = new Member("test", "member", "phone", "email", 1);

            member.AddFine(fine);

            Assert.Equal(fine, member.FineAmount);

            var ex = Assert.Throws<ArgumentException>(() => member.PayFine(payment));

            Assert.Equal("Payment must not be negative value", ex.Message);
        }
        public void HasReachedFineLimitReturnsTrueIfFinesReachFineMax()
        {
            var member = new Member("test", "member", "phone", "email", 1);

            // Add a fine.
            const float fine1 = 5.50f;
            const float fine2 = BookConstants.FINE_LIMIT - fine1;
            const float fine3 = fine2 + 1.0f;

            member.AddFine(fine1);

            // Test that Fine Limit is not reached. Assuming FINE_MAX == FINE_LIMIT.
            Assert.True(member.FineAmount < BookConstants.FINE_LIMIT);
            Assert.False(member.HasReachedFineLimit);

            // Add additional fine to reach == FINE_LIMIT.
            member.AddFine(fine2);

            // Test that Loan Limit has been reached.
            Assert.True(member.FineAmount == BookConstants.FINE_LIMIT);
            Assert.True(member.HasReachedFineLimit);

            // Add additional fine to exceed FINE_LIMIT.
            member.AddFine(fine3);
            Assert.True(member.FineAmount > BookConstants.FINE_LIMIT);
            Assert.True(member.HasReachedFineLimit);
        }
        public void HasFinesPayableReturnsTrueIfFinesExceedZero()
        {
            var member = new Member("test", "member", "phone", "email", 1);

            Assert.False(member.HasFinesPayable);

            member.AddFine(5.00f);

            Assert.True(member.HasFinesPayable);
        }
        public void CanPayFineByMember()
        {
            const float fine = 5.50f;
            const float payment = 2.50f;

            var member = new Member("test", "member", "phone", "email", 1);

            member.AddFine(fine);

            Assert.Equal(fine, member.FineAmount);

            member.PayFine(payment);

            Assert.Equal(fine - payment, member.FineAmount);
        }