test_main

Tests for the main launcher

  1#! /usr/bin/env python3
  2# -*- coding: utf-8 -*-
  3
  4"""
  5Tests for the main launcher
  6"""
  7
  8import argparse
  9import contextlib
 10import io
 11import os
 12import sys
 13from unittest import TestCase
 14
 15from main import mergeOptionsWithConfigFile, parseOptions, determineProtocol, MSG_VERSION, createBot
 16from irc_bot import IrcBot
 17from discord_bot import DiscordBot
 18
 19
 20class ConfigMergeTest(TestCase):
 21    """Test merging a config file with a dict"""
 22
 23    def assertMergedConfig(self, config, fileName, expected):
 24        """Merge dict with file and assert the result matches expected"""
 25        configFile = os.path.join("testConfigs", f"{fileName}.json")
 26        actualConfig = mergeOptionsWithConfigFile(config, configFile)
 27        self.assertEqual(actualConfig, expected)
 28
 29
 30    def testEmpty(self):
 31        """Empty into empty should equal empty"""
 32        self.assertMergedConfig({}, "empty", {})
 33
 34    def testAddSingleParameter(self):
 35        """Add a single parameter to an empty config"""
 36        new = {
 37            "single": "test"
 38        }
 39        expected = {
 40            "single": "test"
 41        }
 42        self.assertMergedConfig(new, "empty", expected)
 43
 44    def testAddSingleParameterOverwrites(self):
 45        """Add a single parameter to a config that contains it already"""
 46        new = {
 47            "single": "test"
 48        }
 49        expected = {
 50            "single": "original"
 51        }
 52        self.assertMergedConfig(new, "single", expected)
 53
 54    def testAddSingleParameterMerges(self):
 55        """Add a single parameter to a config that contains a different one"""
 56        new = {
 57            "new": "test"
 58        }
 59        expected = {
 60            "new" : "test",
 61            "single" : "original"
 62        }
 63        self.assertMergedConfig(new, "single", expected)
 64
 65class ConfigParseTest(TestCase):
 66    """Test parsing options into a config"""
 67
 68    SAMPLE_CONFIG = {
 69        "server": "localhost",
 70        "port": 6667,
 71        "channel": "#dbwebb",
 72        "nick": "marvin",
 73        "realname": "Marvin The All Mighty dbwebb-bot",
 74        "ident": "password"
 75    }
 76
 77    CHANGED_CONFIG = {
 78        "server": "remotehost",
 79        "port": 1234,
 80        "channel": "#db-o-webb",
 81        "nick": "imposter",
 82        "realname": "where is marvin?",
 83        "ident": "identify"
 84    }
 85
 86    def testOverrideHardcodedParameters(self):
 87        """Test that all the hard coded parameters can be overridden from commandline"""
 88        for parameter in ["server", "port", "channel", "nick", "realname", "ident"]:
 89            sys.argv = ["./main.py", f"--{parameter}", str(self.CHANGED_CONFIG.get(parameter))]
 90            actual = parseOptions(self.SAMPLE_CONFIG)
 91            self.assertEqual(actual.get(parameter), self.CHANGED_CONFIG.get(parameter))
 92
 93    def testOverrideMultipleParameters(self):
 94        """Test that multiple parameters can be overridden from commandline"""
 95        sys.argv = ["./main.py", "--server", "dbwebb.se", "--port", "5432"]
 96        actual = parseOptions(self.SAMPLE_CONFIG)
 97        self.assertEqual(actual.get("server"), "dbwebb.se")
 98        self.assertEqual(actual.get("port"), 5432)
 99
