public void CanGetBorrower()
        {
            var book = Substitute.For<IBook>();
            var borrower = Substitute.For<IMember>();

            var loan = new Loan(book, borrower, DateTime.Today, DateTime.Today.AddDays(1));

            Assert.Equal(borrower, loan.Borrower);
        }
        public void CanCommitLoan()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            var loanId = 1;

            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(1));

            loan.Commit(loanId);
        }
        public void WhenLoanIsCreatedShouldBePending()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today;

            var loan = new Loan(book, member, borrowDate, dueDate);

            Assert.Equal(LoanState.PENDING, loan.State);
        }
        public void CanGetBook()
        {
            var book = new Book("author", "title", "call number", 1);
            var member = new Member("first", "last", "phone", "email", 1);

            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today.AddDays(7);

            var loan = new Loan(book, member, borrowDate, dueDate);

            Assert.Equal(book, loan.Book);
        }
        public void AddLoanThrowsInvalidOperationExceptionIfMemberIsNotAllowedToBorrow()
        {
            var book = new Book("author", "title", "call number", 1);

            // Set member to BORROWING_DISALLOWED
            var member = new Member("first", "last", "phone", "email", 1) { State = MemberState.BORROWING_DISALLOWED };

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

            var ex = Assert.Throws<InvalidOperationException>(() => member.AddLoan(loan));

            Assert.Equal("Cannot add a loan when member is not allowed to borrow", ex.Message);
        }
        public void CanCompleteLoan()
        {
            var book = Substitute.For<IBook>();
            var borrower = Substitute.For<IMember>();

            var loan = new Loan(book, borrower, DateTime.Today, DateTime.Today.AddDays(1));

            loan.Commit(1);

            loan.Complete();

            Assert.Equal(LoanState.COMPLETE, loan.State);
        }
        public void CanAddLoanToMember()
        {
            var book = new Book("author", "title", "call number", 1);

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

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

            member.AddLoan(loan);

            Assert.Contains(loan, member.Loans);
        }
        public void CanCommitLoan()
        {
            var book = new Book("author", "title", "call number", 1);
            var member = new Member("first", "last", "phone", "email", 1);

            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today.AddDays(7);
            var loanId = 1;

            var loan = new Loan(book, member, borrowDate, dueDate);

            loan.Commit(loanId);
        }
        public void BorrowBookThrowsRuntimeExceptionIfBookIsNotCurrentlyAvailable()
        {
            // Set book state to something other than Available.
            var book = new Book("author", "title", "call number", 1) { State = BookState.LOST };
            var member = new Member("first", "last", "phone", "email", 1);

            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7));

            // Associate the book with the loan.
            var ex = Assert.Throws<InvalidOperationException>(() => book.Borrow(loan));

            Assert.Equal("Cannot borrow a book that is not available", ex.Message);
        }
        public void CanCreateLoan()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today;

            // Jim has stated that the initial spec is incorrect and it should not take an ID, but should return a default ID of 0.
            var loan = new Loan(book, member, borrowDate, dueDate);

            Assert.NotNull(loan);

            // By new rule, assert ID = 0.
            Assert.Equal(0, loan.ID);
        }
        public void CanBorrowBook()
        {
            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));

            // Associate the book with the loan.
            book.Borrow(loan);

            // Set book state to ON_LOAN - affected by GetLoanFromBookReturnsNullIfBookIsNotON_LOAN()
            book.State = BookState.ON_LOAN;

            Assert.Equal(loan, book.Loan);
        }
        public void CanCreateLoan()
        {
            var book = new Book("author", "title", "call number", 1);
            var member = new Member("first", "last", "phone", "email", 1);

            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today.AddDays(7);

            // Jim has stated that the initial spec is incorrect and it should not take an ID, but should return a default ID of 0.
            var loan = new Loan(book, member, borrowDate, dueDate);

            Assert.NotNull(loan);

            // By new rule, assert ID = 0.
            Assert.Equal(0, loan.ID);
        }
        public void WhenLoanIsCurrentAndOverdueShouldBeOverdue()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today.AddDays(7);

            var loan = new Loan(book, member, borrowDate, dueDate);

            loan.Commit(1);

            Assert.Equal(LoanState.CURRENT, loan.State);

            loan.CheckOverDue(DateTime.Today.AddDays(14));

            Assert.Equal(LoanState.OVERDUE, loan.State);
        }
        public void WhenLoanIsCurrentAndCompletedShouldBeComplete()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today.AddDays(7);

            var loan = new Loan(book, member, borrowDate, dueDate);

            loan.Commit(1);

            Assert.Equal(LoanState.CURRENT, loan.State);

            loan.Complete();

            Assert.Equal(LoanState.COMPLETE, loan.State);
        }
        public void CanRemoveLoanFromMember()
        {
            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(14)) { State = LoanState.CURRENT };

            member.AddLoan(loan);

            // Make sure Member has Loan.
            Assert.Contains(loan, member.Loans);

            member.RemoveLoan(loan);

            // Make sure Loan has been removed from Member.
            Assert.DoesNotContain(loan, member.Loans);
        }
        public void CanGetLoans()
        {
            var book = new Book("author", "title", "call number", 1);

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

            var loan1 = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(14)) { State = LoanState.CURRENT };
            var loan2 = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(14)) { State = LoanState.CURRENT };
            var loan3 = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(14)) { State = LoanState.CURRENT };
            var loan4 = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(14)) { State = LoanState.CURRENT };

            member.AddLoan(loan1);
            member.AddLoan(loan2);
            member.AddLoan(loan3);

            Assert.Equal(3, member.Loans.Count());
            Assert.Contains(loan1, member.Loans);
            Assert.DoesNotContain(loan4, member.Loans);
        }
        public void CheckOverDueSetsLoanStateToOverdue()
        {
            var book = Substitute.For<IBook>();
            var borrower = Substitute.For<IMember>();

            // Set DueDate to the past so we can check it is < Today.
            var dueDate = DateTime.Today.AddMonths(-1).AddDays(1);

            var loan = new Loan(book, borrower, DateTime.Today.AddMonths(-1), dueDate);

            // Set loan state to current so it clears next test (Must be Current or Overdue).
            loan.State = LoanState.CURRENT;

            Assert.True(dueDate < DateTime.Today);

            // Check if it is overdue as of Today.
            var result = loan.CheckOverDue(DateTime.Today);

            // Make sure the check set the loan state to overdue.
            Assert.Equal(LoanState.OVERDUE, loan.State);
            Assert.True(result);
        }
        public void LoanCtorThrowsIllegalParameterException()
        {
            var book = Substitute.For<IBook>();
            var member = Substitute.For<IMember>();
            DateTime borrowDate = DateTime.Today;
            DateTime dueDate = DateTime.Today;

            var ex = Assert.Throws<ArgumentException>(() =>
            {
                var loan = new Loan(null, member, borrowDate, dueDate);
            });

            Assert.Equal("Book needs to be provided", ex.Message);

            ex = Assert.Throws<ArgumentException>(() =>
            {
                new Loan(book, null, borrowDate, dueDate);
            });

            Assert.Equal("Member needs to be provided", ex.Message);

            ex = Assert.Throws<ArgumentException>(() =>
            {
                // DateTime can't be null in .NET
                new Loan(book, member, DateTime.MinValue, dueDate);
            });

            Assert.Equal("Borrow date needs to be provided", ex.Message);

            ex = Assert.Throws<ArgumentException>(() =>
            {
                // DateTime can't be null in .NET
                new Loan(book, member, borrowDate, DateTime.MinValue);
            });

            Assert.Equal("Due date needs to be provided", ex.Message);

            ex = Assert.Throws<ArgumentException>(() =>
            {
                // DateTime can't be null in .NET
                new Loan(book, member, borrowDate, borrowDate.AddDays(-1));
            });

            Assert.Equal("Due date cannot be before Borrow date", ex.Message);
        }
        public void WhenBorrowingDisallowedAndLoanRemovedButHasOverdueLoanBorrowingDisallowed()
        {
            var book = new Book("author", "title", "call number", 1);

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

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

            member.AddLoan(overdue);

            // Set it to overdue
            overdue.CheckOverDue(DateTime.Today.AddMonths(1));

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

                member.AddLoan(loan);
            }

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

            // Remove the first one that isn't the overdue mock.
            member.RemoveLoan(member.Loans.First(l => l != overdue));

            Assert.Equal(MemberState.BORROWING_DISALLOWED, member.State);
        }
        public void WhenBorrowingDisallowedAndLoanRemovedBorrowingAllowed()
        {
            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);
            }

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

            member.RemoveLoan(member.Loans[0]);

            Assert.Equal(MemberState.BORROWING_ALLOWED, 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 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 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 WhenBorrowingAllowedAndRemovingLoanBorrowingAllowed()
        {
            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(14)) { State = LoanState.CURRENT };

            member.AddLoan(loan);

            Assert.False(member.HasReachedLoanLimit);

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

            member.RemoveLoan(loan);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);
        }
        public void WhenBorrowingAllowedAndNoOverdueLoansBorrowingAllowed()
        {
            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(14)) { State = LoanState.CURRENT };

            member.AddLoan(loan);

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

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

            Assert.False(member.HasOverDueLoans);

            Assert.Equal(MemberState.BORROWING_ALLOWED, member.State);
        }
        public void ReturnLoanReadable()
        {
            var book = Substitute.For<Book>("Jim Tulip", "Adventures in Programming", "call number", 1);
            var member = Substitute.For<Member>("Jim", "Tulip", "Phone", "Email", 1);

            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(1));

            var readable =
                $"Loan ID:\t\t{loan.ID}\nAuthor:\t\t{loan.Book.Author}\nTitle:\t\t{loan.Book.Title}\nBorrower:\t{loan.Borrower.ToString()}\nBorrow Date:\t{loan.BorrowDate.ToShortDateString()}\nDue Date:\t{loan.DueDate.ToShortDateString()}";
            Assert.Equal(readable, loan.ToString());
        }
        public void RemoveLoanThrowsArgumentExceptionIfLoanIsNotInCollection()
        {
            var book = new Book("author", "title", "call number", 1);

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

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

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

            member.AddLoan(loan1);

            var ex = Assert.Throws<ArgumentException>(() => member.RemoveLoan(loan2));

            Assert.Equal("Loan was not found in member's loans", ex.Message);
        }
        public void HasReachedLoanLimitReturnsTrueIfLoanCountEqualsLoanLimit()
        {
            var book = new Book("author", "title", "call number", 1);

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

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

            member.AddLoan(loan);

            // Test that Loan Limit is not reached.
            Assert.True(member.Loans.Count() < BookConstants.LOAN_LIMIT);
            Assert.False(member.HasReachedLoanLimit);

            // Add additional loans.
            while (member.Loans.Count() < BookConstants.LOAN_LIMIT)
            {
                member.AddLoan(new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7)));
            }

            // Test that Loan Limit has been reached.
            Assert.True(member.Loans.Count() == BookConstants.LOAN_LIMIT);
            Assert.True(member.HasReachedLoanLimit);
        }
        public void HasOverdueLoansReturnsFalseIfNoLoanIsOverdue()
        {
            var book = new Book("author", "title", "call number", 1);

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

            // Add a single loan that is not overdue.
            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7));

            member.Loans.Add(loan);

            Assert.False(member.HasOverDueLoans);
        }
        public void HasOverdueLoansReturnsTrueIfAnyLoanIsOverdue()
        {
            var book = new Book("author", "title", "call number", 1);

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

            // Add a single loan that is not overdue.
            var loan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(14)) { State = LoanState.CURRENT };

            member.AddLoan(loan);

            // Add a second loan that is overdue.
            var secondLoan = new Loan(book, member, DateTime.Today, DateTime.Today.AddDays(7)) { State = LoanState.CURRENT };

            member.AddLoan(secondLoan);

            // Check if overdue

            foreach (var l in member.Loans)
            {
                l.CheckOverDue(DateTime.Today.AddDays(10));
            }

            Assert.True(member.HasOverDueLoans);
        }