Passed
Branch master (a5c0c0)
by Mikael
03:26 queued 19s
created

test_marvin_actions.ActionTest.assertBBQResponse()   A

Complexity

Conditions 5

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 13
nop 4
dl 0
loc 15
ccs 13
cts 13
cp 1
crap 5
rs 9.2833
c 0
b 0
f 0
1
#! /usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
"""
5
Tests for all Marvin actions
6
"""
7
8
import json
9
10
from datetime import date
11
from unittest import mock, TestCase
12
13
import requests
14
15
from bot import Bot
16
import marvin_actions
17
import marvin_general_actions
18
19
class ActionTest(TestCase):
20
    """Test Marvin actions"""
21
    strings = {}
22
23
    @classmethod
24
    def setUpClass(cls):
25
        with open("marvin_strings.json", encoding="utf-8") as f:
26
            cls.strings = json.load(f)
27
28
29
    def executeAction(self, action, message):
30
        """Execute an action for a message and return the response"""
31
        return action(Bot.tokenize(message))
32
33
34
    def assertActionOutput(self, action, message, expectedOutput):
35
        """Call an action on message and assert expected output"""
36
        actualOutput = self.executeAction(action, message)
37
38
        self.assertEqual(actualOutput, expectedOutput)
39
40
41
    def assertActionSilent(self, action, message):
42
        """Call an action with provided message and assert no output"""
43
        self.assertActionOutput(action, message, None)
44
45
46
    def assertStringsOutput(self, action, message, expectedoutputKey, subkey=None):
47
        """Call an action with provided message and assert the output is equal to DB"""
48
        expectedOutput = self.strings.get(expectedoutputKey)
49
        if subkey is not None:
50
            if isinstance(expectedOutput, list):
51
                expectedOutput = expectedOutput[subkey]
52
            else:
53
                expectedOutput = expectedOutput.get(subkey)
54
        self.assertActionOutput(action, message, expectedOutput)
55
56
57
    def assertBBQResponse(self, todaysDate, bbqDate, expectedMessageKey):
58
        """Assert that the proper bbq message is returned, given a date"""
59
        url = self.strings.get("barbecue").get("url")
60
        message = self.strings.get("barbecue").get(expectedMessageKey)
61
        if isinstance(message, list):
62
            message = message[1]
63
        if expectedMessageKey in ["base", "week", "eternity"]:
64
            message = message % bbqDate
65
66
        with mock.patch("marvin_actions.datetime") as d:
67
            d.date.today.return_value = todaysDate
68
            with mock.patch("marvin_actions.random") as r:
69
                r.randint.return_value = 1
70
                expected = f"{url}. {message}"
71
                self.assertActionOutput(marvin_actions.marvinTimeToBBQ, "dags att grilla", expected)
72
73
74
    def assertNameDayOutput(self, exampleFile, expectedOutput):
75
        """Assert that the proper nameday message is returned, given an inputfile"""
76
        with open(f"namedayFiles/{exampleFile}.json", "r", encoding="UTF-8") as f:
77
            response = requests.models.Response()
78
            response._content = str.encode(json.dumps(json.load(f)))
79
            with mock.patch("marvin_actions.requests") as r:
80
                r.get.return_value = response
81
                self.assertActionOutput(marvin_actions.marvinNameday, "nameday", expectedOutput)
82
83
    def assertJokeOutput(self, exampleFile, expectedOutput):
84
        """Assert that a joke is returned, given an input file"""
85
        with open(f"jokeFiles/{exampleFile}.json", "r", encoding="UTF-8") as f:
86
            response = requests.models.Response()
87
            response._content = str.encode(json.dumps(json.load(f)))
88
            with mock.patch("marvin_actions.requests") as r:
89
                r.get.return_value = response
90
                self.assertActionOutput(marvin_actions.marvinJoke, "joke", expectedOutput)
91
92
    def testSmile(self):
93
        """Test that marvin can smile"""
94
        with mock.patch("marvin_actions.random") as r:
95
            r.randint.return_value = 1
96
            self.assertStringsOutput(marvin_actions.marvinSmile, "le lite?", "smile", 1)
97
        self.assertActionSilent(marvin_actions.marvinSmile, "sur idag?")