100    def testOverrideWithFile(self):
101        """Test that parameters can be overridden with the --config option"""
102        configFile = os.path.join("testConfigs", "server.json")
103        sys.argv = ["./main.py", "--config", configFile]
104        actual = parseOptions(self.SAMPLE_CONFIG)
105        self.assertEqual(actual.get("server"), "irc.dbwebb.se")
106
107    def testOverridePrecedenceConfigFirst(self):
108        """Test that proper precedence is considered. From most to least significant it should be:
109        explicit parameter -> parameter in --config file -> default """
110
111        configFile = os.path.join("testConfigs", "server.json")
112        sys.argv = ["./main.py", "--config", configFile, "--server", "important.com"]
113        actual = parseOptions(self.SAMPLE_CONFIG)
114        self.assertEqual(actual.get("server"), "important.com")
115
116    def testOverridePrecedenceParameterFirst(self):
117        """Test that proper precedence is considered. From most to least significant it should be:
118        explicit parameter -> parameter in --config file -> default """
119
120        configFile = os.path.join("testConfigs", "server.json")
121        sys.argv = ["./main.py", "--server", "important.com", "--config", configFile]
122        actual = parseOptions(self.SAMPLE_CONFIG)
123        self.assertEqual(actual.get("server"), "important.com")
124
125    def testBannedParameters(self):
126        """Don't allow config, help and version as parameters, as those options are special"""
127        for bannedParameter in ["config", "help", "version"]:
128            with self.assertRaises(argparse.ArgumentError):
129                parseOptions({bannedParameter: "test"})
130
131
132class FormattingTest(TestCase):
133    """Test the parameters that cause printouts"""
134
135    USAGE = ("usage: main.py [-h] [-v] [--config CONFIG] [--server SERVER] [--port PORT] "
136             "[--channel CHANNEL] [--nick NICK] [--realname REALNAME] [--ident IDENT]\n"
137             "               [{irc,discord}]\n")
138
139    OPTIONS = ("positional arguments:\n  {irc,discord}\n\n"
140               "options:\n"
141               "  -h, --help           show this help message and exit\n"
142               "  -v, --version\n"
143               "  --config CONFIG\n"
144               "  --server SERVER\n"
145               "  --port PORT\n"
146               "  --channel CHANNEL\n"
147               "  --nick NICK\n"
148               "  --realname REALNAME\n"
149               "  --ident IDENT")
150
151
152    @classmethod
153    def setUpClass(cls):
154        """Set the terminal width to 160 to prevent the tests from failing on small terminals"""
155        os.environ["COLUMNS"] = "160"
156
157
158    def assertPrintOption(self, options, returnCode, output):
159        """Assert that parseOptions returns a certain code and prints a certain output"""
160        with self.assertRaises(SystemExit) as e:
161            s = io.StringIO()
162            with contextlib.redirect_stdout(s):
163                sys.argv = ["./main.py"] + [options]
164                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
165        self.assertEqual(e.exception.code, returnCode)
166        self.assertEqual(s.getvalue(), output+"\n") # extra newline added by print()
167
168
169    def testHelpPrintout(self):
170        """Test that a help is printed when providing the --help flag"""
171        self.assertPrintOption("--help", 0, f"{self.USAGE}\n{self.OPTIONS}")
172
173    def testHelpPrintoutShort(self):
174        """Test that a help is printed when providing the -h flag"""
175        self.assertPrintOption("-h", 0, f"{self.USAGE}\n{self.OPTIONS}")
176
177    def testVersionPrintout(self):
178        """Test that the version is printed when provided the --version flag"""
179        self.assertPrintOption("--version", 0, MSG_VERSION)
180
181    def testVersionPrintoutShort(self):
182        """Test that the version is printed when provided the -v flag"""
183        self.assertPrintOption("-v", 0, MSG_VERSION)
184
185    def testUnhandledOption(self):
186        """Test that unknown options gives an error"""
187        with self.assertRaises(SystemExit) as e:
188            s = io.StringIO()
189            expectedError = f"{self.USAGE}main.py: error: unrecognized arguments: -g\n"
190            with contextlib.redirect_stderr(s):
191                sys.argv = ["./main.py", "-g"]
192                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
193        self.assertEqual(e.exception.code, 2)
194        self.assertEqual(s.getvalue(), expectedError)
195
196    def testUnhandledArgument(self):
197        """Test that any argument gives an error"""
198        with self.assertRaises(SystemExit) as e:
199            s = io.StringIO()
200            expectedError = (f"{self.USAGE}main.py: error: argument protocol: "
201                             "invalid choice: 'arg' (choose from 'irc', 'discord')\n")
202            with contextlib.redirect_stderr(s):
203                sys.argv = ["./main.py", "arg"]
204                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
205        self.assertEqual(e.exception.code, 2)
206        self.assertEqual(s.getvalue(), expectedError)
207
208class TestArgumentParsing(TestCase):
209    """Test parsing argument to determine whether to launch as irc or discord bot """
210    def testDetermineDiscordProtocol(self):
211        """Test that the it's possible to give argument to start the bot as a discord bot"""
212        sys.argv = ["main.py", "discord"]
213        protocol = determineProtocol()
214        self.assertEqual(protocol, "discord")
215
216    def testDetermineIRCProtocol(self):
217        """Test that the it's possible to give argument to start the bot as an irc bot"""
218        sys.argv = ["main.py", "irc"]
219        protocol = determineProtocol()
220        self.assertEqual(protocol, "irc")
221
222    def testDetermineIRCProtocolisDefault(self):
223        """Test that if no argument is given, irc is the default"""
224        sys.argv = ["main.py"]
225        protocol = determineProtocol()
226        self.assertEqual(protocol, "irc")
227
228    def testDetermineConfigThrowsOnInvalidProto(self):
229        """Test that determineProtocol throws error on unsupported protocols"""
230        sys.argv = ["main.py", "gopher"]
231        with self.assertRaises(SystemExit) as e:
232            determineProtocol()
233        self.assertEqual(e.exception.code, 2)
234
235class TestBotFactoryMethod(TestCase):
236    """Test that createBot returns expected instances of Bots"""
237    def testCreateIRCBot(self):
238        """Test that an irc bot can be created"""
239        bot = createBot("irc")
240        self.assertIsInstance(bot, IrcBot)
241
242    def testCreateDiscordBot(self):
243        """Test that a discord bot can be created"""
244        bot = createBot("discord")
245        self.assertIsInstance(bot, DiscordBot)
246
247    def testCreateUnsupportedProtocolThrows(self):
248        """Test that trying to create a bot with an unsupported protocol will throw exception"""
249        with self.assertRaises(ValueError) as e:
250            createBot("gopher")
251        self.assertEqual(str(e.exception), "Unsupported protocol: gopher")
class ConfigMergeTest(unittest.case.TestCase):
21class ConfigMergeTest(TestCase):
22    """Test merging a config file with a dict"""
23
24    def assertMergedConfig(self, config, fileName, expected):
25        """Merge dict with file and assert the result matches expected"""
26        configFile = os.path.join("testConfigs", f"{fileName}.json")
27        actualConfig = mergeOptionsWithConfigFile(config, configFile)
28        self.assertEqual(actualConfig, expected)
29
30
31    def testEmpty(self):
32        """Empty into empty should equal empty"""
33        self.assertMergedConfig({}, "empty", {})
34
35    def testAddSingleParameter(self):
36        """Add a single parameter to an empty config"""
37        new = {
38            "single": "test"
39        }
40        expected = {
41            "single": "test"
42        }
43        self.assertMergedConfig(new, "empty", expected)
44
45    def testAddSingleParameterOverwrites(self):
46        """Add a single parameter to a config that contains it already"""
47        new = {
48            "single": "test"
49        }
50        expected = {
51            "single": "original"
52        }
53        self.assertMergedConfig(new, "single", expected)
54
55    def testAddSingleParameterMerges(self):
56        """Add a single parameter to a config that contains a different one"""
57        new = {
58            "new": "test"
59        }
60        expected = {
61            "new" : "test",
62            "single" : "original"
63        }
64        self.assertMergedConfig(new, "single", expected)

