Limnoria/plugins/Geography/test.py

271 lines
9.9 KiB
Python

###
# Copyright (c) 2021, Valentin Lorentz
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import datetime
import functools
import contextlib
from unittest import skipIf
from unittest.mock import patch
try:
import pytz
except ImportError:
pytz = None
try:
import zoneinfo
except ImportError:
zoneinfo = None
from supybot.test import *
from supybot import utils
from . import wikidata
from . import nominatim
def mock(f):
@functools.wraps(f)
def newf(self):
with patch.object(wikidata, "uri_from_osmid", return_value="foo"):
with patch.object(nominatim, "search_osmids", return_value=[42]):
f(self)
return newf
class GeographyTimezoneTestCase(PluginTestCase):
plugins = ("Geography",)
@skipIf(not pytz, "pytz is not available")
@mock
def testTimezonePytz(self):
tz = pytz.timezone("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)"
)
tz = pytz.timezone("America/New_York")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone New York", r"America/New_York \(currently UTC-[45]\)"
)
tz = pytz.timezone("Canada/Newfoundland")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Newfoundland",
r"Canada/Newfoundland \(currently UTC-[23]:30\)",
)
tz = pytz.timezone("Asia/Kolkata")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
@skipIf(not zoneinfo, "Python is older than 3.9")
@mock
def testTimezoneZoneinfo(self):
tz = zoneinfo.ZoneInfo("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)"
)
tz = zoneinfo.ZoneInfo("America/New_York")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone New York", r"America/New_York \(currently UTC-[45]\)"
)
tz = zoneinfo.ZoneInfo("Canada/Newfoundland")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Newfoundland",
r"Canada/Newfoundland \(currently UTC-[23]:30\)",
)
tz = zoneinfo.ZoneInfo("Asia/Kolkata")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
@skipIf(not zoneinfo, "Python is older than 3.9")
@mock
def testTimezoneAbsolute(self):
tz = datetime.timezone(datetime.timedelta(hours=4))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC+4")
tz = datetime.timezone(datetime.timedelta(hours=4, minutes=30))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC+4:30")
tz = datetime.timezone(datetime.timedelta(hours=-4, minutes=30))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC-3:30")
@skipIf(not network, "Network test")
def testTimezoneIntegration(self):
self.assertRegexp(
"timezone Metz, France", r"Europe/Paris \(currently UTC\+[12]\)"
)
self.assertResponse("timezone Saint-Denis, La Réunion", "UTC+4")
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
self.assertRegexp("timezone Newfoundland", r"UTC-[23]:30")
class GeographyLocaltimeTestCase(PluginTestCase):
plugins = ("Geography",)
@skipIf(not pytz, "pytz is not available")
@mock
def testLocaltimePytz(self):
tz = pytz.timezone("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp("localtime Foo Bar", r".*\+0[12]00$")
@skipIf(not zoneinfo, "Python is older than 3.9")
@mock
def testLocaltimeZoneinfo(self):
tz = zoneinfo.ZoneInfo("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp("localtime Foo Bar", r".*\+0[12]00$")
@skipIf(not zoneinfo, "Python is older than 3.9")
@mock
def testLocaltimeAbsolute(self):
tz = datetime.timezone(datetime.timedelta(hours=4))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp("localtime Foo Bar", r".*\+0400$")
tz = datetime.timezone(datetime.timedelta(hours=4, minutes=30))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp("localtime Foo Bar", r".*\+0430$")
@skipIf(not network, "Network test")
def testLocaltimeIntegration(self):
self.assertRegexp("localtime Metz, France", r".*\+0[12]00$")
self.assertRegexp("localtime Saint-Denis, La Réunion", r".*\+0400$")
class GeographyWikidataTestCase(SupyTestCase):
@skipIf(not network, "Network test")
def testOsmidToTimezone(self):
self.assertEqual(
wikidata.uri_from_osmid(450381),
"http://www.wikidata.org/entity/Q22690",
)
self.assertEqual(
wikidata.uri_from_osmid(192468),
"http://www.wikidata.org/entity/Q47045",
)
@skipIf(not network, "Network test")
def testDirect(self):
# The queried object directly has a timezone property
self.assertEqual(
# New York
wikidata.timezone_from_uri("http://www.wikidata.org/entity/Q1384"),
utils.time.iana_timezone("America/New_York"),
)
@skipIf(not network, "Network test")
def testParent(self):
# The queried object does not have a TZ property but it is part
# of an object that does
self.assertEqual(
# Metz, France
wikidata.timezone_from_uri(
"http://www.wikidata.org/entity/Q22690"
),
utils.time.iana_timezone("Europe/Paris"),
)
@skipIf(not network, "Network test")
def testParentAndIgnoreSelf(self):
# The queried object has a TZ property, but it's useless to us;
# however it is part of an object that has a useful one.
self.assertEqual(
# New York City, NY
wikidata.timezone_from_uri("http://www.wikidata.org/entity/Q60"),
utils.time.iana_timezone("America/New_York"),
)
self.assertEqual(
# Paris, France
wikidata.timezone_from_uri("http://www.wikidata.org/entity/Q90"),
utils.time.iana_timezone("Europe/Paris"),
)
@skipIf(not network, "Network test")
def testParentQualifiedIgnorePreferred(self):
# The queried object does not have a TZ property,
# and is part of an object that does.
# However, this parent's 'preferred' timezone is not the
# right one, so we must make sure to select the right one
# based on P518 ('applies to part').
# La Réunion is a French region, but in UTC+4.
# France has a bunch of timezone statements, and 'Europe/Paris'
# is marked as Preferred because it is the time of metropolitan
# France. However, it is not valid for La Réunion.
self.assertEqual(
# La Réunion
wikidata.timezone_from_uri(
"http://www.wikidata.org/entity/Q17070"
),
datetime.timezone(datetime.timedelta(hours=4)),
)
class GeographyNominatimTestCase(SupyTestCase):
@skipIf(not network, "Network test")
def testSearch(self):
self.assertIn(450381, nominatim.search_osmids("Metz"))
results = nominatim.search_osmids("Metz, France")
self.assertEqual(results[0], 450381, results)
results = nominatim.search_osmids("Saint-Denis, La Réunion")
self.assertEqual(results[0], 192468, results)
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: