From b4fcd4703c599b15d47384b6fe1a111385e7f82f Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 3 Dec 2017 23:18:33 -0800 Subject: [PATCH] Again with the tests --- examples/data/config/Inventory.json | 1 + pyircbot/modules/Inventory.py | 2 +- pyircbot/modules/LinkTitler.py | 15 +++++--- pyircbot/modules/Seen.py | 1 - pyircbot/modules/Urban.py | 7 ++-- tests/modules/test_inventory.py | 58 +++++++++++++++++++++++++++++ tests/modules/test_linktitler.py | 58 +++++++++++++++++++++++++++++ tests/modules/test_seen.py | 41 ++++++++++++++++++++ tests/modules/test_urban.py | 23 ++++++++++++ 9 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 tests/modules/test_inventory.py create mode 100644 tests/modules/test_linktitler.py create mode 100644 tests/modules/test_seen.py create mode 100644 tests/modules/test_urban.py diff --git a/examples/data/config/Inventory.json b/examples/data/config/Inventory.json index 716c9f2..073dc3f 100644 --- a/examples/data/config/Inventory.json +++ b/examples/data/config/Inventory.json @@ -5,6 +5,7 @@ "swap_msg": "\u0001ACTION takes %(adjective)s%(recv_item)s but drops %(drop_item)s\u0010", "dupe_msg": "No thanks, I've already got %(item)s", "adjectives": [ + "a", "some", "the", "an", diff --git a/pyircbot/modules/Inventory.py b/pyircbot/modules/Inventory.py index fd4ba75..e3aba4a 100755 --- a/pyircbot/modules/Inventory.py +++ b/pyircbot/modules/Inventory.py @@ -74,7 +74,7 @@ class Inventory(ModuleBase): def add_item(self, donor, itemName): dropped = [] - c = self.db.query("SELECT * FROM `inventory` ORDER BY RANDOM() LIMIT %s,1000000" % self.config["limit"]) + c = self.db.query("SELECT * FROM `inventory` ORDER BY RANDOM() LIMIT %s,1000000" % str(int(self.config["limit"]) - 1)) while True: row = c.fetchone() if row is None: diff --git a/pyircbot/modules/LinkTitler.py b/pyircbot/modules/LinkTitler.py index bb9e4f8..d0b18e8 100755 --- a/pyircbot/modules/LinkTitler.py +++ b/pyircbot/modules/LinkTitler.py @@ -56,8 +56,7 @@ class LinkTitler(ModuleBase): if submissionId in done: continue done.append(submissionId) - r = praw.Reddit(**self.config["reddit"]) - submission = r.submission(id=submissionId) + submission = self.get_reddit_submission(submissionId) msg = "šŸ‘½ \x02\x031,15REDDIT\x0f\x02 :: %(title)s \x02on \x02%(domain)s%(nsfw)s\x02 - points " \ "\x02%(points)s\x02 (%(percent)sā†‘) - comments \x02%(comments)s\x02 - by \x02%(author)s\x02 on " \ "\x02%(date)s\x02" % { @@ -106,6 +105,10 @@ class LinkTitler(ModuleBase): return + def get_reddit_submission(self, subid): + r = praw.Reddit(**self.config["reddit"]) + return r.submission(id=subid) + def nicesize(self, numBytes): "Return kb or plain bytes" if numBytes > 1024: @@ -160,10 +163,12 @@ class LinkTitler(ModuleBase): ) # http://stackoverflow.com/a/16742742 return ISO_8601_period_rx.match(stamp).groupdict() - def get_video_description(self, vid_id): - apidata = get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s' - '&key=%s' % (vid_id, self.config["youtube_api_key"])).json() + def _get_video_description_api(self, vid_id): + return get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s' + '&key=%s' % (vid_id, self.config["youtube_api_key"])).json() + def get_video_description(self, vid_id): + apidata = self._get_video_description_api(vid_id) if not apidata['pageInfo']['totalResults']: return diff --git a/pyircbot/modules/Seen.py b/pyircbot/modules/Seen.py index e7c4ac5..9ec019b 100755 --- a/pyircbot/modules/Seen.py +++ b/pyircbot/modules/Seen.py @@ -26,7 +26,6 @@ class Seen(ModuleBase): self.log.info("Seen: Creating database") # if no, create it. c.execute("CREATE TABLE `seen` (`nick` VARCHAR(32), `date` INTEGER, PRIMARY KEY(`nick`))") - self.x = "asdf" @hook("PRIVMSG") def recordSeen(self, message, command): diff --git a/pyircbot/modules/Urban.py b/pyircbot/modules/Urban.py index 808efef..728274b 100755 --- a/pyircbot/modules/Urban.py +++ b/pyircbot/modules/Urban.py @@ -8,7 +8,7 @@ """ from pyircbot.modulebase import ModuleBase, command -from requests import get +import requests from pyircbot.modules.ModInfo import info @@ -17,9 +17,8 @@ class Urban(ModuleBase): @info("urban lookup an urban dictionary definition", cmds=["urban", "u"]) @command("urban", "u") def urban(self, msg, cmd): - print(cmd) - definitions = get("http://www.urbandictionary.com/iphone/search/define", - params={"term": cmd.args_str}).json()["list"] + definitions = requests.get("http://www.urbandictionary.com/iphone/search/define", + params={"term": cmd.args_str}).json()["list"] if len(definitions) == 0: self.bot.act_PRIVMSG(msg.args[0], "Urban definition: no results!") else: diff --git a/tests/modules/test_inventory.py b/tests/modules/test_inventory.py new file mode 100644 index 0000000..357eaed --- /dev/null +++ b/tests/modules/test_inventory.py @@ -0,0 +1,58 @@ +import pytest +from contextlib import closing +from unittest.mock import call +from tests.lib import * # NOQA - fixtures + + +@pytest.fixture +def invbot(fakebot): + """ + Provide a bot loaded with the Calc module. Clear the database. + """ + fakebot.botconfig["module_configs"]["Inventory"] = { + "limit": 2, + "recv_msg": "Oh, thanks, I'll keep %(adjective)s%(item)s safe", + "inv_msg": "\u0001ACTION is carrying %(itemlist)s\u0001", + "swap_msg": "\u0001ACTION takes %(adjective)s%(recv_item)s but drops %(drop_item)s\u0010", + "dupe_msg": "No thanks, I've already got %(item)s", + "adjectives": [ + "a", + "some", + "the", + "an", + "these" + ] + } + fakebot.loadmodule("SQLite") + with closing(fakebot.moduleInstances["SQLite"].opendb("inventory.db")) as db: + db.query("DROP TABLE IF EXISTS `inventory`;") + fakebot.loadmodule("Inventory") + return fakebot + + +def test_inv_empty(invbot): + invbot.feed_line(".inventory") + invbot.act_PRIVMSG.assert_called_once_with('#test', '\x01ACTION is carrying nothing!\x01') + + +def test_inv_basic(invbot): + invbot.feed_line(".have a foobar") + invbot.act_PRIVMSG.assert_called_once_with('#test', "Oh, thanks, I'll keep this foobar safe") + + +def test_inv_full(invbot): + invbot.feed_line(".have a foobarA") + invbot.act_PRIVMSG.assert_called_once_with('#test', "Oh, thanks, I'll keep this foobarA safe") + invbot.act_PRIVMSG.reset_mock() + + invbot.feed_line(".have a foobarB") + invbot.act_PRIVMSG.assert_called_once_with('#test', "Oh, thanks, I'll keep this foobarB safe") + invbot.act_PRIVMSG.reset_mock() + + invbot.feed_line(".inventory") + invbot.act_PRIVMSG.assert_called_once_with('#test', "\x01ACTION is carrying foobarA, foobarB\x01") + invbot.act_PRIVMSG.reset_mock() + + invbot.feed_line(".have a foobarC") + assert invbot.act_PRIVMSG.mock_calls[0] == call('#test', '\x01ACTION takes a foobarC but drops foobarA\x10') \ + or invbot.act_PRIVMSG.mock_calls[0] == call('#test', '\x01ACTION takes a foobarC but drops foobarB\x10') diff --git a/tests/modules/test_linktitler.py b/tests/modules/test_linktitler.py new file mode 100644 index 0000000..40f5322 --- /dev/null +++ b/tests/modules/test_linktitler.py @@ -0,0 +1,58 @@ +import pytest +from time import sleep +from unittest.mock import MagicMock +from tests.lib import * # NOQA - fixtures + + +@pytest.fixture +def linkbot(fakebot): + """ + Provide a bot loaded with the Calc module. Clear the database. + """ + fakebot.botconfig["module_configs"]["LinkTitler"] = { + "reddit": { + "user_agent": "pyircbot3 by /u/(changeme)", + "client_id": "test", + "client_secret": "test", + "username": "test", + "password": "test" + }, + "youtube_api_key": "test" + } + + fakebot.loadmodule("LinkTitler") + return fakebot + + +def test_link_html_title(linkbot, monkeypatch): + monkeypatch.setattr(linkbot.moduleInstances["LinkTitler"], "url_headers", lambda url: {"Content-Type": "text/html"}) + monkeypatch.setattr(linkbot.moduleInstances["LinkTitler"], "url_htmltitle", lambda url: "foo bar title") + linkbot.feed_line("http://example.com/") + sleep(0.1) + linkbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: \x02foo bar title\x02') + + +def test_youtube(linkbot, monkeypatch): + monkeypatch.setattr(linkbot.moduleInstances["LinkTitler"], "_get_video_description_api", + lambda vid_id: {"kind": "youtube#videoListResponse", "etag": "\"xxxx\"", "pageInfo": {"totalResults": 1, "resultsPerPage": 1}, "items": [{"kind": "youtube#video", "etag": "\"xxxx\"", "id": "SvArQjKr488", "snippet": {"publishedAt": "2009-06-16T06:12:24.000Z", "channelId": "UCgeRcbMDaVTwEHJvO6-hFjQ", "title": "Liquid X - RIoT Rich", "description": "blah", "thumbnails": {"default": {"url": "https://i.ytimg.com/vi/SvArQjKr488/default.jpg", "width": 120, "height": 90}, "medium": {"url": "https://i.ytimg.com/vi/SvArQjKr488/mqdefault.jpg", "width": 320, "height": 180}, "high": {"url": "https://i.ytimg.com/vi/SvArQjKr488/hqdefault.jpg", "width": 480, "height": 360}}, "channelTitle": "Bieji", "tags": ["liquid", "riot", "rich", "digital", "gangster", "nerd", "life", "rit", "Rochester", "Institute", "of", "Technology"], "categoryId": "10", "liveBroadcastContent": "none", "localized": {"title": "Liquid X - RIoT Rich", "description": "blah"}}, "contentDetails": {"duration": "PT5M39S", "dimension": "2d", "definition": "sd", "caption": "false", "licensedContent": False, "projection": "rectangular"}, "statistics": {"viewCount": "17141", "likeCount": "193", "dislikeCount": "8", "favoriteCount": "0", "commentCount": "31"}}]}) + linkbot.feed_line("blah blah https://www.youtube.com/watch?v=SvArQjKr488 blah blah") + sleep(0.1) + linkbot.act_PRIVMSG.assert_called_once_with('#test', '\x02\x031,0You\x0f\x030,4Tube\x02\x0f :: \x02Liquid X - RIoT Rich\x02 - length \x025m 39s\x02 - rated \x024.80/5\x02 - \x0217,141\x02 views - by \x02Bieji\x02 on \x022009.06.16\x02') + + +def test_reddit(linkbot, monkeypatch): + fake = MagicMock() + fake.title = "TIL X11 forwarding is (basically) as simple as running 'ssh -X user@hostname'" + fake.domain = "self.todayilearned" + fake.ups = 6 + fake.upvote_ratio = 0.67 + fake.over_18 = False + fake.num_comments = 6 + fake.author.name = "drfrogsplat" + fake.created = 1260361210 + + monkeypatch.setattr(linkbot.moduleInstances["LinkTitler"], "get_reddit_submission", lambda sub_id: fake) + linkbot.feed_line("blah blah https://www.reddit.com/r/todayilearned/comments/acm26/til_x11_forwarding_is_basically_as_simple_as/ blah blah") + sleep(0.1) + linkbot.act_PRIVMSG.assert_called_once_with('#test', "šŸ‘½ \x02\x031,15REDDIT\x0f\x02 :: TIL X11 forwarding is (basically) as simple as running 'ssh -X user@hostname' \x02on \x02self.todayilearned\x02 - points \x026\x02 (67%ā†‘) - comments \x026\x02 - by \x02drfrogsplat\x02 on \x022009.12.09\x02") + diff --git a/tests/modules/test_seen.py b/tests/modules/test_seen.py new file mode 100644 index 0000000..37750cc --- /dev/null +++ b/tests/modules/test_seen.py @@ -0,0 +1,41 @@ +import pytest +from contextlib import closing +from unittest.mock import call +from tests.lib import * # NOQA - fixtures +import sqlite3 + + +@pytest.fixture +def seenbot(fakebot): + """ + Provide a bot loaded with the Seen module + """ + fakebot.botconfig["module_configs"]["Seen"] = { + "timezone": "UTC", + "add_hours": 0 + } + fakebot.loadmodule("Seen") + return fakebot + + +def test_seen(seenbot): + seenbot.feed_line("blah") + seenbot.act_PRIVMSG.assert_not_called() + dbpath = seenbot.moduleInstances["Seen"].getFilePath('database.sql3') + seenbot.unloadmodule("Seen") + + with closing(sqlite3.connect(dbpath)) as db: + with closing(db.cursor()) as c: + c.execute("UPDATE `seen` SET `date`=1512369350.460798 WHERE `nick`='chatter';") + assert c.rowcount == 1 + db.commit() + + seenbot.loadmodule("Seen") + seenbot.feed_line(".seen chatter") + seenbot.act_PRIVMSG.assert_called_once_with('#test', "I last saw chatter on 12/03/17 at 10:35 PM (UTC).") + + +def test_notseen(seenbot): + seenbot.feed_line(".seen notme") + seenbot.act_PRIVMSG.assert_called_once_with('#test', "Sorry, I haven't seen notme!") + diff --git a/tests/modules/test_urban.py b/tests/modules/test_urban.py new file mode 100644 index 0000000..dd4015d --- /dev/null +++ b/tests/modules/test_urban.py @@ -0,0 +1,23 @@ +import pytest +from unittest.mock import MagicMock +from tests.lib import * # NOQA - fixtures +import requests + + +@pytest.fixture +def urbanbot(fakebot): + """ + Provide a bot loaded with the Seen module + """ + fakebot.loadmodule("Urban") + return fakebot + + +def test_seen(urbanbot, monkeypatch): + def fakeget(url, params=None): + r = MagicMock() + r.json = lambda: {"list": [{"definition": "A process for testing things", "defid": 708924}]} + return r + monkeypatch.setattr(requests, 'get', fakeget) + urbanbot.feed_line(".u test") + urbanbot.act_PRIVMSG.assert_called_once_with('#test', "Urban definition: A process for testing things - http://urbanup.com/708924")