98
99
    def testWhois(self):
100
        """Test that marvin responds to whois"""
101
        self.assertStringsOutput(marvin_actions.marvinWhoIs, "vem är marvin?", "whois")
102
        self.assertActionSilent(marvin_actions.marvinWhoIs, "vemär")
103
104
    def testGoogle(self):
105
        """Test that marvin can help google stuff"""
106
        with mock.patch("marvin_actions.random") as r:
107
            r.randint.return_value = 1
108
            self.assertActionOutput(
109
                marvin_actions.marvinGoogle,
110
                "kan du googla mos",
111
                "LMGTFY https://www.google.se/search?q=mos")
112
            self.assertActionOutput(
113
                marvin_actions.marvinGoogle,
114
                "kan du googla google mos",
115
                "LMGTFY https://www.google.se/search?q=google+mos")
116
        self.assertActionSilent(marvin_actions.marvinGoogle, "du kan googla")
117
        self.assertActionSilent(marvin_actions.marvinGoogle, "gogool")
118
119
    def testExplainShell(self):
120
        """Test that marvin can explain shell commands"""
121
        url = "http://explainshell.com/explain?cmd=pwd"
122
        self.assertActionOutput(marvin_actions.marvinExplainShell, "explain pwd", url)
123
        self.assertActionOutput(marvin_actions.marvinExplainShell, "can you explain pwd", url)
124
        self.assertActionOutput(
125
            marvin_actions.marvinExplainShell,
126
            "förklara pwd|grep -o $user",
127
            f"{url}%7Cgrep+-o+%24user")
128
129
        self.assertActionSilent(marvin_actions.marvinExplainShell, "explains")
130
131
    def testSource(self):
132
        """Test that marvin responds to questions about source code"""
133
        self.assertStringsOutput(marvin_actions.marvinSource, "source", "source")
134
        self.assertStringsOutput(marvin_actions.marvinSource, "källkod", "source")
135
        self.assertActionSilent(marvin_actions.marvinSource, "opensource")
136
137
    def testBudord(self):
138
        """Test that marvin knows all the commandments"""
139
        for n in range(1, 5):
140
            self.assertStringsOutput(marvin_actions.marvinBudord, f"budord #{n}", "budord", f"#{n}")
141
142
        self.assertStringsOutput(marvin_actions.marvinBudord,"visa stentavla 1", "budord", "#1")
143
        self.assertActionSilent(marvin_actions.marvinBudord, "var är stentavlan?")
144
145
    def testQuote(self):
146
        """Test that marvin can quote The Hitchhikers Guide to the Galaxy"""
147
        with mock.patch("marvin_actions.random") as r:
148
            r.randint.return_value = 1
149
            self.assertStringsOutput(marvin_actions.marvinQuote, "ge os ett citat", "hitchhiker", 1)
150
            self.assertStringsOutput(marvin_actions.marvinQuote, "filosofi", "hitchhiker", 1)
151
            self.assertStringsOutput(marvin_actions.marvinQuote, "filosofera", "hitchhiker", 1)
152
            self.assertActionSilent(marvin_actions.marvinQuote, "noquote")
153
154
            for i,_ in enumerate(self.strings.get("hitchhiker")):
155
                r.randint.return_value = i
156
                self.assertStringsOutput(marvin_actions.marvinQuote, "quote", "hitchhiker", i)
157
158
    def testVideoOfToday(self):
159
        """Test that marvin can link to a different video each day of the week"""
160
        with mock.patch("marvin_actions.datetime") as dt:
161
            for d in range(1, 8):
162
                dt.date.weekday.return_value = d - 1
163
                day =  self.strings.get("weekdays").get(str(d))
164
                video = self.strings.get("video-of-today").get(str(d))
165
                response = f"{day} En passande video är {video}"
166
                self.assertActionOutput(marvin_actions.marvinVideoOfToday, "dagens video", response)
167
        self.assertActionSilent(marvin_actions.marvinVideoOfToday, "videoidag")
168
169
    def testHelp(self):
170
        """Test that marvin can provide a help menu"""
171
        self.assertStringsOutput(marvin_actions.marvinHelp, "help", "menu")
172
        self.assertActionSilent(marvin_actions.marvinHelp, "halp")
