def runTest(self):
        fare = transitfeed.FareAttribute()
        fare.fare_id = "normal"
        fare.price = 1.50
        fare.currency_type = "USD"
        fare.payment_method = 0
        fare.transfers = 1
        fare.transfer_duration = 7200
        fare.Validate(self.problems)

        fare.fare_id = None
        self.ValidateAndExpectMissingValue(fare, "fare_id")
        fare.fare_id = ""
        self.ValidateAndExpectMissingValue(fare, "fare_id")
        fare.fare_id = "normal"

        fare.price = "1.50"
        self.ValidateAndExpectInvalidValue(fare, "price")
        fare.price = 1
        fare.Validate(self.problems)
        fare.price = None
        self.ValidateAndExpectMissingValue(fare, "price")
        fare.price = 0.0
        fare.Validate(self.problems)
        fare.price = -1.50
        self.ValidateAndExpectInvalidValue(fare, "price")
        fare.price = 1.50

        fare.currency_type = ""
        self.ValidateAndExpectMissingValue(fare, "currency_type")
        fare.currency_type = None
        self.ValidateAndExpectMissingValue(fare, "currency_type")
        fare.currency_type = "usd"
        self.ValidateAndExpectInvalidValue(fare, "currency_type")
        fare.currency_type = "KML"
        self.ValidateAndExpectInvalidValue(fare, "currency_type")
        fare.currency_type = "USD"

        fare.payment_method = "0"
        self.ValidateAndExpectInvalidValue(fare, "payment_method")
        fare.payment_method = -1
        self.ValidateAndExpectInvalidValue(fare, "payment_method")
        fare.payment_method = 1
        fare.Validate(self.problems)
        fare.payment_method = 2
        self.ValidateAndExpectInvalidValue(fare, "payment_method")
        fare.payment_method = None
        self.ValidateAndExpectMissingValue(fare, "payment_method")
        fare.payment_method = ""
        self.ValidateAndExpectMissingValue(fare, "payment_method")
        fare.payment_method = 0

        fare.transfers = "1"
        self.ValidateAndExpectInvalidValue(fare, "transfers")
        fare.transfers = -1
        self.ValidateAndExpectInvalidValue(fare, "transfers")
        fare.transfers = 2
        fare.Validate(self.problems)
        fare.transfers = 3
        self.ValidateAndExpectInvalidValue(fare, "transfers")
        fare.transfers = None
        fare.Validate(self.problems)
        fare.transfers = 1

        fare.transfer_duration = 0
        fare.Validate(self.problems)
        fare.transfer_duration = None
        fare.Validate(self.problems)
        fare.transfer_duration = -3600
        self.ValidateAndExpectInvalidValue(fare, "transfer_duration")
        fare.transfers = 0  # no transfers allowed and duration specified!
        fare.transfer_duration = 3600
        fare.Validate(self.problems)
        fare.transfers = 1
        fare.transfer_duration = "3600"
        self.ValidateAndExpectInvalidValue(fare, "transfer_duration")
        fare.transfer_duration = 7200
        self.accumulator.AssertNoMoreExceptions()
    def runTest(self):
        accumulator = util.RecordingProblemAccumulator(
            self, ignore_types=("ExpirationDate", ))
        problems = transitfeed.ProblemReporter(accumulator)
        schedule = transitfeed.Schedule(problem_reporter=problems)
        agency = transitfeed.Agency()
        agency.agency_id = "DTA"
        agency.agency_name = "Demo Transit Authority"
        agency.agency_url = "http://google.com"
        agency.agency_timezone = "America/Los_Angeles"
        agency.agency_lang = 'en'
        # Test that unknown columns, such as agency_mission, are preserved
        agency.agency_mission = "Get You There"
        schedule.AddAgencyObject(agency)

        routes = []
        route_data = [("AB", "DTA", "10", "Airport - Bullfrog", 3),
                      ("BFC", "DTA", "20", "Bullfrog - Furnace Creek Resort",
                       3),
                      ("STBA", "DTA", "30", "Stagecoach - Airport Shuttle", 3),
                      ("CITY", "DTA", "40", "City", 3),
                      ("AAMV", "DTA", "50", "Airport - Amargosa Valley", 3)]

        for route_entry in route_data:
            route = transitfeed.Route()
            (route.route_id, route.agency_id, route.route_short_name,
             route.route_long_name, route.route_type) = route_entry
            routes.append(route)
            schedule.AddRouteObject(route)

        shape_data = [
            (36.915760, -116.751709),
            (36.905018, -116.763206),
            (36.902134, -116.777969),
            (36.904091, -116.788185),
            (36.883602, -116.814537),
            (36.874523, -116.795593),
            (36.873302, -116.786491),
            (36.869202, -116.784241),
            (36.868515, -116.784729),
        ]

        shape = transitfeed.Shape("BFC1S")
        for (lat, lon) in shape_data:
            shape.AddPoint(lat, lon)
        schedule.AddShapeObject(shape)

        week_period = transitfeed.ServicePeriod()
        week_period.service_id = "FULLW"
        week_period.start_date = "20070101"
        week_period.end_date = "20071231"
        week_period.SetWeekdayService()
        week_period.SetWeekendService()
        week_period.SetDateHasService("20070604", False)
        schedule.AddServicePeriodObject(week_period)

        weekend_period = transitfeed.ServicePeriod()
        weekend_period.service_id = "WE"
        weekend_period.start_date = "20070101"
        weekend_period.end_date = "20071231"
        weekend_period.SetWeekendService()
        schedule.AddServicePeriodObject(weekend_period)

        stops = []
        stop_data = [
            ("FUR_CREEK_RES", "Furnace Creek Resort (Demo)", 36.425288,
             -117.133162, "zone-a", "1234"),
            ("BEATTY_AIRPORT", "Nye County Airport (Demo)", 36.868446,
             -116.784682, "zone-a", "1235"),
            ("BULLFROG", "Bullfrog (Demo)", 36.88108, -116.81797, "zone-b",
             "1236"),
            ("STAGECOACH", "Stagecoach Hotel & Casino (Demo)", 36.915682,
             -116.751677, "zone-c", "1237"),
            ("NADAV", "North Ave / D Ave N (Demo)", 36.914893, -116.76821, "",
             ""),
            ("NANAA", "North Ave / N A Ave (Demo)", 36.914944, -116.761472, "",
             ""),
            ("DADAN", "Doing AVe / D Ave N (Demo)", 36.909489, -116.768242, "",
             ""),
            ("EMSI", "E Main St / S Irving St (Demo)", 36.905697, -116.76218,
             "", ""),
            ("AMV", "Amargosa Valley (Demo)", 36.641496, -116.40094, "", ""),
        ]
        for stop_entry in stop_data:
            stop = transitfeed.Stop()
            (stop.stop_id, stop.stop_name, stop.stop_lat, stop.stop_lon,
             stop.zone_id, stop.stop_code) = stop_entry
            schedule.AddStopObject(stop)
            stops.append(stop)
        # Add a value to an unknown column and make sure it is preserved
        schedule.GetStop("BULLFROG").stop_sound = "croak!"

        trip_data = [
            ("AB", "FULLW", "AB1", "to Bullfrog", "0", "1", None),
            ("AB", "FULLW", "AB2", "to Airport", "1", "2", None),
            ("STBA", "FULLW", "STBA", "Shuttle", None, None, None),
            ("CITY", "FULLW", "CITY1", None, "0", None, None),
            ("CITY", "FULLW", "CITY2", None, "1", None, None),
            ("BFC", "FULLW", "BFC1", "to Furnace Creek Resort", "0", "1",
             "BFC1S"),
            ("BFC", "FULLW", "BFC2", "to Bullfrog", "1", "2", None),
            ("AAMV", "WE", "AAMV1", "to Amargosa Valley", "0", None, None),
            ("AAMV", "WE", "AAMV2", "to Airport", "1", None, None),
            ("AAMV", "WE", "AAMV3", "to Amargosa Valley", "0", None, None),
            ("AAMV", "WE", "AAMV4", "to Airport", "1", None, None),
        ]

        trips = []
        for trip_entry in trip_data:
            trip = transitfeed.Trip()
            (trip.route_id, trip.service_id, trip.trip_id, trip.trip_headsign,
             trip.direction_id, trip.block_id, trip.shape_id) = trip_entry
            trips.append(trip)
            schedule.AddTripObject(trip)

        stop_time_data = {
            "STBA":
            [("6:00:00", "6:00:00", "STAGECOACH", None, None, None, None),
             ("6:20:00", "6:20:00", "BEATTY_AIRPORT", None, None, None, None)],
            "CITY1":
            [("6:00:00", "6:00:00", "STAGECOACH", 1.34, 0, 0, "stop 1"),
             ("6:05:00", "6:07:00", "NANAA", 2.40, 1, 2, "stop 2"),
             ("6:12:00", "6:14:00", "NADAV", 3.0, 2, 2, "stop 3"),
             ("6:19:00", "6:21:00", "DADAN", 4, 2, 2, "stop 4"),
             ("6:26:00", "6:28:00", "EMSI", 5.78, 2, 3, "stop 5")],
            "CITY2": [("6:28:00", "6:28:00", "EMSI", None, None, None, None),
                      ("6:35:00", "6:37:00", "DADAN", None, None, None, None),
                      ("6:42:00", "6:44:00", "NADAV", None, None, None, None),
                      ("6:49:00", "6:51:00", "NANAA", None, None, None, None),
                      ("6:56:00", "6:58:00", "STAGECOACH", None, None, None,
                       None)],
            "AB1":
            [("8:00:00", "8:00:00", "BEATTY_AIRPORT", None, None, None, None),
             ("8:10:00", "8:15:00", "BULLFROG", None, None, None, None)],
            "AB2":
            [("12:05:00", "12:05:00", "BULLFROG", None, None, None, None),
             ("12:15:00", "12:15:00", "BEATTY_AIRPORT", None, None, None, None)
             ],
            "BFC1": [
                ("8:20:00", "8:20:00", "BULLFROG", None, None, None, None),
                ("9:20:00", "9:20:00", "FUR_CREEK_RES", None, None, None, None)
            ],
            "BFC2":
            [("11:00:00", "11:00:00", "FUR_CREEK_RES", None, None, None, None),
             ("12:00:00", "12:00:00", "BULLFROG", None, None, None, None)],
            "AAMV1": [("8:00:00", "8:00:00", "BEATTY_AIRPORT", None, None,
                       None, None),
                      ("9:00:00", "9:00:00", "AMV", None, None, None, None)],
            "AAMV2": [("10:00:00", "10:00:00", "AMV", None, None, None, None),
                      ("11:00:00", "11:00:00", "BEATTY_AIRPORT", None, None,
                       None, None)],
            "AAMV3": [("13:00:00", "13:00:00", "BEATTY_AIRPORT", None, None,
                       None, None),
                      ("14:00:00", "14:00:00", "AMV", None, None, None, None)],
            "AAMV4": [("15:00:00", "15:00:00", "AMV", None, None, None, None),
                      ("16:00:00", "16:00:00", "BEATTY_AIRPORT", None, None,
                       None, None)],
        }

        for trip_id, stop_time_list in stop_time_data.items():
            for stop_time_entry in stop_time_list:
                (arrival_time, departure_time, stop_id, shape_dist_traveled,
                 pickup_type, drop_off_type, stop_headsign) = stop_time_entry
                trip = schedule.GetTrip(trip_id)
                stop = schedule.GetStop(stop_id)
                trip.AddStopTime(stop,
                                 arrival_time=arrival_time,
                                 departure_time=departure_time,
                                 shape_dist_traveled=shape_dist_traveled,
                                 pickup_type=pickup_type,
                                 drop_off_type=drop_off_type,
                                 stop_headsign=stop_headsign)

        self.assertEqual(
            0,
            schedule.GetTrip("CITY1").GetStopTimes()[0].pickup_type)
        self.assertEqual(
            1,
            schedule.GetTrip("CITY1").GetStopTimes()[1].pickup_type)

        headway_data = [
            ("STBA", "6:00:00", "22:00:00", 1800),
            ("CITY1", "6:00:00", "7:59:59", 1800),
            ("CITY2", "6:00:00", "7:59:59", 1800),
            ("CITY1", "8:00:00", "9:59:59", 600),
            ("CITY2", "8:00:00", "9:59:59", 600),
            ("CITY1", "10:00:00", "15:59:59", 1800),
            ("CITY2", "10:00:00", "15:59:59", 1800),
            ("CITY1", "16:00:00", "18:59:59", 600),
            ("CITY2", "16:00:00", "18:59:59", 600),
            ("CITY1", "19:00:00", "22:00:00", 1800),
            ("CITY2", "19:00:00", "22:00:00", 1800),
        ]

        headway_trips = {}
        for headway_entry in headway_data:
            (trip_id, start_time, end_time, headway) = headway_entry
            headway_trips[trip_id] = []  # adding to set to check later
            trip = schedule.GetTrip(trip_id)
            trip.AddFrequency(start_time, end_time, headway, 0, problems)
        for trip_id in headway_trips:
            headway_trips[trip_id] = \
                schedule.GetTrip(trip_id).GetFrequencyTuples()

        fare_data = [
            ("p", 1.25, "USD", 0, 0),
            ("a", 5.25, "USD", 0, 0),
        ]

        fares = []
        for fare_entry in fare_data:
            fare = transitfeed.FareAttribute(fare_entry[0], fare_entry[1],
                                             fare_entry[2], fare_entry[3],
                                             fare_entry[4])
            fares.append(fare)
            schedule.AddFareAttributeObject(fare)

        fare_rule_data = [
            ("p", "AB", "zone-a", "zone-b", None),
            ("p", "STBA", "zone-a", None, "zone-c"),
            ("p", "BFC", None, "zone-b", "zone-a"),
            ("a", "AAMV", None, None, None),
        ]

        for fare_id, route_id, orig_id, dest_id, contains_id in fare_rule_data:
            rule = transitfeed.FareRule(fare_id=fare_id,
                                        route_id=route_id,
                                        origin_id=orig_id,
                                        destination_id=dest_id,
                                        contains_id=contains_id)
            schedule.AddFareRuleObject(rule, problems)

        schedule.Validate(problems)
        accumulator.AssertNoMoreExceptions()
        schedule.WriteGoogleTransitFeed(self.tempfilepath)

        read_schedule = \
            transitfeed.Loader(self.tempfilepath, problems=problems,
                               extra_validation=True).Load()
        e = accumulator.PopException("UnrecognizedColumn")
        self.assertEqual(e.file_name, "agency.txt")
        self.assertEqual(e.column_name, "agency_mission")
        e = accumulator.PopException("UnrecognizedColumn")
        self.assertEqual(e.file_name, "stops.txt")
        self.assertEqual(e.column_name, "stop_sound")
        accumulator.AssertNoMoreExceptions()

        self.assertEqual(1, len(read_schedule.GetAgencyList()))
        self.assertEqual(agency, read_schedule.GetAgency(agency.agency_id))

        self.assertEqual(len(routes), len(read_schedule.GetRouteList()))
        for route in routes:
            self.assertEqual(route, read_schedule.GetRoute(route.route_id))

        self.assertEqual(2, len(read_schedule.GetServicePeriodList()))
        self.assertEqual(
            week_period,
            read_schedule.GetServicePeriod(week_period.service_id))
        self.assertEqual(
            weekend_period,
            read_schedule.GetServicePeriod(weekend_period.service_id))

        self.assertEqual(len(stops), len(read_schedule.GetStopList()))
        for stop in stops:
            self.assertEqual(stop, read_schedule.GetStop(stop.stop_id))
        self.assertEqual("croak!",
                         read_schedule.GetStop("BULLFROG").stop_sound)

        self.assertEqual(len(trips), len(read_schedule.GetTripList()))
        for trip in trips:
            self.assertEqual(trip, read_schedule.GetTrip(trip.trip_id))

        for trip_id in headway_trips:
            self.assertEqual(
                headway_trips[trip_id],
                read_schedule.GetTrip(trip_id).GetFrequencyTuples())

        for trip_id, stop_time_list in stop_time_data.items():
            trip = read_schedule.GetTrip(trip_id)
            read_stoptimes = trip.GetStopTimes()
            self.assertEqual(len(read_stoptimes), len(stop_time_list))
            for stop_time_entry, read_stoptime in zip(stop_time_list,
                                                      read_stoptimes):
                (arrival_time, departure_time, stop_id, shape_dist_traveled,
                 pickup_type, drop_off_type, stop_headsign) = stop_time_entry
                self.assertEqual(stop_id, read_stoptime.stop_id)
                self.assertEqual(read_schedule.GetStop(stop_id),
                                 read_stoptime.stop)
                self.assertEqualTimeString(arrival_time,
                                           read_stoptime.arrival_time)
                self.assertEqualTimeString(departure_time,
                                           read_stoptime.departure_time)
                self.assertEqual(shape_dist_traveled,
                                 read_stoptime.shape_dist_traveled)
                self.assertEqualWithDefault(pickup_type,
                                            read_stoptime.pickup_type, 0)
                self.assertEqualWithDefault(drop_off_type,
                                            read_stoptime.drop_off_type, 0)
                self.assertEqualWithDefault(stop_headsign,
                                            read_stoptime.stop_headsign, '')

        self.assertEqual(len(fares), len(read_schedule.GetFareAttributeList()))
        for fare in fares:
            self.assertEqual(fare,
                             read_schedule.GetFareAttribute(fare.fare_id))

        read_fare_rules_data = []
        for fare in read_schedule.GetFareAttributeList():
            for rule in fare.GetFareRuleList():
                self.assertEqual(fare.fare_id, rule.fare_id)
                read_fare_rules_data.append(
                    (fare.fare_id, rule.route_id, rule.origin_id,
                     rule.destination_id, rule.contains_id))

        fare_rule_data.sort()
        read_fare_rules_data.sort()
        self.assertEqual(len(read_fare_rules_data), len(fare_rule_data))
        for rf, f in zip(read_fare_rules_data, fare_rule_data):
            self.assertEqual(rf, f)

        self.assertEqual(1, len(read_schedule.GetShapeList()))
        self.assertEqual(shape, read_schedule.GetShape(shape.shape_id))