Test merging a config file with a dict

def assertMergedConfig(self, config, fileName, expected):
24    def assertMergedConfig(self, config, fileName, expected):
25        """Merge dict with file and assert the result matches expected"""
26        configFile = os.path.join("testConfigs", f"{fileName}.json")
27        actualConfig = mergeOptionsWithConfigFile(config, configFile)
28        self.assertEqual(actualConfig, expected)

Merge dict with file and assert the result matches expected

def testEmpty(self):
31    def testEmpty(self):
32        """Empty into empty should equal empty"""
33        self.assertMergedConfig({}, "empty", {})

Empty into empty should equal empty

def testAddSingleParameter(self):
35    def testAddSingleParameter(self):
36        """Add a single parameter to an empty config"""
37        new = {
38            "single": "test"
39        }
40        expected = {
41            "single": "test"
42        }
43        self.assertMergedConfig(new, "empty", expected)

Add a single parameter to an empty config

def testAddSingleParameterOverwrites(self):
45    def testAddSingleParameterOverwrites(self):
46        """Add a single parameter to a config that contains it already"""
47        new = {
48            "single": "test"
49        }
50        expected = {
51            "single": "original"
52        }
53        self.assertMergedConfig(new, "single", expected)

Add a single parameter to a config that contains it already

def testAddSingleParameterMerges(self):
55    def testAddSingleParameterMerges(self):
56        """Add a single parameter to a config that contains a different one"""
57        new = {
58            "new": "test"
59        }
60        expected = {
61            "new" : "test",
62            "single" : "original"
63        }
64        self.assertMergedConfig(new, "single", expected)

