From 03c12be3f35eef49673aed94a52946a4cdc5ed0a Mon Sep 17 00:00:00 2001 From: Florian Strzelecki Date: Tue, 10 Dec 2019 13:52:33 +0100 Subject: [PATCH 1/2] test: remove test_tools from the test suite --- test/modules/test_modules_remind.py | 26 +++++++------ test/test_db.py | 16 +++++--- test/test_module.py | 46 ++++++++++++++--------- test/test_regression.py | 57 ++++++++++++++++------------- test/test_trigger.py | 54 +++++++++++++++------------ test/tools/test_tools_jobs.py | 19 +++++----- 6 files changed, 126 insertions(+), 92 deletions(-) diff --git a/test/modules/test_modules_remind.py b/test/modules/test_modules_remind.py index 54d1c8c64a..e897bc61ee 100644 --- a/test/modules/test_modules_remind.py +++ b/test/modules/test_modules_remind.py @@ -8,17 +8,18 @@ import pytest import pytz -from sopel import test_tools from sopel.modules import remind -@pytest.fixture -def sopel(): - bot = test_tools.MockSopel('Sopel') - bot.config.basename = 'default' - bot.config.core.owner = 'Admin' - bot.config.core.host = 'chat.freenode.net' - return bot +TMP_CONFIG = """ +[core] +owner = Admin +nick = Sopel +enable = + coretasks + remind +host = chat.freenode.net +""" WEIRD_MESSAGE = ( @@ -313,10 +314,13 @@ def test_timereminder_get_duration_error(date1, date2, date3): reminder.get_duration(test_today) -def test_get_filename(sopel): - filename = remind.get_filename(sopel) +def test_get_filename(configfactory, botfactory): + tmpconfig = configfactory('default.ini', TMP_CONFIG) + mockbot = botfactory(tmpconfig) + + filename = remind.get_filename(mockbot) assert filename == os.path.join( - sopel.config.core.homedir, + mockbot.config.core.homedir, 'default.reminders.db') diff --git a/test/test_db.py b/test/test_db.py index 78bc8bfd1c..c47266fca7 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,7 +15,6 @@ import pytest from sopel.db import SopelDB -from sopel.test_tools import MockConfig from sopel.tools import Identifier db_filename = tempfile.mkstemp()[1] @@ -31,11 +30,18 @@ iterkeys = dict.iterkeys +TMP_CONFIG = """ +[core] +owner = Embolalia +db_filename = {db_filename} +""" + + @pytest.fixture -def db(): - config = MockConfig() - config.core.db_filename = db_filename - db = SopelDB(config) +def db(configfactory): + content = TMP_CONFIG.format(db_filename=db_filename) + settings = configfactory('default.cfg', content) + db = SopelDB(settings) # TODO add tests to ensure db creation works properly, too. return db diff --git a/test/test_module.py b/test/test_module.py index 6a59606d94..164f486d39 100644 --- a/test/test_module.py +++ b/test/test_module.py @@ -5,47 +5,59 @@ import pytest from sopel.trigger import PreTrigger, Trigger -from sopel.test_tools import MockSopel, MockSopelWrapper -from sopel.tools import Identifier -from sopel import module +from sopel import module, tools -@pytest.fixture -def sopel(): - bot = MockSopel('Sopel') - bot.config.core.owner = 'Bar' - return bot +TMP_CONFIG = """ +[core] +owner = Bar +nick = Sopel +enable = coretasks +""" + + +FOO_MESSAGE = ':Foo!foo@example.com PRIVMSG #Sopel :Hello, world' +FOO_PRIV_MESSAGE = ':Foo!foo@example.com PRIVMSG Sopel :Hello, world' @pytest.fixture -def bot(sopel, pretrigger): - bot = MockSopelWrapper(sopel, pretrigger) - bot.channels[Identifier('#Sopel')].privileges[Identifier('Foo')] = module.VOICE +def bot(configfactory, botfactory, triggerfactory, ircfactory): + settings = configfactory('default.cfg', TMP_CONFIG) + mockbot = botfactory.preloaded(settings) + mockserver = ircfactory(mockbot) + + bot = triggerfactory.wrapper(mockbot, FOO_MESSAGE) + mockserver.channel_joined('#Sopel') + mockserver.join('Foo', '#Sopel') + mockserver.mode_set('#Sopel', '+v', ['Foo']) + return bot @pytest.fixture def pretrigger(): - line = ':Foo!foo@example.com PRIVMSG #Sopel :Hello, world' - return PreTrigger(Identifier('Foo'), line) + return PreTrigger(tools.Identifier('Foo'), FOO_MESSAGE) @pytest.fixture def pretrigger_pm(): - line = ':Foo!foo@example.com PRIVMSG Sopel :Hello, world' - return PreTrigger(Identifier('Foo'), line) + return PreTrigger(tools.Identifier('Foo'), FOO_PRIV_MESSAGE) @pytest.fixture def trigger_owner(bot): line = ':Bar!bar@example.com PRIVMSG #Sopel :Hello, world' - return Trigger(bot.config, PreTrigger(Identifier('Bar'), line), None) + return Trigger(bot.config, PreTrigger(tools.Identifier('Bar'), line), None) @pytest.fixture def trigger_account(bot): line = '@account=egg :egg!egg@eg.gs PRIVMSG #Sopel :Hello, world' - return Trigger(bot.config, PreTrigger(Identifier('egg'), line), None, 'egg') + return Trigger( + bot.config, + PreTrigger(tools.Identifier('egg'), line), + None, + 'egg') @pytest.fixture diff --git a/test/test_regression.py b/test/test_regression.py index 6a53fb17b4..2bc39edcbf 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -2,43 +2,50 @@ """Regression tests""" from __future__ import unicode_literals, absolute_import, print_function, division -import pytest +from sopel import coretasks, tools -from sopel import coretasks -from sopel.tools import Identifier -from sopel.test_tools import MockSopel, MockSopelWrapper -from sopel.trigger import PreTrigger, Trigger +TMP_CONFIG = """ +[core] +owner = testnick +nick = Sopel +enable = coretasks +""" -@pytest.fixture -def sopel(): - bot = MockSopel("Sopel") - return bot - -def test_bot_legacy_permissions(sopel): +def test_bot_legacy_permissions(configfactory, botfactory, triggerfactory): """ Make sure permissions match after being updated from both RPL_NAMREPLY and RPL_WHOREPLY, #1482 """ - - nick = Identifier("Admin") + mockbot = botfactory(configfactory('default.cfg', TMP_CONFIG)) + nick = tools.Identifier("Admin") # RPL_NAMREPLY - pretrigger = PreTrigger("Foo", ":test.example.com 353 Foo = #test :Foo ~@Admin") - trigger = Trigger(sopel.config, pretrigger, None) - coretasks.handle_names(MockSopelWrapper(sopel, trigger), trigger) + mockwrapper = triggerfactory.wrapper( + mockbot, ":test.example.com 353 Foo = #test :Foo ~@Admin") + coretasks.handle_names(mockwrapper, mockwrapper._trigger) + + assert '#test' in mockbot.channels + assert nick in mockbot.channels["#test"].privileges + + assert '#test' in mockbot.privileges + assert nick in mockbot.privileges["#test"] + + channel_privileges = mockbot.channels["#test"].privileges[nick] + privileges = mockbot.privileges["#test"][nick] - assert sopel.channels["#test"].privileges[nick] == sopel.privileges["#test"][nick] + assert channel_privileges == privileges # RPL_WHOREPLY - pretrigger = PreTrigger( - "Foo", - ":test.example.com 352 Foo #test ~Admin adminhost test.example.com Admin Hr~ :0 Admin", - ) - trigger = Trigger(sopel.config, pretrigger, None) - coretasks.recv_who(MockSopelWrapper(sopel, trigger), trigger) + mockwrapper = triggerfactory.wrapper( + mockbot, + ":test.example.com 352 Foo #test " + "~Admin adminhost test.example.com Admin Hr~ :0 Admin") + coretasks.recv_who(mockwrapper, mockwrapper._trigger) - assert sopel.channels["#test"].privileges[nick] == sopel.privileges["#test"][nick] + channel_privileges = mockbot.channels["#test"].privileges[nick] + privileges = mockbot.privileges["#test"][nick] - assert sopel.users.get(nick) is not None + assert channel_privileges == privileges + assert mockbot.users.get(nick) is not None diff --git a/test/test_trigger.py b/test/test_trigger.py index c81fcd2b1d..43d4e8fbfc 100644 --- a/test/test_trigger.py +++ b/test/test_trigger.py @@ -6,11 +6,27 @@ import pytest import datetime -from sopel.test_tools import MockConfig from sopel.trigger import PreTrigger, Trigger from sopel.tools import Identifier +TMP_CONFIG = """ +[core] +owner = Foo +admins = + Bar +""" + + +TMP_CONFIG_ACCOUNT = """ +[core] +owner = Foo +owner_account = bar +admins = + Bar +""" + + @pytest.fixture def nick(): return Identifier('Sopel') @@ -154,12 +170,11 @@ def test_ircv3_extended_join_pretrigger(nick): assert pretrigger.sender == Identifier('#Sopel') -def test_ircv3_extended_join_trigger(nick): +def test_ircv3_extended_join_trigger(nick, configfactory): line = ':Foo!foo@example.com JOIN #Sopel bar :Real Name' pretrigger = PreTrigger(nick, line) - config = MockConfig() - config.core.owner_account = 'bar' + config = configfactory('default.cfg', TMP_CONFIG) fakematch = re.match('.*', line) @@ -182,22 +197,19 @@ def test_ircv3_extended_join_trigger(nick): assert trigger.admin is True -def test_ircv3_intents_trigger(nick): - line = '@intent=ACTION :Foo!foo@example.com PRIVMSG #Sopel :Hello, world' +def test_ircv3_intents_trigger(nick, configfactory): + line = '@intent=ACTION :Foo!bar@example.com PRIVMSG #Sopel :Hello, world' pretrigger = PreTrigger(nick, line) - config = MockConfig() - config.core.owner = 'Foo' - config.core.admins = ['Bar'] - + config = configfactory('default.cfg', TMP_CONFIG) fakematch = re.match('.*', line) trigger = Trigger(config, pretrigger, fakematch) assert trigger.sender == '#Sopel' assert trigger.raw == line assert trigger.is_privmsg is False - assert trigger.hostmask == 'Foo!foo@example.com' - assert trigger.user == 'foo' + assert trigger.hostmask == 'Foo!bar@example.com' + assert trigger.user == 'bar' assert trigger.nick == Identifier('Foo') assert trigger.host == 'example.com' assert trigger.event == 'PRIVMSG' @@ -207,18 +219,16 @@ def test_ircv3_intents_trigger(nick): assert trigger.groupdict == fakematch.groupdict assert trigger.args == ['#Sopel', 'Hello, world'] assert trigger.tags == {'intent': 'ACTION'} + assert trigger.account is None assert trigger.admin is True assert trigger.owner is True -def test_ircv3_account_tag_trigger(nick): - line = '@account=Foo :Nick_Is_Not_Foo!foo@example.com PRIVMSG #Sopel :Hello, world' +def test_ircv3_account_tag_trigger(nick, configfactory): + line = '@account=bar :Nick_Is_Not_Foo!foo@example.com PRIVMSG #Sopel :Hello, world' pretrigger = PreTrigger(nick, line) - config = MockConfig() - config.core.owner_account = 'Foo' - config.core.admins = ['Bar'] - + config = configfactory('default.cfg', TMP_CONFIG_ACCOUNT) fakematch = re.match('.*', line) trigger = Trigger(config, pretrigger, fakematch) @@ -226,14 +236,10 @@ def test_ircv3_account_tag_trigger(nick): assert trigger.owner is True -def test_ircv3_server_time_trigger(nick): +def test_ircv3_server_time_trigger(nick, configfactory): line = '@time=2016-01-09T03:15:42.000Z :Foo!foo@example.com PRIVMSG #Sopel :Hello, world' pretrigger = PreTrigger(nick, line) - - config = MockConfig() - config.core.owner = 'Foo' - config.core.admins = ['Bar'] - + config = configfactory('default.cfg', TMP_CONFIG) fakematch = re.match('.*', line) trigger = Trigger(config, pretrigger, fakematch) diff --git a/test/tools/test_tools_jobs.py b/test/tools/test_tools_jobs.py index f45861a106..b790286068 100644 --- a/test/tools/test_tools_jobs.py +++ b/test/tools/test_tools_jobs.py @@ -5,21 +5,20 @@ import datetime import time -import pytest - -from sopel import test_tools from sopel.tools import jobs -@pytest.fixture -def sopel(): - bot = test_tools.MockSopel('Sopel') - bot.config.core.owner = 'Bar' - return bot +TMP_CONFIG = """ +[core] +owner = Bar +nick = Sopel +enable = coretasks +""" -def test_jobscheduler_stop(sopel): - scheduler = jobs.JobScheduler(sopel) +def test_jobscheduler_stop(configfactory, botfactory): + mockbot = botfactory(configfactory('config.cfg', TMP_CONFIG)) + scheduler = jobs.JobScheduler(mockbot) assert not scheduler.stopping.is_set(), 'Stopping must not be set at init' scheduler.stop() From ba9bf8448ea1403144966110a0dc0f767b811745 Mon Sep 17 00:00:00 2001 From: Florian Strzelecki Date: Tue, 10 Dec 2019 14:10:54 +0100 Subject: [PATCH 2/2] test: deprecate MockConfig, MockSopel, and MockSopelWrapper --- sopel/test_tools.py | 69 +++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/sopel/test_tools.py b/sopel/test_tools.py index 45d3ff934c..aaaa17b3d1 100644 --- a/sopel/test_tools.py +++ b/sopel/test_tools.py @@ -39,6 +39,7 @@ class MockConfig(sopel.config.Config): + @sopel.tools.deprecated('use configfactory fixture instead', '7.0', '8.0') def __init__(self): self.filename = tempfile.mkstemp()[1] self.parser = ConfigParser.RawConfigParser(allow_no_value=True) @@ -54,6 +55,7 @@ def define_section(self, name, cls_): class MockSopel(object): + @sopel.tools.deprecated('use botfactory fixture instead', '7.0', '8.0') def __init__(self, nick, admin=False, owner=False): self.nick = nick self.user = "sopel" @@ -115,7 +117,17 @@ def search_url_callbacks(self, url): class MockSopelWrapper(SopelWrapper): - pass + @sopel.tools.deprecated('use sopel.bot.SopelWrapper instead', '7.0', '8.0') + def __init__(self, *args, **kwargs): + super(MockSopelWrapper, self).__init__(*args, **kwargs) + + +TEST_CONFIG = """ +[core] +nick = {name} +owner = {owner} +admin = {admin} +""" def get_example_test(tested_func, msg, results, privmsg, admin, @@ -138,8 +150,16 @@ def get_example_test(tested_func, msg, results, privmsg, admin, :return: a test function for ``tested_func`` :rtype: ``callable`` """ - def test(): - bot = MockSopel("NickName", admin=admin, owner=owner) + def test(configfactory, botfactory, ircfactory): + test_config = TEST_CONFIG.format( + name='NickName', + admin=admin, + owner=owner, + ) + settings = configfactory('default.cfg', test_config) + bot = botfactory(settings) + server = ircfactory(bot) + server.channel_joined('#Sopel') match = None if hasattr(tested_func, "commands"): @@ -152,38 +172,51 @@ def test(): sender = bot.nick if privmsg else "#channel" hostmask = "%s!%s@%s" % (bot.nick, "UserName", "example.com") + # TODO enable message tags full_message = ':{} PRIVMSG {} :{}'.format(hostmask, sender, msg) - pretrigger = sopel.trigger.PreTrigger(bot.nick, full_message) - trigger = sopel.trigger.Trigger(bot.config, pretrigger, match) + trigger = sopel.trigger.Trigger(bot.settings, pretrigger, match) + pattern = re.compile(r'^%s: ' % re.escape(bot.nick)) + # setup module module = sys.modules[tested_func.__module__] if hasattr(module, 'setup'): module.setup(bot) def isnt_ignored(value): """Return True if value doesn't match any re in ignore list.""" - for ignored_line in ignore: - if re.match(ignored_line, value): - return False - return True + return not any( + re.match(ignored_line, value) + for ignored_line in ignore) expected_output_count = 0 for _i in range(repeat): expected_output_count += len(results) - wrapper = MockSopelWrapper(bot, trigger) + wrapper = SopelWrapper(bot, trigger) tested_func(wrapper, trigger) - wrapper.output = list(filter(isnt_ignored, wrapper.output)) - assert len(wrapper.output) == expected_output_count - for result, output in zip(results, wrapper.output): - if type(output) is bytes: - output = output.decode('utf-8') + + output_triggers = ( + sopel.trigger.PreTrigger(bot.nick, message.decode('utf-8')) + for message in wrapper.backend.message_sent + ) + output_texts = ( + # subtract "Sopel: " when necessary + pattern.sub('', output_trigger.args[-1]) + for output_trigger in output_triggers + ) + outputs = [text for text in output_texts if isnt_ignored(text)] + + # output length + assert len(outputs) == expected_output_count + + # output content + for expected, output in zip(results, outputs): if use_regexp: - if not re.match(result, output): - assert result == output + if not re.match(expected, output): + assert expected == output else: - assert result == output + assert expected == output return test