From 5692d9ad61729cbde61d0c7cd11dc0234a1f2532 Mon Sep 17 00:00:00 2001 From: Krzysztof Naglik Date: Sun, 23 Jul 2023 15:22:42 +0200 Subject: [PATCH] Add ability to pass many locations to GetPriceGraph (#11) --- .github/workflows/ci.yaml | 18 +++++++ examples/example1/main.go | 6 ++- examples/example2/main.go | 12 +++-- flights/flight.go | 73 +++++++++++++++++--------- flights/flight_test.go | 22 ++++---- flights/price_graph.go | 89 +++++++++++++++++++------------- flights/price_graph_test.go | 100 +++++++++++++++++++++++++++++------- flights/types.go | 25 +++++++++ flights/url.go | 25 --------- flights/utils.go | 10 ++-- 10 files changed, 255 insertions(+), 125 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f8a8a7b..3b93159 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,3 +24,21 @@ jobs: - name: Run unit tests run: | go test ./... -v + + examples: + name: Run examples + runs-on: ubuntu-22.04 + steps: + - name: Set up toolchain + uses: actions/setup-go@v3 + with: + go-version: 1.20.1 + id: go + + - name: Check out repository code + uses: actions/checkout@v3 + + - name: Run unit tests + run: | + go run ./examples/example1/main.go + go run ./examples/example2/main.go diff --git a/examples/example1/main.go b/examples/example1/main.go index 2a2436f..d32c612 100644 --- a/examples/example1/main.go +++ b/examples/example1/main.go @@ -15,7 +15,11 @@ func getCheapOffers(rangeStartDate, rangeEndDate time.Time, tripLength int, srcC for _, s := range srcCities { for _, d := range dstCities { - offers, err := session.GetPriceGraph(rangeStartDate, rangeEndDate, tripLength, s, d, currency.PLN, lang) + offers, err := session.GetPriceGraph( + rangeStartDate, rangeEndDate, + []string{s}, []string{}, []string{d}, []string{}, + 1, currency.PLN, flights.AnyStops, flights.Economy, flights.RoundTrip, + lang, tripLength) if err != nil { log.Fatal(err) } diff --git a/examples/example2/main.go b/examples/example2/main.go index 4913547..e057213 100644 --- a/examples/example2/main.go +++ b/examples/example2/main.go @@ -10,11 +10,15 @@ import ( "golang.org/x/text/language" ) -func getBestOffer(rangeStartDate, rangeEndDate time.Time, tripLength int, srcCities, dstCities string, lang language.Tag) { +func getBestOffer(rangeStartDate, rangeEndDate time.Time, tripLength int, srcCity, dstCity string, lang language.Tag) { session := flights.New() var bestOffer flights.Offer - offers, err := session.GetPriceGraph(rangeStartDate, rangeEndDate, tripLength, srcCities, dstCities, currency.PLN, lang) + offers, err := session.GetPriceGraph( + rangeStartDate, rangeEndDate, + []string{srcCity}, []string{}, []string{dstCity}, []string{}, + 1, currency.PLN, flights.AnyStops, flights.Economy, flights.RoundTrip, + lang, tripLength) if err != nil { log.Fatal(err) } @@ -30,9 +34,9 @@ func getBestOffer(rangeStartDate, rangeEndDate time.Time, tripLength int, srcCit url, err := session.SerializeUrl( bestOffer.StartDate, bestOffer.ReturnDate, - []string{srcCities}, + []string{srcCity}, []string{}, - []string{dstCities}, + []string{dstCity}, []string{}, 1, currency.PLN, diff --git a/flights/flight.go b/flights/flight.go index d62e9c6..f5664aa 100644 --- a/flights/flight.go +++ b/flights/flight.go @@ -65,7 +65,7 @@ func serializeFlightClass(class Class) string { return "4" } -func (s *Session) getFlightRawData( +func (s *Session) getRawData( date, returnDate time.Time, srcCities, srcAirports, dstCities, dstAirports []string, adults int, @@ -92,10 +92,7 @@ func (s *Session) getFlightRawData( serClass := serializeFlightClass(class) serTripType := serializeTripType(tripType) - prefix := `[null,"[[],` - suffix := `],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` - - rawData := prefix + rawData := "" rawData += fmt.Sprintf(`[null,null,%d,null,[],%s,%s,null,null,null,null,null,null,[`, serTripType, serClass, serAdults) @@ -108,23 +105,48 @@ func (s *Session) getFlightRawData( serDsts, serSrcs, serStops, serReturnDate) } - rawData += suffix + return rawData, nil +} + +func (s *Session) getFlightReqData( + date, returnDate time.Time, + srcCities, srcAirports, dstCities, dstAirports []string, + adults int, + stops Stops, + class Class, + tripType TripType, + lang language.Tag, +) (string, error) { + rawData, err := s.getRawData( + date, returnDate, + srcCities, srcAirports, dstCities, dstAirports, + adults, stops, class, tripType, lang) + if err != nil { + return "", nil + } + + prefix := `[null,"[[],` + suffix := `],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` + + reqData := prefix + reqData += rawData + reqData += suffix - return url.QueryEscape(rawData), nil + return url.QueryEscape(reqData), nil } func getPrice(tripObj []interface{}) (float64, error) { - priceObj1, ok := tripObj[1].([]interface{}) + priceObj1, ok := getElement[[]interface{}](tripObj, 1) if !ok { - return 0, fmt.Errorf("wrong price format stage 1: %v", priceObj1[1]) + return 0, fmt.Errorf("wrong price format stage 1: %v", priceObj1) } - priceObj2, ok := priceObj1[0].([]interface{}) + priceObj2, ok := getElement[[]interface{}](priceObj1, 0) if !ok { - return 0, fmt.Errorf("wrong price format stage 2: %v", priceObj2[0]) + return 0, fmt.Errorf("wrong price format stage 2: %v", priceObj2) } - price, ok := priceObj2[1].(float64) + price, ok := getElement[float64](priceObj2, 1) if !ok { - return 0, fmt.Errorf("wrong price format stage 3: %v", priceObj2[1]) + return 0, fmt.Errorf("wrong price format stage 3: %v", priceObj2) } return price, nil } @@ -182,7 +204,7 @@ func getTime(flightTime interface{}, flightDate interface{}) (time.Time, error) } func getDuration(duration []interface{}) (time.Duration, error) { - duration1 := getElement[float64](duration, 11) + duration1, _ := getElement[float64](duration, 11) return time.ParseDuration(fmt.Sprintf("%dm", int(duration1))) } @@ -191,15 +213,15 @@ func getFlightNumberAirline(data interface{}) (string, interface{}, string, erro if !ok || len(data1) != 4 { return "", "", "", fmt.Errorf("wrong flight number of airline type: %v", data) } - flightNumberPart1 := getElement[string](data1, 0) + flightNumberPart1, _ := getElement[string](data1, 0) // if !ok { // return "", "", "", fmt.Errorf("wrong flight number part 1 type: %v", data1[0]) // } - flightNumberPart2 := getElement[string](data1, 1) + flightNumberPart2, _ := getElement[string](data1, 1) // if !ok { // return "", "", "", fmt.Errorf("wrong flight number part 2 type: %v", data1[1]) // } - airline := getElement[string](data1, 3) + airline, _ := getElement[string](data1, 3) // if !ok { // return "", "", "", fmt.Errorf("wrong airline name type: %v", data1[3]) // } @@ -237,19 +259,19 @@ func getFlight(flightObj interface{}) (flight, error) { return flight{}, fmt.Errorf("wrong flight format: %v", flightObj) } - departureAirportCode := getElement[string](flightObj1, 3) + departureAirportCode, _ := getElement[string](flightObj1, 3) // if !ok { // return flightV2{}, fmt.Errorf("wrong departure airport code type: %v", object1[3]) // } - departureAirportName := getElement[string](flightObj1, 4) + departureAirportName, _ := getElement[string](flightObj1, 4) // if !ok { // return flightV2{}, fmt.Errorf("wrong departure airport name type: %v", object1[4]) // } - arrivalAirportName := getElement[string](flightObj1, 5) + arrivalAirportName, _ := getElement[string](flightObj1, 5) // if !ok { // return flightV2{}, fmt.Errorf("wrong arrival airport name type: %v", object1[5]) // } - arrivalAirportCode := getElement[string](flightObj1, 6) + arrivalAirportCode, _ := getElement[string](flightObj1, 6) // if !ok { // return flightV2{}, fmt.Errorf("wrong arrival airport code type: %v", object1[6]) // } @@ -270,11 +292,11 @@ func getFlight(flightObj interface{}) (flight, error) { // if err != nil { // return flightV2{}, err // } - airplane := getElement[string](flightObj1, 17) + airplane, _ := getElement[string](flightObj1, 17) // if !ok { // return flightV2{}, fmt.Errorf("wrong airplane format: %v", object1[17]) // } - legroom := getElement[string](flightObj1, 30) + legroom, _ := getElement[string](flightObj1, 30) us := getUnknowns(flightObj1) unknowns = append(unknowns, us...) return flight{ @@ -368,7 +390,7 @@ func (s *Session) doRequestFlights( ) (*http.Response, error) { url := "https://www.google.com/_/TravelFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetShoppingResults?f.sid=-1300922759171628473&bl=boq_travel-frontend-ui_20230627.02_p1&hl=en&soc-app=162&soc-platform=1&soc-device=1&_reqid=52717&rt=c" - rawDate, err := s.getFlightRawData( + reqDate, err := s.getFlightReqData( date, returnDate, srcCities, srcAirports, dstCities, dstAirports, adults, stops, class, tripType, lang) @@ -377,7 +399,8 @@ func (s *Session) doRequestFlights( return nil, err } - jsonBody := []byte(`f.req=` + rawDate + `&at=AAuQa1qjMakasqKYcQeoFJjN7RZ3%3A1687955915303&`) // Add current unix timestamp instead of 1687955915303 + jsonBody := []byte(`f.req=` + reqDate + + `&at=AAuQa1qjMakasqKYcQeoFJjN7RZ3%3A1687955915303&`) // Add current unix timestamp instead of 1687955915303 bodyReader := bytes.NewReader(jsonBody) req, err := http.NewRequest(http.MethodPost, url, bodyReader) diff --git a/flights/flight_test.go b/flights/flight_test.go index a77b55d..6fc49c3 100644 --- a/flights/flight_test.go +++ b/flights/flight_test.go @@ -177,11 +177,11 @@ func TestGetOffers(t *testing.T) { } } -func TestFlightRawData(t *testing.T) { +func TestFlightReqData(t *testing.T) { session := New() - expectedUnescapedQuery1 := `[null,"[[],[null,null,1,null,[],1,[1,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,0,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3],[[[[\"CDG\",0],[\"/m/04jpl\",5]]],[[[\"SFO\",0],[\"/m/030qb3t\",5]]],null,0,[],[],\"2024-01-31\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` - expectedUnescapedQuery2 := `[null,"[[],[null,null,2,null,[],3,[2,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,3,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` + expectedReqData1 := `[null,"[[],[null,null,1,null,[],1,[1,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,0,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3],[[[[\"CDG\",0],[\"/m/04jpl\",5]]],[[[\"SFO\",0],[\"/m/030qb3t\",5]]],null,0,[],[],\"2024-01-31\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` + expectedReqData2 := `[null,"[[],[null,null,2,null,[],3,[2,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,3,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],1,0,0]"]` date, err := time.Parse("2006-01-02", "2024-01-01") if err != nil { @@ -192,7 +192,7 @@ func TestFlightRawData(t *testing.T) { t.Fatalf("Error while creating return date: %v", err) } - rawData1, err := session.getFlightRawData( + _reqData1, err := session.getFlightReqData( date, returnDate, []string{"Los Angeles"}, @@ -208,16 +208,16 @@ func TestFlightRawData(t *testing.T) { t.Fatal(err) } - unescapedQuery1, err := url.QueryUnescape(rawData1) + reqData1, err := url.QueryUnescape(_reqData1) if err != nil { t.Fatal(err) } - if unescapedQuery1 != expectedUnescapedQuery1 { - t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedUnescapedQuery1, unescapedQuery1) + if reqData1 != expectedReqData1 { + t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedReqData1, reqData1) } - rawData2, err := session.getFlightRawData( + _reqData2, err := session.getFlightReqData( date, returnDate, []string{"Los Angeles"}, @@ -233,12 +233,12 @@ func TestFlightRawData(t *testing.T) { t.Fatal(err) } - unescapedQuery2, err := url.QueryUnescape(rawData2) + reqData2, err := url.QueryUnescape(_reqData2) if err != nil { t.Fatal(err) } - if unescapedQuery2 != expectedUnescapedQuery2 { - t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedUnescapedQuery2, unescapedQuery2) + if reqData2 != expectedReqData2 { + t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedReqData2, reqData2) } } diff --git a/flights/price_graph.go b/flights/price_graph.go index bd100df..7180e42 100644 --- a/flights/price_graph.go +++ b/flights/price_graph.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" "net/url" "time" @@ -15,45 +14,59 @@ import ( "golang.org/x/text/language" ) -func (s *Session) reqDataPriceGraph( +func (s *Session) getPriceGraphReqData( rangeStartDate, rangeEndDate time.Time, - tripLength int, - originCity, targetCity string, + srcCities, srcAirports, dstCities, dstAirports []string, + adults int, + stops Stops, + class Class, + tripType TripType, lang language.Tag, -) string { - serializedOriginCity, err := s.AbbrCity(originCity, lang) - if err != nil { - log.Fatalf(err.Error()) - } - serializedTargetCity, err := s.AbbrCity(targetCity, lang) - if err != nil { - log.Fatalf(err.Error()) - } - additionalDate := rangeStartDate.AddDate(0, 0, tripLength).Format("2006-01-02") + tripLength int, +) (string, error) { + additionalDate := rangeStartDate.AddDate(0, 0, tripLength) serializedRangeStartDate := rangeStartDate.Format("2006-01-02") serializedRangeEndDate := rangeEndDate.Format("2006-01-02") - return url.QueryEscape(`[null,"[null,[null,null,1,null,[],1,[1,0,0,0],null,null,null,null,null,null,` + - fmt.Sprintf(`[[[[[\"%s\",4]]],[[[\"%s\",5]]],null,0,[],[],\"%s\",null,[],[],[],null,null,[],3],`, - serializedOriginCity, serializedTargetCity, serializedRangeStartDate) + - fmt.Sprintf(`[[[[\"%s\",5]]],[[[\"%s\",4]]],null,0,[],[],\"%s\",null,[],[],[],null,null,[],3]],`, - serializedTargetCity, serializedOriginCity, additionalDate) + - fmt.Sprintf(`null,null,null,1,null,null,null,null,null,[]],[\"%s\",\"%s\"],null,[%d,%d]]"]`, - serializedRangeStartDate, serializedRangeEndDate, tripLength, tripLength)) + rawData, err := s.getRawData( + rangeStartDate, additionalDate, + srcCities, srcAirports, dstCities, dstAirports, + adults, stops, class, tripType, lang) + if err != nil { + return "", nil + } + + prefix := `[null,"[null,` + suffix := fmt.Sprintf(`],null,null,null,1,null,null,null,null,null,[]],[\"%s\",\"%s\"],null,[%d,%d]]"]`, + serializedRangeStartDate, serializedRangeEndDate, tripLength, tripLength) + + reqData := prefix + reqData += rawData + reqData += suffix + + return url.QueryEscape(reqData), nil } func (s *Session) doRequestPriceGraph( - rangeStartDate time.Time, - rangeEndDate time.Time, - tripLength int, - originCity string, - targetCity string, - currencyUnit currency.Unit, + rangeStartDate, rangeEndDate time.Time, + srcCities, srcAirports, dstCities, dstAirports []string, + adults int, + curr currency.Unit, + stops Stops, + class Class, + tripType TripType, lang language.Tag, + tripLength int, ) (*http.Response, error) { url := "https://www.google.com/_/TravelFrontendUi/data/travel.frontend.flights.FlightsFrontendService/GetCalendarGraph?f.sid=-8920707734915550076&bl=boq_travel-frontend-ui_20230627.07_p1&hl=en&soc-app=162&soc-platform=1&soc-device=1&_reqid=261464&rt=c" - jsonBody := []byte(`f.req=` + s.reqDataPriceGraph(rangeStartDate, rangeEndDate, tripLength, originCity, targetCity, lang) + `&at=AAuQa1oq5qIkgkQ2nG9vQZFTgSME%3A1688396662350&`) // Add current unix timestamp instead of 1687955915303 + reqDate, err := s.getPriceGraphReqData( + rangeStartDate, rangeEndDate, + srcCities, srcAirports, dstCities, dstAirports, + adults, stops, class, tripType, lang, tripLength) + + jsonBody := []byte(`f.req=` + reqDate + + `&at=AAuQa1oq5qIkgkQ2nG9vQZFTgSME%3A1688396662350&`) // Add current unix timestamp instead of 1687955915303 req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(jsonBody)) if err != nil { @@ -132,20 +145,26 @@ func checkRangeDate(rangeStartDate time.Time, rangeEndDate time.Time) error { } func (s *Session) GetPriceGraph( - rangeStartDate time.Time, - rangeEndDate time.Time, - tripLength int, - originCity string, - targetCity string, - currencyUnit currency.Unit, + rangeStartDate, rangeEndDate time.Time, + srcCities, srcAirports, dstCities, dstAirports []string, + adults int, + curr currency.Unit, + stops Stops, + class Class, + tripType TripType, lang language.Tag, + tripLength int, ) ([]Offer, error) { if err := checkRangeDate(rangeStartDate, rangeEndDate); err != nil { return nil, err } offers := []Offer{} - resp, err := s.doRequestPriceGraph(rangeStartDate, rangeEndDate, tripLength, originCity, targetCity, currencyUnit, lang) + resp, err := s.doRequestPriceGraph( + rangeStartDate, rangeEndDate, + srcCities, srcAirports, dstCities, dstAirports, + adults, curr, stops, class, tripType, lang, + tripLength) if err != nil { return nil, err } diff --git a/flights/price_graph_test.go b/flights/price_graph_test.go index 68f0251..49cd58f 100644 --- a/flights/price_graph_test.go +++ b/flights/price_graph_test.go @@ -2,6 +2,7 @@ package flights import ( "fmt" + "net/url" "testing" "time" @@ -12,23 +13,23 @@ import ( func TestGetPriceGraphReal(t *testing.T) { session := New() - date, err := time.Parse("2006-01-02", "2024-01-01") - if err != nil { - t.Fatalf("Error while creating date") - } - returnDate, err := time.Parse("2006-01-02", "2024-01-31") - if err != nil { - t.Fatalf("Error while creating return date") - } + daysDiff1 := 60 + daysDiff2 := 90 + expectedOffers := daysDiff2 - daysDiff1 + 1 + + offers, err := session.GetPriceGraph( + time.Now().AddDate(0, 0, daysDiff1), time.Now().AddDate(0, 0, daysDiff2), + []string{"London"}, []string{}, []string{"Paris"}, []string{}, + 1, currency.PLN, AnyStops, Economy, RoundTrip, + language.English, 7) - offers, err := session.GetPriceGraph(date, returnDate, 7, "Berlin", "Rome", currency.PLN, language.English) if err != nil { t.Fatalf(err.Error()) } - if len(offers) != 31 { + if len(offers) != expectedOffers { fmt.Println(offers) - t.Fatalf("received offers array length is different than 31: %d", len(offers)) + t.Fatalf("received offers array length is different than %d: %d", expectedOffers, len(offers)) } } @@ -50,7 +51,12 @@ func TestGetPriceGraph(t *testing.T) { client: httpClientMock, } - offers, err := session.GetPriceGraph(time.Now().AddDate(0, 0, 2), time.Now().AddDate(0, 0, 5), 0, "Athens", "Warsaw", currency.PLN, language.English) + offers, err := session.GetPriceGraph( + time.Now().AddDate(0, 0, 2), + time.Now().AddDate(0, 0, 5), + []string{"Athens"}, []string{}, []string{"Warsaw"}, []string{}, + 0, currency.PLN, AnyStops, Economy, RoundTrip, + language.English, 0) if err != nil { t.Fatalf(err.Error()) } @@ -67,13 +73,10 @@ func TestGetPriceGraph(t *testing.T) { func _testGetPriceGraphDateLimit(t *testing.T, session *Session, start time.Time, end time.Time, errorValue string) { _, err := session.GetPriceGraph( - start, - end, - 0, - "", - "", - currency.PLN, - language.English) + start, end, + []string{}, []string{}, []string{}, []string{}, + 0, currency.PLN, AnyStops, Economy, RoundTrip, language.English, + 0) if err == nil { t.Fatalf("GetPriceGraph call for the following dates start %s end %s, should result in error", start, end) @@ -89,3 +92,62 @@ func TestGetPriceGraphDateLimit(t *testing.T) { _testGetPriceGraphDateLimit(t, session, time.Now().AddDate(0, 0, 5), time.Now().AddDate(0, 0, 2), "rangeEndDate is before rangeStartDate") _testGetPriceGraphDateLimit(t, session, time.Now().AddDate(0, 0, -1), time.Now().AddDate(0, 0, 2), "rangeStartDate is before today's date") } + +func TestPriceGraphReqData(t *testing.T) { + session := New() + + expectedReqData1 := `[null,"[null,[null,null,1,null,[],1,[1,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,0,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3],[[[[\"CDG\",0],[\"/m/04jpl\",5]]],[[[\"SFO\",0],[\"/m/030qb3t\",5]]],null,0,[],[],\"2024-01-03\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],[\"2024-01-01\",\"2024-01-31\"],null,[2,2]]"]` + expectedReqData2 := `[null,"[null,[null,null,2,null,[],3,[2,0,0,0],null,null,null,null,null,null,[[[[[\"SFO\",0],[\"/m/030qb3t\",5]]],[[[\"CDG\",0],[\"/m/04jpl\",5]]],null,3,[],[],\"2024-01-01\",null,[],[],[],null,null,[],3]],null,null,null,1,null,null,null,null,null,[]],[\"2024-01-01\",\"2024-01-31\"],null,[2,2]]"]` + + date, err := time.Parse("2006-01-02", "2024-01-01") + if err != nil { + t.Fatalf("Error while creating date: %v", err) + } + returnDate, err := time.Parse("2006-01-02", "2024-01-31") + if err != nil { + t.Fatalf("Error while creating return date: %v", err) + } + + _reqData1, err := session.getPriceGraphReqData( + date, returnDate, + []string{"Los Angeles"}, + []string{"SFO"}, + []string{"London"}, + []string{"CDG"}, + 1, AnyStops, Economy, RoundTrip, + language.English, 2) + if err != nil { + t.Fatal(err) + } + + reqData1, err := url.QueryUnescape(_reqData1) + if err != nil { + t.Fatal(err) + } + + if reqData1 != expectedReqData1 { + t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedReqData1, reqData1) + } + + _reqData2, err := session.getPriceGraphReqData( + date, + returnDate, + []string{"Los Angeles"}, + []string{"SFO"}, + []string{"London"}, + []string{"CDG"}, + 2, Stop2, Buisness, OneWay, + language.English, 2) + if err != nil { + t.Fatal(err) + } + + reqData2, err := url.QueryUnescape(_reqData2) + if err != nil { + t.Fatal(err) + } + + if reqData2 != expectedReqData2 { + t.Fatalf("wrong unescaped query, expected: %s received: %s", expectedReqData2, reqData2) + } +} diff --git a/flights/types.go b/flights/types.go index 2f44b57..f379645 100644 --- a/flights/types.go +++ b/flights/types.go @@ -42,6 +42,31 @@ type PriceRange struct { High float64 } +type Stops int64 + +const ( + AnyStops Stops = iota + Nonstop + Stop1 + Stop2 +) + +type Class int64 + +const ( + Economy Class = iota + PremiumEconomy + Buisness + First +) + +type TripType int64 + +const ( + RoundTrip TripType = iota + OneWay +) + func (f flight) String() string { out := "" out += fmt.Sprintf("DepAirportCode: %s ", f.DepAirportCode) diff --git a/flights/url.go b/flights/url.go index 0f6dc02..4abb1ab 100644 --- a/flights/url.go +++ b/flights/url.go @@ -16,31 +16,6 @@ const ( srcConst byte = 106 ) -type Stops int64 - -const ( - AnyStops Stops = iota - Nonstop - Stop1 - Stop2 -) - -type Class int64 - -const ( - Economy Class = iota - PremiumEconomy - Buisness - First -) - -type TripType int64 - -const ( - RoundTrip TripType = iota - OneWay -) - func checkMaxLocations(cities, airports []string) (bool, error) { length := len(cities) + len(airports) if length <= 7 { diff --git a/flights/utils.go b/flights/utils.go index b28b930..6aca216 100644 --- a/flights/utils.go +++ b/flights/utils.go @@ -18,13 +18,13 @@ func skipPrefix(body *bufio.Reader) error { return nil } -func getElement[T any](slice []interface{}, index int) T { - elem, ok := getRawElement(slice, index).(T) - if !ok { +func getElement[T any](slice []interface{}, index int) (T, bool) { + if len(slice) <= index { var empty T - return empty + return empty, false } - return elem + elem, ok := slice[index].(T) + return elem, ok } func getRawElement(slice []interface{}, index int) interface{} {