Add a single parameter to a config that contains a different one

class ConfigParseTest(unittest.case.TestCase):
 66class ConfigParseTest(TestCase):
 67    """Test parsing options into a config"""
 68
 69    SAMPLE_CONFIG = {
 70        "server": "localhost",
 71        "port": 6667,
 72        "channel": "#dbwebb",
 73        "nick": "marvin",
 74        "realname": "Marvin The All Mighty dbwebb-bot",
 75        "ident": "password"
 76    }
 77
 78    CHANGED_CONFIG = {
 79        "server": "remotehost",
 80        "port": 1234,
 81        "channel": "#db-o-webb",
 82        "nick": "imposter",
 83        "realname": "where is marvin?",
 84        "ident": "identify"
 85    }
 86
 87    def testOverrideHardcodedParameters(self):
 88        """Test that all the hard coded parameters can be overridden from commandline"""
 89        for parameter in ["server", "port", "channel", "nick", "realname", "ident"]:
 90            sys.argv = ["./main.py", f"--{parameter}", str(self.CHANGED_CONFIG.get(parameter))]
 91            actual = parseOptions(self.SAMPLE_CONFIG)
 92            self.assertEqual(actual.get(parameter), self.CHANGED_CONFIG.get(parameter))
 93
 94    def testOverrideMultipleParameters(self):
 95        """Test that multiple parameters can be overridden from commandline"""
 96        sys.argv = ["./main.py", "--server", "dbwebb.se", "--port", "5432"]
 97        actual = parseOptions(self.SAMPLE_CONFIG)
 98        self.assertEqual(actual.get("server"), "dbwebb.se")
 99        self.assertEqual(actual.get("port"), 5432)
100
101    def testOverrideWithFile(self):
102        """Test that parameters can be overridden with the --config option"""
103        configFile = os.path.join("testConfigs", "server.json")
104        sys.argv = ["./main.py", "--config", configFile]
105        actual = parseOptions(self.SAMPLE_CONFIG)
106        self.assertEqual(actual.get("server"), "irc.dbwebb.se")
107
108    def testOverridePrecedenceConfigFirst(self):
109        """Test that proper precedence is considered. From most to least significant it should be:
110        explicit parameter -> parameter in --config file -> default """
111
112        configFile = os.path.join("testConfigs", "server.json")
113        sys.argv = ["./main.py", "--config", configFile, "--server", "important.com"]
114        actual = parseOptions(self.SAMPLE_CONFIG)
115        self.assertEqual(actual.get("server"), "important.com")
116
117    def testOverridePrecedenceParameterFirst(self):
118        """Test that proper precedence is considered. From most to least significant it should be:
119        explicit parameter -> parameter in --config file -> default """
120
121        configFile = os.path.join("testConfigs", "server.json")
122        sys.argv = ["./main.py", "--server", "important.com", "--config", configFile]
123        actual = parseOptions(self.SAMPLE_CONFIG)
124        self.assertEqual(actual.get("server"), "important.com")
125
126    def testBannedParameters(self):
127        """Don't allow config, help and version as parameters, as those options are special"""
128        for bannedParameter in ["config", "help", "version"]:
129            with self.assertRaises(argparse.ArgumentError):
130                parseOptions({bannedParameter: "test"})

