/// <summary>
 /// Initializes a new instance of the <see cref="BasicTicketService"> class.
 /// </summary>
 /// <param name="venue">The venue.</param>
 /// <param name="maxHoldDuration">The maximum duration for which seat holds are valid.</param>
 /// <param name="reservationCodeLength">The length of the reservation codes. Defaults to 8.</param>
 /// <param name="getNow">A function which can mock the current DateTime. Defaults to DateTime.UtcNow; should only be set for unit tests.</param>
 public BasicTicketService(BasicVenue venue, double maxHoldDuration, int reservationCodeLength = 8, Func <bool, DateTime> getNow = null)
 {
     this.Venue = venue;
     this.firstRowWithAvailableSeats = venue.Rows[0];
     this.maxHoldDuration            = maxHoldDuration;
     this.reservationCodeLength      = reservationCodeLength;
     this.getNow = getNow ?? (x => DateTime.UtcNow);
 }
        public void FindAndHoldSeats_RequestingFewerThanOneSeat_ShouldThrowException(int numSeats)
        {
            // Arrange
            BasicVenue     singleSeatVenue = new BasicVenue(1, 1);
            ITicketService ticketService   = new BasicTicketService(singleSeatVenue, TestData.HourHoldDuration);

            // Act
            ticketService.FindAndHoldSeats(numSeats, TestData.TestCustomerEmail);
        }
        public void FindAndHoldSeats_RequestingMoreSeatsThanAvailable_ShouldThrowException()
        {
            // Arrange
            BasicVenue     singleSeatVenue = new BasicVenue(1, 1);
            ITicketService ticketService   = new BasicTicketService(singleSeatVenue, TestData.HourHoldDuration);

            // Act
            ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
        }
        public void ReserveSeats_NoHeldSeats_ShouldThrowException()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            ticketService.ReserveSeats(1, TestData.TestCustomerEmail);
        }
        public void FindAndHoldSeats_SecondTimeWithNotEnoughSeats_ShouldThrowException()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(2, 2);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            ticketService.FindAndHoldSeats(3, TestData.TestCustomerEmail);
            ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
        }
        public void ReserveSeats_WithDifferentEmail_ShouldThrowException()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            ticketService.ReserveSeats(seatHold.Id, TestData.SecondTestCustomerEmail);
        }
        public void ReserveSeats_ExpiredSeatHold_ShouldThrowException()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.NegativeHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            ticketService.ReserveSeats(seatHold.Id, TestData.TestCustomerEmail);
        }
        public void NumSeatsAvailable_NoHeldSeats_ShouldReturnTotalVenueCapacity()
        {
            // Arrange
            BasicVenue     singleSeatVenue = new BasicVenue(1, 1);
            ITicketService ticketService   = new BasicTicketService(singleSeatVenue, TestData.HourHoldDuration);

            // Act
            int actualNumSeatsAvailable = ticketService.NumSeatsAvailable();

            // Assert
            Assert.AreEqual(1, actualNumSeatsAvailable);
        }
        public void FindAndHoldSeats_RequestingOneSeat_ShouldReturnOneSeat()
        {
            // Arrange
            BasicVenue     singleSeatVenue = new BasicVenue(1, 1);
            ITicketService ticketService   = new BasicTicketService(singleSeatVenue, TestData.HourHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(1, seatHold.Seats.Count);
        }
        public void NumSeatsAvailable_AfterHoldingAllSeats_ShouldReturnNoAvailableSeats()
        {
            // Arrange
            BasicVenue     oneRowFiveSeatsVenue = new BasicVenue(1, 5);
            ITicketService ticketService        = new BasicTicketService(oneRowFiveSeatsVenue, TestData.HourHoldDuration);

            // Act
            ticketService.FindAndHoldSeats(5, TestData.TestCustomerEmail);
            int actualNumSeatsAvailable = ticketService.NumSeatsAvailable();

            // Assert
            Assert.AreEqual(0, actualNumSeatsAvailable);
        }
        public void NumSeatsAvailable_AfterReleasingHold_ShouldIncrementAvailableSeats()
        {
            // Arrange
            BasicVenue     singleSeatVenue = new BasicVenue(1, 1);
            ITicketService ticketService   = new BasicTicketService(singleSeatVenue, TestData.NegativeHoldDuration);

            // Act
            ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            int actualNumSeatsAvailable = ticketService.NumSeatsAvailable();

            // Assert
            Assert.AreEqual(1, actualNumSeatsAvailable, $"The seat should be released when NumSeatsAvailable is called.");
        }
        public void ReserveSeats_ValidSeatHold_ShouldReserveSeats()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration, 8);

            // Act
            SeatHold seatHold        = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            string   reservationCode = ticketService.ReserveSeats(seatHold.Id, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(8, reservationCode.Length);
        }
        public void FindAndHoldSeats_WhenReservationSizeLargerThanRowSize_ShouldSplitGroup()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(4, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(0, seatHold.Seats[0].RowNumber);
            Assert.AreEqual(0, seatHold.Seats[2].RowNumber);
            Assert.AreEqual(1, seatHold.Seats[3].RowNumber);
        }
        public void FindAndHoldSeats_RequestingThreeSeats_ShouldReturnThreeAdjacentSeats()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(5, 5);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(5, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(0, seatHold.Seats[0].SeatNumber);
            Assert.AreEqual(1, seatHold.Seats[1].SeatNumber);
            Assert.AreEqual(2, seatHold.Seats[2].SeatNumber);
        }
        public void FindAndHoldSeats_FirstHoldReleased_ShouldGiveSecondHoldSameSeats()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.NegativeHoldDuration);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(3, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(3, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(0, secondSeatHold.Seats[0].RowNumber);
            Assert.AreEqual(0, secondSeatHold.Seats[1].RowNumber);
            Assert.AreEqual(0, secondSeatHold.Seats[2].RowNumber);
        }
        public void FindAndHoldSeats_ThreeSeatHolds_ShouldHaveIncreasingSeatIds()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            SeatHold thirdSeatHold  = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            // Assert
            Assert.IsTrue(firstSeatHold.Id < secondSeatHold.Id);
            Assert.IsTrue(secondSeatHold.Id < thirdSeatHold.Id);
        }
        public void ReserveSeats_TwoReservations_ShouldHaveDifferentReservationCodes()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            string firstReservationCode  = ticketService.ReserveSeats(firstSeatHold.Id, TestData.TestCustomerEmail);
            string secondReservationCode = ticketService.ReserveSeats(secondSeatHold.Id, TestData.TestCustomerEmail);

            // Assert
            Assert.AreNotEqual(firstReservationCode, secondReservationCode, "Reservation codes should never be the same.");
        }
        public void FindAndHoldSeats_WhenInsufficientAvailableSeatsInCloserRow_ShouldHoldSeatsInHigherRow()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(3, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(0, firstSeatHold.Seats[0].RowNumber);
            Assert.AreEqual(0, firstSeatHold.Seats[1].RowNumber);

            Assert.AreEqual(1, secondSeatHold.Seats[0].RowNumber);
            Assert.AreEqual(1, secondSeatHold.Seats[1].RowNumber);
        }
        public void NumSeatsAvailable_AfterReservingSeatHold_ShouldReturnSameNumberOfAvailableSeats()
        {
            // Arrange
            BasicVenue     oneRowFiveSeatsVenue = new BasicVenue(1, 5);
            ITicketService ticketService        = new BasicTicketService(oneRowFiveSeatsVenue, TestData.HourHoldDuration);

            // Act
            SeatHold seatHold = ticketService.FindAndHoldSeats(3, TestData.TestCustomerEmail);
            int      numSeatsAvailableAfterHold = ticketService.NumSeatsAvailable();

            ticketService.ReserveSeats(seatHold.Id, TestData.TestCustomerEmail);
            int numSeatsAvailableAfterReservation = ticketService.NumSeatsAvailable();

            // Assert
            Assert.AreEqual(2, numSeatsAvailableAfterHold);
            Assert.AreEqual(2, numSeatsAvailableAfterReservation);
        }
        public void FindAndHoldSeats_WhenReservationSizeLargerThanAvailableSeatsInEachRow_ShouldSplitGroup()
        {
            // Arrange
            BasicVenue     venue         = new BasicVenue(2, 3);
            ITicketService ticketService = new BasicTicketService(venue, TestData.HourHoldDuration);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
            SeatHold thirdSeatHold  = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);

            // Assert
            Assert.AreEqual(0, thirdSeatHold.Seats[0].RowNumber);
            Assert.AreEqual(2, thirdSeatHold.Seats[0].SeatNumber);
            Assert.AreEqual(1, thirdSeatHold.Seats[1].RowNumber);
            Assert.AreEqual(2, thirdSeatHold.Seats[1].SeatNumber);
        }
        public void FindAndHoldSeats_FirstHoldExpiresWhileSecondStillValid_ShouldGiveLaterHoldsFirstHoldsSeats()
        {
            // Arrange
            BasicVenue venue = new BasicVenue(3, 3);
            // To mock DateTime.UtcNow, make it so if there are an even number of seats in the seat hold and there are an
            // even number of seat holds, it will expire immediately. Otherwise it will never expire.
            Func <bool, DateTime> dateTimeFunc  = (b => b ? DateTime.MaxValue : DateTime.MinValue);
            ITicketService        ticketService = new BasicTicketService(venue, TestData.HourHoldDuration, getNow: dateTimeFunc);

            // Act
            SeatHold firstSeatHold  = ticketService.FindAndHoldSeats(2, TestData.TestCustomerEmail);
            SeatHold secondSeatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            SeatHold thirdSeatHold  = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);
            SeatHold fourthSeatHold = ticketService.FindAndHoldSeats(1, TestData.TestCustomerEmail);

            // Assert
            Assert.IsFalse(secondSeatHold.Expired);
            Assert.AreEqual(0, thirdSeatHold.Seats[0].SeatNumber);
            Assert.AreEqual(0, thirdSeatHold.Seats[0].RowNumber);
            Assert.AreEqual(1, fourthSeatHold.Seats[0].SeatNumber);
            Assert.AreEqual(0, fourthSeatHold.Seats[0].RowNumber);
        }