173
174
    def testStats(self):
175
        """Test that marvin can provide a link to the IRC stats page"""
176
        self.assertStringsOutput(marvin_actions.marvinStats, "stats", "ircstats")
177
        self.assertActionSilent(marvin_actions.marvinStats, "statistics")
178
179
    def testIRCLog(self):
180
        """Test that marvin can provide a link to the IRC log"""
181
        self.assertStringsOutput(marvin_actions.marvinIrcLog, "irc", "irclog")
182
        self.assertActionSilent(marvin_actions.marvinIrcLog, "ircstats")
183
184
    def testSayHi(self):
185
        """Test that marvin responds to greetings"""
186
        with mock.patch("marvin_actions.random") as r:
187
            for skey, s in enumerate(self.strings.get("smile")):
188
                for hkey, h in enumerate(self.strings.get("hello")):
189
                    for fkey, f in enumerate(self.strings.get("friendly")):
190
                        r.randint.side_effect = [skey, hkey, fkey]
191
                        self.assertActionOutput(marvin_actions.marvinSayHi, "hej", f"{s} {h} {f}")
192
        self.assertActionSilent(marvin_actions.marvinSayHi, "korsning")
193
194
    def testLunchLocations(self):
195
        """Test that marvin can provide lunch suggestions for certain places"""
196
        locations = ["karlskrona", "goteborg", "angelholm", "hassleholm", "malmo"]
197
        with mock.patch("marvin_actions.random") as r:
198
            for location in locations:
199
                for index, place in enumerate(self.strings.get(f"lunch-{location}")):
200
                    r.randint.side_effect = [0, index]
201
                    self.assertActionOutput(
202
                        marvin_actions.marvinLunch, f"mat {location}", f"Ska vi ta {place}?")
203
            r.randint.side_effect = [1, 2]
204
            self.assertActionOutput(
205
                marvin_actions.marvinLunch, "dags att luncha", "Jag är lite sugen på Indiska?")
206
        self.assertActionSilent(marvin_actions.marvinLunch, "matdags")
207
208
    def testStrip(self):
209
        """Test that marvin can recommend comics"""
210
        messageFormat = self.strings.get("commitstrip").get("message")
211
        expected = messageFormat.format(url=self.strings.get("commitstrip").get("url"))
212
        self.assertActionOutput(marvin_actions.marvinStrip, "lite strip kanske?", expected)
213
        self.assertActionSilent(marvin_actions.marvinStrip, "nostrip")
214
215
    def testRandomStrip(self):
216
        """Test that marvin can recommend random comics"""
217
        messageFormat = self.strings.get("commitstrip").get("message")
218
        expected = messageFormat.format(url=self.strings.get("commitstrip").get("urlPage") + "123")
219
        with mock.patch("marvin_actions.random") as r:
220
            r.randint.return_value = 123
221
            self.assertActionOutput(marvin_actions.marvinStrip, "random strip kanske?", expected)
222
223
    def testTimeToBBQ(self):
224
        """Test that marvin knows when the next BBQ is"""
225
        self.assertBBQResponse(date(2024, 5, 17), date(2024, 5, 17), "today")
226
        self.assertBBQResponse(date(2024, 5, 16), date(2024, 5, 17), "tomorrow")
227
        self.assertBBQResponse(date(2024, 5, 10), date(2024, 5, 17), "week")
228
        self.assertBBQResponse(date(2024, 5, 1), date(2024, 5, 17), "base")
229
        self.assertBBQResponse(date(2023, 10, 17), date(2024, 5, 17), "eternity")
230
231
        self.assertBBQResponse(date(2024, 9, 20), date(2024, 9, 20), "today")
232
        self.assertBBQResponse(date(2024, 9, 19), date(2024, 9, 20), "tomorrow")
233
        self.assertBBQResponse(date(2024, 9, 13), date(2024, 9, 20), "week")
234
        self.assertBBQResponse(date(2024, 9, 4), date(2024, 9, 20), "base")
235
236
    def testNameDayReaction(self):
237
        """Test that marvin only responds to nameday when asked"""
238
        self.assertActionSilent(marvin_actions.marvinNameday, "anything")