Test parsing options into a config

SAMPLE_CONFIG = {'server': 'localhost', 'port': 6667, 'channel': '#dbwebb', 'nick': 'marvin', 'realname': 'Marvin The All Mighty dbwebb-bot', 'ident': 'password'}
CHANGED_CONFIG = {'server': 'remotehost', 'port': 1234, 'channel': '#db-o-webb', 'nick': 'imposter', 'realname': 'where is marvin?', 'ident': 'identify'}
def testOverrideHardcodedParameters(self):
87    def testOverrideHardcodedParameters(self):
88        """Test that all the hard coded parameters can be overridden from commandline"""
89        for parameter in ["server", "port", "channel", "nick", "realname", "ident"]:
90            sys.argv = ["./main.py", f"--{parameter}", str(self.CHANGED_CONFIG.get(parameter))]
91            actual = parseOptions(self.SAMPLE_CONFIG)
92            self.assertEqual(actual.get(parameter), self.CHANGED_CONFIG.get(parameter))

Test that all the hard coded parameters can be overridden from commandline

def testOverrideMultipleParameters(self):
94    def testOverrideMultipleParameters(self):
95        """Test that multiple parameters can be overridden from commandline"""
96        sys.argv = ["./main.py", "--server", "dbwebb.se", "--port", "5432"]
97        actual = parseOptions(self.SAMPLE_CONFIG)
98        self.assertEqual(actual.get("server"), "dbwebb.se")
99        self.assertEqual(actual.get("port"), 5432)

Test that multiple parameters can be overridden from commandline

def testOverrideWithFile(self):
101    def testOverrideWithFile(self):
102        """Test that parameters can be overridden with the --config option"""
103        configFile = os.path.join("testConfigs", "server.json")
104        sys.argv = ["./main.py", "--config", configFile]
105        actual = parseOptions(self.SAMPLE_CONFIG)
106        self.assertEqual(actual.get("server"), "irc.dbwebb.se")

Test that parameters can be overridden with the --config option

def testOverridePrecedenceConfigFirst(self):
108    def testOverridePrecedenceConfigFirst(self):
109        """Test that proper precedence is considered. From most to least significant it should be:
110        explicit parameter -> parameter in --config file -> default """
111
112        configFile = os.path.join("testConfigs", "server.json")
113        sys.argv = ["./main.py", "--config", configFile, "--server", "important.com"]
114        actual = parseOptions(self.SAMPLE_CONFIG)
115        self.assertEqual(actual.get("server"), "important.com")

Test that proper precedence is considered. From most to least significant it should be: explicit parameter -> parameter in --config file -> default

def testOverridePrecedenceParameterFirst(self):
117    def testOverridePrecedenceParameterFirst(self):
118        """Test that proper precedence is considered. From most to least significant it should be:
119        explicit parameter -> parameter in --config file -> default """
120
121        configFile = os.path.join("testConfigs", "server.json")
122        sys.argv = ["./main.py", "--server", "important.com", "--config", configFile]
123        actual = parseOptions(self.SAMPLE_CONFIG)
124        self.assertEqual(actual.get("server"), "important.com")

Test that proper precedence is considered. From most to least significant it should be: explicit parameter -> parameter in --config file -> default

