Esempio n. 1
0
    def setUp(self):
        """
        Setup test
        """
        try:
            self.bot = WhensMyBus(testing=self.testing_level)
        except RuntimeError as exc:
            print exc
            self.tearDown()
            self.fail("Sorry, a RuntimeError was encountered")

        if not self.bot.geocoder:
            self.fail("Sorry, this needs a geocoder in order to validate tests properly")

        self.at_reply = '@%s ' % self.bot.username
        self.geodata_table_names = ('locations', )

        # Route Number, Origin Name, Origin Number, Origin Longitude, Origin Latitude, Dest Name, Dest Number, Expected Origin, Unwanted Destination
        self.standard_test_data = (
            ('15',         'Limehouse Station', '53452', 51.5124, -0.0397, 'Poplar',           '73923', 'Limehouse Station', 'Regent Street'),
            ('425 25 205', 'Bow Road Station',  '55489', 51.5272, -0.0247, 'Mile End station', '76239', 'Bow Road Station',  '(Bow Church|Ilford|Stratford)'),
        )
        # Troublesome destinations & data
        self.nonstandard_test_data = (
            # Hoxton is mistaken as Brixton
            ('243 from Hoxton',
                ('Hoxton Station / Geffrye Museum',),
                ('Brixton',)),
            # Postcodes should be doable with a geocoder
            ('55 from EC1M 4PN',
                ('St John Street',),
                ()),
            # 103 has more than 2 runs, check we delete the empty one
            ('103 from Romford Station',
                ('Romford Station',),
                ('None shown',)),
            # Ignore use of the definite article
            ('the 15 from st pauls churchyard',
                ("St Paul's Churchyard",),
                ('None shown',)),
            # Ignore unknown words like directions before the "from" or "to"
            ('243 north bound to Clerkenwell from Hoxton Station please',
                ("Hoxton Station",),
                ('None shown',)),
        )
