public void BrowseQuotes_WhenCall_ReturnExpected()
        {
            //Arrange
            var expectedDepartDate       = "2020-08-01";
            var expectedInboundIataCode  = "JFK";
            var expectedOutboundIataCode = "SFO";
            var expectedNumberOfStops    = "1 stop";
            var expectedAirlineName      = "Alaska Airlines";
            var expectedTripTotalPrice   = "$139";
            var expectedSource           = "Skyscanner";
            var expectedBookingBaseUrl   = "https://www.kayak.com/flights";
            var expectedBookingUrl       = $"{expectedBookingBaseUrl}/{expectedOutboundIataCode}/{expectedInboundIataCode}/{expectedDepartDate}/";

            IFlightRequest request = new FlightRequest()
            {
                DepartDate = expectedDepartDate, Destination = expectedInboundIataCode, Origin = expectedOutboundIataCode
            };
            SkyscannerBrowseQuoteResponse expectedResponse = GetAlaskaFlight();

            MockISkyscannerLoader.Setup(_ => _.BrowseQuotesAsync(request)).Returns(Task.FromResult(expectedResponse));
            MockISkyscannerLoader.Setup(_ => _.GetBaseBookingUrl()).Returns(expectedBookingBaseUrl);


            // Act
            var skyscannerQuoteReader = new SkyscannerResponseReader();
            Task <List <IFlightResponse> > taskResponse = skyscannerQuoteReader.BrowseQuotesAsync(request);

            taskResponse.Wait();

            List <IFlightResponse> actualResponses = taskResponse.Result;

            var expectedItineraries = 1; // 1 quote, and 1 Outbound, 0 Inbound
            var actualItineraries   = actualResponses[0].FlightItineraries;
            var actualResponse      = actualResponses[0];

            //Assert
            Assert.IsNotNull(actualResponse);
            Assert.AreEqual(expectedResponse.Quotes.Length, actualResponses.Count);
            Assert.AreEqual(expectedSource, actualResponse.QuoteSource);
            Assert.AreEqual(expectedTripTotalPrice, actualResponse.TripTotalPrice);
            Assert.AreEqual(expectedBookingUrl, actualResponse.BookingLink);
            Assert.AreEqual(expectedItineraries, actualItineraries.Count);
            Assert.AreEqual(expectedAirlineName, actualItineraries[0].AirlineName);
            Assert.AreEqual(expectedInboundIataCode, actualItineraries[0].InboundIataCode);
            Assert.AreEqual(expectedOutboundIataCode, actualItineraries[0].OutboundIataCode);
            Assert.AreEqual(expectedNumberOfStops, actualItineraries[0].NumberOfStops);
        }
        private static IFlightItinerary GetItinerary(SkyscannerBrowseQuoteResponse skyscannerBrowseResponse, ISkyscannerItinerary itinerary)
        {
            if (itinerary == null)
            {
                return(null);
            }
            var stops           = itinerary.CarrierIds?.Length ?? 0;
            var flightItinerary = new FlightItinerary
            {
                NumberOfStops    = GetFlightItineraryNumberOfStops(stops),
                OutboundIataCode = GetOutboundIataCode(skyscannerBrowseResponse, itinerary),
                InboundIataCode  = GetInboundIataCode(skyscannerBrowseResponse, itinerary)
            };

            foreach (var carrier in skyscannerBrowseResponse.Carriers.Where(_ => itinerary.CarrierIds.Contains(_.CarrierId)))
            {
                flightItinerary.AirlineName += carrier.Name;
            }

            return(flightItinerary);
        }
        /// <summary>
        /// Browse for flights quotes from skyscanner Api
        /// </summary>
        /// <param name="request">An user flight request</param>
        /// <returns></returns>
        public async Task <List <IFlightResponse> > BrowseQuotesAsync(IFlightRequest request)
        {
            var flightResponses = new List <IFlightResponse>();

            try
            {
                //load flights from skyscanner api
                SkyscannerBrowseQuoteResponse response = await Loader.BrowseQuotesAsync(request);

                //parse flight response to the model shown to the user
                flightResponses.AddRange(response.Quotes.Select(quote => ParseResponse(request, response, quote)));
            }
            catch (Exception ex)
            {
                //log exception
                Logger.Error($"{ex.Message}|{ex.InnerException}");
            }

            //return flight response for one-was or round trip.
            return(flightResponses);
        }
        public void BrowseQuotes_WhenCallNotQuotesFound_ReturnEmptyList()
        {
            // Arrange
            IFlightRequest request  = new FlightRequest();
            var            response = new SkyscannerBrowseQuoteResponse()
            {
                Quotes = new Quote[] { }
            };

            MockISkyscannerLoader.Setup(_ => _.BrowseQuotesAsync(request)).Returns(Task.FromResult(response));

            // Act
            var skyscannerQuoteReader = new SkyscannerResponseReader();
            Task <List <IFlightResponse> > taskResponse = skyscannerQuoteReader.BrowseQuotesAsync(request);

            taskResponse.Wait();

            var actualResponse = taskResponse.Result;

            // Assert
            Assert.IsNotNull(actualResponse);
            Assert.AreEqual(actualResponse.Count, 0);
            MockILog.Verify(_ => _.Error(It.IsAny <string>()), Times.Never);
        }
        private static IFlightResponse ParseResponse(IFlightRequest modelQuoteRequest, SkyscannerBrowseQuoteResponse response,
                                                     Quote quote)
        {
            IFlightItinerary outboundItinerary = GetItinerary(response, quote.OutboundLeg);
            IFlightItinerary inboundItinerary  = GetItinerary(response, quote.InboundLeg);

            var flightItineraries = new List <IFlightItinerary>();

            if (inboundItinerary != null)
            {
                flightItineraries.Add(inboundItinerary);
            }
            if (outboundItinerary != null)
            {
                flightItineraries.Add(outboundItinerary);
            }

            IFlightResponse aFlightResponse = new FlightResponse()
            {
                QuoteSource       = "Skyscanner",
                TripTotalPrice    = TryGetCost(quote.MinPrice) ?? quote.MinPrice,
                BookingLink       = GetBookingLink(modelQuoteRequest),
                FlightItineraries = flightItineraries
            };

            return(aFlightResponse);
        }
 private static string GetOutboundIataCode(SkyscannerBrowseQuoteResponse skyscannerBrowseResponse, ISkyscannerItinerary itinerary)
 {
     return(skyscannerBrowseResponse.Places.First(_ => _.PlaceId == itinerary.OriginId).IataCode);
 }