def testBannedParameters(self):
126    def testBannedParameters(self):
127        """Don't allow config, help and version as parameters, as those options are special"""
128        for bannedParameter in ["config", "help", "version"]:
129            with self.assertRaises(argparse.ArgumentError):
130                parseOptions({bannedParameter: "test"})

Don't allow config, help and version as parameters, as those options are special

class FormattingTest(unittest.case.TestCase):
133class FormattingTest(TestCase):
134    """Test the parameters that cause printouts"""
135
136    USAGE = ("usage: main.py [-h] [-v] [--config CONFIG] [--server SERVER] [--port PORT] "
137             "[--channel CHANNEL] [--nick NICK] [--realname REALNAME] [--ident IDENT]\n"
138             "               [{irc,discord}]\n")
139
140    OPTIONS = ("positional arguments:\n  {irc,discord}\n\n"
141               "options:\n"
142               "  -h, --help           show this help message and exit\n"
143               "  -v, --version\n"
144               "  --config CONFIG\n"
145               "  --server SERVER\n"
146               "  --port PORT\n"
147               "  --channel CHANNEL\n"
148               "  --nick NICK\n"
149               "  --realname REALNAME\n"
150               "  --ident IDENT")
151
152
153    @classmethod
154    def setUpClass(cls):
155        """Set the terminal width to 160 to prevent the tests from failing on small terminals"""
156        os.environ["COLUMNS"] = "160"
157
158
159    def assertPrintOption(self, options, returnCode, output):
160        """Assert that parseOptions returns a certain code and prints a certain output"""
161        with self.assertRaises(SystemExit) as e:
162            s = io.StringIO()
163            with contextlib.redirect_stdout(s):
164                sys.argv = ["./main.py"] + [options]
165                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
166        self.assertEqual(e.exception.code, returnCode)
167        self.assertEqual(s.getvalue(), output+"\n") # extra newline added by print()
168
169
170    def testHelpPrintout(self):
171        """Test that a help is printed when providing the --help flag"""
172        self.assertPrintOption("--help", 0, f"{self.USAGE}\n{self.OPTIONS}")
173
174    def testHelpPrintoutShort(self):
175        """Test that a help is printed when providing the -h flag"""
176        self.assertPrintOption("-h", 0, f"{self.USAGE}\n{self.OPTIONS}")
177
178    def testVersionPrintout(self):
179        """Test that the version is printed when provided the --version flag"""
180        self.assertPrintOption("--version", 0, MSG_VERSION)
181
182    def testVersionPrintoutShort(self):
183        """Test that the version is printed when provided the -v flag"""
184        self.assertPrintOption("-v", 0, MSG_VERSION)
185
186    def testUnhandledOption(self):
187        """Test that unknown options gives an error"""
188        with self.assertRaises(SystemExit) as e:
189            s = io.StringIO()
190            expectedError = f"{self.USAGE}main.py: error: unrecognized arguments: -g\n"
191            with contextlib.redirect_stderr(s):
192                sys.argv = ["./main.py", "-g"]
193                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
194        self.assertEqual(e.exception.code, 2)
195        self.assertEqual(s.getvalue(), expectedError)
196
197    def testUnhandledArgument(self):
198        """Test that any argument gives an error"""
199        with self.assertRaises(SystemExit) as e:
200            s = io.StringIO()
201            expectedError = (f"{self.USAGE}main.py: error: argument protocol: "
202                             "invalid choice: 'arg' (choose from 'irc', 'discord')\n")
203            with contextlib.redirect_stderr(s):
204                sys.argv = ["./main.py", "arg"]
205                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
206        self.assertEqual(e.exception.code, 2)
207        self.assertEqual(s.getvalue(), expectedError)

Test the parameters that cause printouts