239
240
    def testNameDayRequest(self):
241
        """Test that marvin sends a proper request for nameday info"""
242
        with mock.patch("marvin_actions.requests") as r:
243
            with mock.patch("marvin_actions.datetime") as d:
244
                d.datetime.now.return_value = date(2024, 1, 2)
245
                self.executeAction(marvin_actions.marvinNameday, "namnsdag")
246
                self.assertEqual(r.get.call_args.args[0], "http://api.dryg.net/dagar/v2.1/2024/1/2")
247
248
    def testNameDayResponse(self):
249
        """Test that marvin properly parses nameday responses"""
250
        self.assertNameDayOutput("single", "Idag har Svea namnsdag")
251
        self.assertNameDayOutput("double", "Idag har Alfred,Alfrida namnsdag")
252
        self.assertNameDayOutput("nobody", "Ingen har namnsdag idag")
253
254
    def testJokeRequest(self):
255
        """Test that marvin sends a proper request for a joke"""
256
        with mock.patch("marvin_actions.requests") as r:
257
            self.executeAction(marvin_actions.marvinJoke, "joke")
258
            self.assertEqual(r.get.call_args.args[0], "https://api.chucknorris.io/jokes/random?category=dev")
259
260
    def testJoke(self):
261
        """Test that marvin sends a joke when requested"""
262
        self.assertJokeOutput("joke", "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris.")
263
264
    def testUptime(self):
265
        """Test that marvin can provide the link to the uptime tournament"""
266
        self.assertStringsOutput(marvin_actions.marvinUptime, "visa lite uptime", "uptime", "info")
267
        self.assertActionSilent(marvin_actions.marvinUptime, "uptimetävling")
268
269
    def testStream(self):
270
        """Test that marvin can provide the link to the stream"""
271
        self.assertStringsOutput(marvin_actions.marvinStream, "ska mos streama?", "stream", "info")
272
        self.assertActionSilent(marvin_actions.marvinStream, "är mos en streamer?")
273
274
    def testPrinciple(self):
275
        """Test that marvin can recite some software principles"""
276
        principles = self.strings.get("principle")
277
        for key, value in principles.items():
278
            self.assertActionOutput(marvin_actions.marvinPrinciple, f"princip {key}", value)
279
        with mock.patch("marvin_actions.random") as r:
280
            r.choice.return_value = "dry"
281
            self.assertStringsOutput(marvin_actions.marvinPrinciple, "princip", "principle", "dry")
282
        self.assertActionSilent(marvin_actions.marvinPrinciple, "principlös")
283
284
    def testCommitRequest(self):
285
        """Test that marvin sends proper requests when generating commit messages"""
286
        with mock.patch("marvin_actions.requests") as r:
287
            self.executeAction(marvin_actions.marvinCommit, "vad skriver man efter commit -m?")
288
            self.assertEqual(r.get.call_args.args[0], "http://whatthecommit.com/index.txt")
289
290
    def testCommitResponse(self):
291
        """Test that marvin properly handles responses when generating commit messages"""
292
        message = "Secret sauce #9"
293
        response = requests.models.Response()
294
        response._content = str.encode(message)
295
        with mock.patch("marvin_actions.requests") as r:
296
            r.get.return_value = response
297
            expected = f"Använd detta meddelandet: '{message}'"
298
            self.assertActionOutput(marvin_actions.marvinCommit, "commit", expected)
299
300
    def testMorning(self):
301
        """Test that marvin wishes good morning, at most once per day"""
302
        marvin_general_actions.lastDateGreeted = None
303
        with mock.patch("marvin_general_actions.datetime") as d:
304
            d.date.today.return_value = date(2024, 5, 17)
305
            with mock.patch("marvin_general_actions.random") as r:
306
                r.choice.return_value = "Morgon"
307
                self.assertActionOutput(marvin_general_actions.marvinMorning, "morrn", "Morgon")
308
                # Should only greet once per day
309
                self.assertActionSilent(marvin_general_actions.marvinMorning, "morgon")
310
                # Should greet again tomorrow
311
                d.date.today.return_value = date(2024, 5, 18)
312
                self.assertActionOutput(marvin_general_actions.marvinMorning, "godmorgon", "Morgon")
313