Esempio n. 2
0
class WhensMyBusTestCase(WhensMyTransportTestCase):
    """
    Main Test Case for When's My Bus
    """
    #pylint: disable=R0904
    def setUp(self):
        """
        Setup test
        """
        try:
            self.bot = WhensMyBus(testing=self.testing_level)
        except RuntimeError as exc:
            print exc
            self.tearDown()
            self.fail("Sorry, a RuntimeError was encountered")

        if not self.bot.geocoder:
            self.fail("Sorry, this needs a geocoder in order to validate tests properly")

        self.at_reply = '@%s ' % self.bot.username
        self.geodata_table_names = ('locations', )

        # Route Number, Origin Name, Origin Number, Origin Longitude, Origin Latitude, Dest Name, Dest Number, Expected Origin, Unwanted Destination
        self.standard_test_data = (
            ('15',         'Limehouse Station', '53452', 51.5124, -0.0397, 'Poplar',           '73923', 'Limehouse Station', 'Regent Street'),
            ('425 25 205', 'Bow Road Station',  '55489', 51.5272, -0.0247, 'Mile End station', '76239', 'Bow Road Station',  '(Bow Church|Ilford|Stratford)'),
        )
        # Troublesome destinations & data
        self.nonstandard_test_data = (
            # Hoxton is mistaken as Brixton
            ('243 from Hoxton',
                ('Hoxton Station / Geffrye Museum',),
                ('Brixton',)),
            # Postcodes should be doable with a geocoder
            ('55 from EC1M 4PN',
                ('St John Street',),
                ()),
            # 103 has more than 2 runs, check we delete the empty one
            ('103 from Romford Station',
                ('Romford Station',),
                ('None shown',)),
            # Ignore use of the definite article
            ('the 15 from st pauls churchyard',
                ("St Paul's Churchyard",),
                ('None shown',)),
            # Ignore unknown words like directions before the "from" or "to"
            ('243 north bound to Clerkenwell from Hoxton Station please',
                ("Hoxton Station",),
                ('None shown',)),
        )

    def _test_correct_successes(self, tweet, routes_specified, expected_origin, destination_to_avoid=''):
        """
        Generic test to confirm a Bus Tweet is being processed correctly
        """
        print tweet.text
        t1 = time.time()
        results = self.bot.process_tweet(tweet)
        self.assertTrue(results)
        t2 = time.time()
        self.assertTrue(results)
        for result in results:
            print result
            # Result exists, no TfL garbage please, and no all-caps either
            self.assertTrue(result)
            for unwanted in ('<>', '#', '\[DLR\]', '>T<'):
                self.assertNotRegexpMatches(result, unwanted)
            self.assertNotEqual(result, result.upper())
            # Should say one of our route numbers, expected origin and a time
            route_regex = "^(%s)" % '|'.join(routes_specified.upper().replace(',', '').split(' '))
            self.assertRegexpMatches(result, route_regex)
            if result.find("None shown") > -1:
                self.assertRegexpMatches(result, 'None shown going (North|NE|East|SE|South|SW|West|NW)(;|$)')
            else:
                self.assertRegexpMatches(result, '(%s to .* [0-9]{4})' % expected_origin)
            # If we have specified a direction or destination, we should not be seeing buses going the other way
            # and the expected origin should therefore only be repeated once
            if destination_to_avoid:
                self.assertNotRegexpMatches(result, destination_to_avoid)
                self.assertNotRegexpMatches(result, ";")
                self.assertEqual(result.count(expected_origin), 1)
            else:
                self.assertRegexpMatches(result, ";")

        print 'Processing of Tweet took %0.3f ms\r\n' % ((t2 - t1) * 1000.0,)

    #
    # Core functionality tests
    #

    def test_location(self):
        """
        Unit tests for WMTLocation object and the bus database
        """
        self.assertEqual(self.bot.geodata.find_closest((51.5124, -0.0397), {'run': '1', 'route': '15'}).number, "53410")
        self.assertEqual(self.bot.geodata.find_fuzzy_match("Limehouse Sta", {'run': '1', 'route': '15'}).number, "53410")
        self.assertEqual(self.bot.geodata.find_exact_match({'run': '1', 'route': '15', 'name': 'LIMEHOUSE TOWN HALL'}).number, "48264")
        self.assertTrue(self.bot.geodata.database.check_existence_of('locations', 'bus_stop_code', '47001'))
        self.assertFalse(self.bot.geodata.database.check_existence_of('locations', 'bus_stop_code', '47000'))
        self.assertEqual(self.bot.geodata.database.get_max_value('locations', 'run', {}), 6)

    def test_no_bus_number(self):
        """
        Test to confirm we are ignoring Tweets that do not have bus numbers in them
        """
        message = 'Thanks!'
        tweet = FakeTweet(self.at_reply + message)
        self.assertFalse(self.bot.process_tweet(tweet))
        direct_message = FakeDirectMessage(message)
        self.assertFalse(self.bot.process_tweet(direct_message))

    def test_nonexistent_bus(self):
        """
        Test to confirm non-existent buses handled OK
        """
        for message in ('218 from Trafalgar Square', '   218 from Trafalgar Square', '   218   from Trafalgar Square #hashtag'):
            tweet = FakeTweet(self.at_reply + message)
            self._test_correct_exception_produced(tweet, 'nonexistent_bus', '218')
            direct_message = FakeDirectMessage(message)
            self._test_correct_exception_produced(direct_message, 'nonexistent_bus', '218')

    def test_textparser(self):
        """
        Tests for the natural language parser
        """
        (route, origin, destination) = ('A1', 'Heathrow Airport', '47000')
        routes = [route]
        self.assertEqual(self.bot.parser.parse_message(""),                                                 (None, None, None, None))
        self.assertEqual(self.bot.parser.parse_message("from %s to %s %s" % (origin, destination, route)),  (None, None, None, None))
        self.assertEqual(self.bot.parser.parse_message("%s" % route),                                       (routes, None, None, None))
        self.assertEqual(self.bot.parser.parse_message("%s %s" % (route, origin)),                          (routes, origin, None, None))
        self.assertEqual(self.bot.parser.parse_message("%s %s to %s" % (route, origin, destination)),       (routes, origin, destination, None))
        self.assertEqual(self.bot.parser.parse_message("%s from %s" % (route, origin)),                     (routes, origin, None, None))
        self.assertEqual(self.bot.parser.parse_message("%s from %s to %s" % (route, origin, destination)),  (routes, origin, destination, None))
        self.assertEqual(self.bot.parser.parse_message("%s to %s" % (route, destination)),                  (routes, None, destination, None))
        self.assertEqual(self.bot.parser.parse_message("%s to %s from %s" % (route, destination, origin)),  (routes, origin, destination, None))

    #
    # Request-based tests
    #

    def test_bad_stop_id(self):
        """
        Test to confirm bad stop IDs handled OK
        """
        message = '15 from 00000'
        tweet = FakeTweet(self.at_reply + message)
        self._test_correct_exception_produced(tweet, 'bad_stop_id', '00000')  # Stop IDs begin at 47000
        direct_message = FakeDirectMessage(message)
        self._test_correct_exception_produced(direct_message, 'bad_stop_id', '00000')  # Stop IDs begin at 47000

    def test_stop_id_mismatch(self):
        """
        Test to confirm when route and stop do not match up is handled OK
        """
        message = '15 from 52240'
        tweet = FakeTweet(self.at_reply + message)
        self._test_correct_exception_produced(tweet, 'stop_id_not_found', '15', '52240')  # The 15 does not go from Canary Wharf
        direct_message = FakeDirectMessage(message)
        self._test_correct_exception_produced(direct_message, 'stop_id_not_found', '15', '52240')

    def test_stop_name_nonsense(self):
        """
        Test to confirm when route and stop do not match up is handled OK
        """
        message = '15 from Eucgekewf78'
        tweet = FakeTweet(self.at_reply + message)
        self._test_correct_exception_produced(tweet, 'stop_name_not_found', '15', 'Eucgekewf78')

    @unittest.skipIf('--live-data' in sys.argv, "Expected responses to messages not replicable with live data")
    def test_standard_messages(self):
        """
        Generic test for standard-issue messages
        """
        #pylint: disable=W0612
        for (route, origin_name, origin_id, lat, lon, destination_name, destination_id, expected_origin, destination_to_avoid) in self.standard_test_data:

            # C-string format helper
            test_variables = dict([(name, eval(name)) for name in ('route', 'origin_name', 'origin_id', 'destination_name', 'destination_id')])

            # 5 types of origin (geotag, ID, name, ID without 'from', name without 'from') and 3 types of destination (none, ID, name)
            from_fragments = [value % test_variables for value in ("", " from %(origin_name)s",    " from %(origin_id)s", " %(origin_name)s", " %(origin_id)s")]
            to_fragments = [value % test_variables for value in ("", " to %(destination_name)s", " to %(destination_id)s")]

            for from_fragment in from_fragments:
                for to_fragment in to_fragments:
                    messages = [(self.at_reply + route + from_fragment + to_fragment)]
                    # Also try "to" first, "from" second, if there is a "from" in the from fragment
                    if to_fragment and from_fragment.find("from") > -1:
                        messages.append(self.at_reply + route + to_fragment + from_fragment)
                    for message in messages:
                        if not from_fragment:
                            tweet = FakeTweet(message, (lat, lon))
                        else:
                            tweet = FakeTweet(message)
                        if (from_fragment.find(origin_id) > -1) or to_fragment:
                            self._test_correct_successes(tweet, route, expected_origin, destination_to_avoid)
                        else:
                            self._test_correct_successes(tweet, route, expected_origin)

    def test_multiple_routes(self):
        """
        Test multiple routes from different bus stops in the same area (unlike the above function which
        tests multiple routes going in the same direction, from the same stop(s)
        """
        test_data = (("277 15", (51.511694, -0.030286), "(East India Dock Road|Limehouse Town Hall)"),)

        for (route, position, expected_origin) in test_data:
            tweet = FakeTweet(self.at_reply + route, position)
            self._test_correct_successes(tweet, route, expected_origin)