USAGE = 'usage: main.py [-h] [-v] [--config CONFIG] [--server SERVER] [--port PORT] [--channel CHANNEL] [--nick NICK] [--realname REALNAME] [--ident IDENT]\n [{irc,discord}]\n'
OPTIONS = 'positional arguments:\n {irc,discord}\n\noptions:\n -h, --help show this help message and exit\n -v, --version\n --config CONFIG\n --server SERVER\n --port PORT\n --channel CHANNEL\n --nick NICK\n --realname REALNAME\n --ident IDENT'
@classmethod
def setUpClass(cls):
153    @classmethod
154    def setUpClass(cls):
155        """Set the terminal width to 160 to prevent the tests from failing on small terminals"""
156        os.environ["COLUMNS"] = "160"

Set the terminal width to 160 to prevent the tests from failing on small terminals

def assertPrintOption(self, options, returnCode, output):
159    def assertPrintOption(self, options, returnCode, output):
160        """Assert that parseOptions returns a certain code and prints a certain output"""
161        with self.assertRaises(SystemExit) as e:
162            s = io.StringIO()
163            with contextlib.redirect_stdout(s):
164                sys.argv = ["./main.py"] + [options]
165                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
166        self.assertEqual(e.exception.code, returnCode)
167        self.assertEqual(s.getvalue(), output+"\n") # extra newline added by print()

Assert that parseOptions returns a certain code and prints a certain output

def testHelpPrintout(self):
170    def testHelpPrintout(self):
171        """Test that a help is printed when providing the --help flag"""
172        self.assertPrintOption("--help", 0, f"{self.USAGE}\n{self.OPTIONS}")

Test that a help is printed when providing the --help flag

def testHelpPrintoutShort(self):
174    def testHelpPrintoutShort(self):
175        """Test that a help is printed when providing the -h flag"""
176        self.assertPrintOption("-h", 0, f"{self.USAGE}\n{self.OPTIONS}")

Test that a help is printed when providing the -h flag

def testVersionPrintout(self):
178    def testVersionPrintout(self):
179        """Test that the version is printed when provided the --version flag"""
180        self.assertPrintOption("--version", 0, MSG_VERSION)

Test that the version is printed when provided the --version flag

def testVersionPrintoutShort(self):
182    def testVersionPrintoutShort(self):
183        """Test that the version is printed when provided the -v flag"""
184        self.assertPrintOption("-v", 0, MSG_VERSION)

Test that the version is printed when provided the -v flag

def testUnhandledOption(self):
186    def testUnhandledOption(self):
187        """Test that unknown options gives an error"""
188        with self.assertRaises(SystemExit) as e:
189            s = io.StringIO()
190            expectedError = f"{self.USAGE}main.py: error: unrecognized arguments: -g\n"
191            with contextlib.redirect_stderr(s):
192                sys.argv = ["./main.py", "-g"]
193                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
194        self.assertEqual(e.exception.code, 2)
195        self.assertEqual(s.getvalue(), expectedError)

Test that unknown options gives an error

def testUnhandledArgument(self):
197    def testUnhandledArgument(self):
198        """Test that any argument gives an error"""
199        with self.assertRaises(SystemExit) as e:
200            s = io.StringIO()
201            expectedError = (f"{self.USAGE}main.py: error: argument protocol: "
202                             "invalid choice: 'arg' (choose from 'irc', 'discord')\n")
203            with contextlib.redirect_stderr(s):
204                sys.argv = ["./main.py", "arg"]
205                parseOptions(ConfigParseTest.SAMPLE_CONFIG)
206        self.assertEqual(e.exception.code, 2)
207        self.assertEqual(s.getvalue(), expectedError)

Test that any argument gives an error

