def test_cache_clear(self): """ Test cache clearing by downloading a page (and thus creating the cached version), then asking for it to be cleared, and checking if the file still exists """ # download a test page first - make sure it is cached climate.get_climate_data("Melbourne") # clear, and see if it reports successful paths = cache.clear("Melbourne") self.assertEqual(cache.exists("Melbourne"), False) # check if file physically exists for path in paths: self.assertFalse(os.path.exists(path))
def test_cache_clear_all(self): """ Test cache clearing by downloading a page (and thus creating the cached version), then asking for everything to be cleared, and checking if files reported exist """ # download a test page first - make sure it is cached climate.get_climate_data("Melbourne") paths = cache.clear_all() # see if it self-reports successful for the test page self.assertEquals(cache.exists("Melbourne"), False) # check if files physically exists for path in paths: self.assertFalse(os.path.exists(path))
def test_any_unicode(self): """arbitrary unicode should work in query""" pagenames = ["Reykjavík", "Gdańsk", "香港", "ᐃᓄᒃᑕᐅᑦ"] for pagename in pagenames: data = climate.get_climate_data(pagename)
def test_nonexistent_page(self): """nonexisting page should give corresponding error message""" data = climate.get_climate_data("Fakey Place, gdsngkjdsnk") self.assertEqual(data["page_error"], True) self.assertEqual(data["title"].endswith("location not found"), True)
def test_weatherbox_cached_template(self): """ Test a New York City-specific weatherbox use that invokes a pre-rendered {{New York City weatherbox/cached}} template. More information in a comment in climate.get_climate_data.find_separate_weatherbox_template """ data = climate.get_climate_data("New York City") self.assertEqual(data["record high C"][2], 30.0) # March self.assertEqual(data["low C"][10], 5.3) # November
def test_unicode_page_name(self): """Page that is accessible on Wikipedia via a Unicode name should return correct climate info. Test with Jan high and Dec record low for Hong Kong (香港)""" data = climate.get_climate_data("香港") self.assertEqual(data["title"], "Hong Kong") self.assertEqual(data["high C"][0], 18.6) self.assertEqual(data["record low C"][11], 4.3)
def test_cache_timing(self): """ Bit of a wonky test: test actual caching by comparing time to load a page uncached and time to load it cached. The latter should be shorter. Might fail with a false negative if filesystem is being slow at the moment, but in general it should work pretty well. """ page = "Melbourne" cache.clear(page) time1 = time.time() climate.get_climate_data(page) time_with_no_cache = time.time() - time1 time2 = time.time() climate.get_climate_data(page) time_with_cache = time.time() - time2 self.assertTrue(time_with_cache < time_with_no_cache)
def test_no_climate_data(self): """page with no climate data should return a default initialized-but-empty result set""" pagename = "Elmira, Ontario" data = climate.get_climate_data(pagename) self.assertEqual(data["page_error"], False) self.assertEqual(data["title"], pagename) for row_name in climate.ROWS: self.assertEqual(len(data[row_name]), 0)
def test_cache_timeout(self): """ Make sure files older than 7 days are treated as not valid for cache purposes. Fake this with changing a file's modified time with os.utime() """ page = "Melbourne" climate.get_climate_data(page) self.assertEqual(cache.exists(page), True) # cache.get_file_name should really be treated as private # most of the time, but for the purposes of the test # it's OK to use it I guess file_name = cache.get_file_name(page) # set new filetime to (max cache age + 1 day) ago new_file_datetime = datetime.now() - timedelta(cache.CACHE_PERIOD_DAYS + 1, 0) new_file_timestamp = time.mktime(new_file_datetime.timetuple()) # use the new timestamp as both access time and modify time os.utime(file_name, (new_file_timestamp, new_file_timestamp)) # assert it's now reported as not cacheable self.assertEqual(cache.exists(page), False)
def test_unit_conversion(self): """ Test for correct conversion of units. Includes F->C and inches to mm and cm. Based on data for Seattle and NYC. """ known_data = { "New York City": { "precipitation mm": {5: 112, 10: 102.1}, # jun, nov "snow cm": {0: 17.8, 5: 0, 11: 12.2}, # jan, jun, dec }, "Seattle": { "high C": {3: 14.7}, # april "record low C": {1: -17.2, 7: 6.7}, # feb, aug "precipitation mm": {0: 141.5, 6: 17.8}, # jan, jul "snow cm": {1: 4.3, 11: 4.3, 5: 0}, # feb, dec, jun }, } for city, data in known_data.items(): actual_data = climate.get_climate_data(city) for key, key_data in data.items(): for month, expected_value in key_data.items(): self.assertEqual(actual_data[key][month], expected_value)
def test_cache_create(self): """ Really basic test: get a page, then check if it is reported as having cache available. """ climate.get_climate_data("Melbourne") self.assertEqual(cache.exists("Melbourne"), True)
def test_redirect(self): """wikipedia redirects should be followed""" data = climate.get_climate_data("nyc") self.assertEqual(data["title"], "New York City")
def test_known_data(self): """Test for correct retrieval of some data for some cities. Test against known-correct values retrieved via browser at time of test authoring. Basically make sure future changes don't mess up known-working queries.""" known_data = { "Vancouver": { "record high C": {6: 34.4}, # july "mean C": {9: 10.3}, # october "precipitation mm": {7: 36.7}, # august }, "Mount Fuji": { # tests cleaning of "−10.9"-like values "high C": {2: -10.9}, # march "record low C": {0: -37.3}, # january }, "Seattle": { # temperatures here also test conversion into C "high C": {3: 14.7}, # april "record low C": {1: -17.2, 7: 6.7}, # feb, aug "precipitation days": {10: 18.4}, # november "sun": {7: 281.4}, # august }, "Calgary": { "snow cm": {2: 17.1}, # march "mean C": {4: 9.8}, # may "low C": {10: -7.5}, # november "record low C": {1: -38}, # february }, "Melbourne": { "record high C": {1: 46.4}, # february "record low C": {6: -2.8}, # july "sun": {5: 108}, # june }, "Toronto": { "mean C": {6: 22.3}, # july "snow days": {0: 12.0, 4: 0}, # january, may "record low C": {11: -30}, # december "rain mm": {7: 81.1}, # august "sun": {4: 227.7}, # may }, # for Sydney, test conversion from daily sun hours, as # specified on wiki page, into monthly hours, as used # elsewhere in the script "Sydney": { "sun": {11: 235.6, 5: 165}, # december, june "record high C": {0: 45.8}, # january "record low C": {3: 7}, # april "rain days": {5: 12.5}, "rain mm": {8: 68.3}, }, } for city, data in known_data.items(): actual_data = climate.get_climate_data(city) for key, key_data in data.items(): for month, expected_value in key_data.items(): self.assertEqual(actual_data[key][month], expected_value)
def get(self, irc, msg, args, strings): """ <text> (including <places>, <months>, <categories>) Gets climate data for <places> during <months> for <categories>. Normally at least one each of place and month are required, except script will pick most contrasting month if two cities are given. Category will default to average high temperature if not specified. Get the list of recognized <categories> with `@climate categories`. Places, months, and categories can be mixed within <text> in any order. Unrecognized words will be silently ignored (this means you can write e.g. "Toronto and Sydney high for December"). """ import climate query = climate.parse_text_query(strings) cities = query['cities'] months = query['months'] categories = query['categories'] has_category = False has_month = False for month in months: has_month = has_month or month for category in categories: has_category = has_category or categories[category] if has_category is False: # default to showing high temperature if no category is specified categories['high C'] = True has_category = True if has_month is True: data = climate.get_comparison_data(cities, months, categories) elif len(cities) == 2: # get data for all, and pick most interesting one automagically # criterion is biggest difference between the numerical values # among chosen categories for the chosen cities # for now only two cities are supported # TODO: expand to arbitrary amount - will need to round-robin # the calculations or something for i in range(len(months)): months[i] = True data = climate.get_comparison_data(cities, months, categories) # get cities' names directly from data - they are likely # different than in request (capitalization, redirects, etc) data_cities = data[data.keys()[0]].keys() comparisons = {} sums = {} for i in range(len(data_cities)): city = data_cities[i] for category,category_include in categories.items(): if not category_include: continue if category == 'location': # only non-numerical 'category' so far. cannot # be compared. detect this case more robustly if we # get more non-numerical categories continue if category not in comparisons: comparisons[category] = {} sums[category] = [] for month,month_include in enumerate(months): if not month_include: continue if not month in comparisons[category]: comparisons[category][month] = {} comparisons[category][month][city] = \ data[month][city][category] if i > 0: for m,dummy_var in enumerate(months): # calculate difference between the two cities for # each month # order within sums[category] list will be created # automagically sums[category].append(abs( \ comparisons[category][m][data_cities[i-1]] - \ comparisons[category][m][data_cities[i]])) max_month = -1 max_value = float('-inf') for category in categories: if category in sums: category_max = max(sums[category]) category_index = sums[category].index(category_max) if category_max > max_value: max_value = category_max max_month = category_index filtered_data = {} if max_month > -1: filtered_data[max_month] = data[max_month] data = filtered_data else: # not supported, return empty data = {} # output format is roughly: """October: Toronto high 10, Melbourne high 20; April: Toronto high 10, Melbourne high 15 October: Toronto high 10, low 5, Melbourne high 20, low 12; April: Toronto high 10, low 3, Melbourne high 15, low 8""" # so each month first, then each city with its categories grouped output = [] for month,month_data in data.items(): month_line = calendar.month_name[month+1] + ': ' city_lines = [] for city,city_data in month_data.items(): city_line = city + ' ' category_lines = [] for category,category_data in city_data.items(): if category in climate.PRINTED_ROW_TITLES: category_lines.append( climate.PRINTED_ROW_TITLES[category] + ' ' + str(int(round(category_data, 0)))) city_line += ', '.join(category_lines) city_lines.append(city_line) month_line += ', '.join(city_lines) output.append(month_line) output = '; '.join(output) response = '' if len(output) > 0: response = output elif len(cities) == 1 and 'location' in categories \ and categories['location'] == True: data = climate.get_climate_data(cities[0]) if 'location' in data and len(data['location']) > 0: response = data['title'] + ': ' + data['location'] if len(response) == 0: response = 'No data found or invalid query. Try @help climate get.' irc.reply(response.encode('utf-8'), prefixNick = False)