class TestArgumentParsing(unittest.case.TestCase):
209class TestArgumentParsing(TestCase):
210    """Test parsing argument to determine whether to launch as irc or discord bot """
211    def testDetermineDiscordProtocol(self):
212        """Test that the it's possible to give argument to start the bot as a discord bot"""
213        sys.argv = ["main.py", "discord"]
214        protocol = determineProtocol()
215        self.assertEqual(protocol, "discord")
216
217    def testDetermineIRCProtocol(self):
218        """Test that the it's possible to give argument to start the bot as an irc bot"""
219        sys.argv = ["main.py", "irc"]
220        protocol = determineProtocol()
221        self.assertEqual(protocol, "irc")
222
223    def testDetermineIRCProtocolisDefault(self):
224        """Test that if no argument is given, irc is the default"""
225        sys.argv = ["main.py"]
226        protocol = determineProtocol()
227        self.assertEqual(protocol, "irc")
228
229    def testDetermineConfigThrowsOnInvalidProto(self):
230        """Test that determineProtocol throws error on unsupported protocols"""
231        sys.argv = ["main.py", "gopher"]
232        with self.assertRaises(SystemExit) as e:
233            determineProtocol()
234        self.assertEqual(e.exception.code, 2)

Test parsing argument to determine whether to launch as irc or discord bot

def testDetermineDiscordProtocol(self):
211    def testDetermineDiscordProtocol(self):
212        """Test that the it's possible to give argument to start the bot as a discord bot"""
213        sys.argv = ["main.py", "discord"]
214        protocol = determineProtocol()
215        self.assertEqual(protocol, "discord")

Test that the it's possible to give argument to start the bot as a discord bot

def testDetermineIRCProtocol(self):
217    def testDetermineIRCProtocol(self):
218        """Test that the it's possible to give argument to start the bot as an irc bot"""
219        sys.argv = ["main.py", "irc"]
220        protocol = determineProtocol()
221        self.assertEqual(protocol, "irc")

Test that the it's possible to give argument to start the bot as an irc bot

def testDetermineIRCProtocolisDefault(self):
223    def testDetermineIRCProtocolisDefault(self):
224        """Test that if no argument is given, irc is the default"""
225        sys.argv = ["main.py"]
226        protocol = determineProtocol()
227        self.assertEqual(protocol, "irc")

Test that if no argument is given, irc is the default

def testDetermineConfigThrowsOnInvalidProto(self):
229    def testDetermineConfigThrowsOnInvalidProto(self):
230        """Test that determineProtocol throws error on unsupported protocols"""
231        sys.argv = ["main.py", "gopher"]
232        with self.assertRaises(SystemExit) as e:
233            determineProtocol()
234        self.assertEqual(e.exception.code, 2)

Test that determineProtocol throws error on unsupported protocols

class TestBotFactoryMethod(unittest.case.TestCase):
236class TestBotFactoryMethod(TestCase):
237    """Test that createBot returns expected instances of Bots"""
238    def testCreateIRCBot(self):
239        """Test that an irc bot can be created"""
240        bot = createBot("irc")
241        self.assertIsInstance(bot, IrcBot)
242
243    def testCreateDiscordBot(self):
244        """Test that a discord bot can be created"""
245        bot = createBot("discord")
246        self.assertIsInstance(bot, DiscordBot)
247
248    def testCreateUnsupportedProtocolThrows(self):
249        """Test that trying to create a bot with an unsupported protocol will throw exception"""
250        with self.assertRaises(ValueError) as e:
251            createBot("gopher")
252        self.assertEqual(str(e.exception), "Unsupported protocol: gopher")

Test that createBot returns expected instances of Bots

def testCreateIRCBot(self):
238    def testCreateIRCBot(self):
239        """Test that an irc bot can be created"""
240        bot = createBot("irc")
241        self.assertIsInstance(bot, IrcBot)

Test that an irc bot can be created

def testCreateDiscordBot(self):
243    def testCreateDiscordBot(self):
244        """Test that a discord bot can be created"""
245        bot = createBot("discord")
246        self.assertIsInstance(bot, DiscordBot)

Test that a discord bot can be created

def testCreateUnsupportedProtocolThrows(self):
248    def testCreateUnsupportedProtocolThrows(self):
249        """Test that trying to create a bot with an unsupported protocol will throw exception"""
250        with self.assertRaises(ValueError) as e:
251            createBot("gopher")
252        self.assertEqual(str(e.exception), "Unsupported protocol: gopher")

Test that trying to create a bot with an unsupported protocol will throw exception