3
from twisted.internet import task
4
from twisted.trial import unittest
6
from axiom import store
8
from imaginary import iimaginary, objects, events, action
10
from imaginary.test import commandutils
12
from examplegame import mice
13
from examplegame import japanese
15
class MouseChallengeMixin(object):
17
A mixin meant to be used in TestCases which want to assert things
18
about mouse challenges.
20
The subclass must be sure to provide a C{player} instance
21
attribute, which is the L{IThing<iimaginary.IThing>} provider of
22
the player which observes the mouse, and a C{mouseName} attribute
23
which should be the mouse's name.
25
def assertChallenge(self, concept):
27
Assert that the given concept is a challenge from the mouse
28
named self.mouseName, as observed by self.player.
30
said = commandutils.flatten(concept.plaintext(self.player))
31
self.failUnless(said.startswith(u"A %s says, '" % (self.mouseName,)), repr(said))
32
self.failUnlessIn(said[-3], japanese.hiragana)
33
self.failUnless(said.endswith("'\n"), repr(said))
37
class HiraganaMouseTestCase(MouseChallengeMixin, unittest.TestCase):
39
Test that there is a mouse that says hiragana and stuff
43
self.store = store.Store()
45
self.clock = objects.Thing(store=self.store, name=u"Clock")
46
self.clockContainer = objects.Container.createFor(self.clock, capacity=10)
48
self.mouseName = u"\N{KATAKANA LETTER PI}\N{KATAKANA LETTER SMALL YU}"
49
self.mouse = mice.createHiraganaMouse(
52
self.mouseActor = iimaginary.IActor(self.mouse)
53
self.mousehood = self.mouseActor.getIntelligence()
54
self.mouse.moveTo(self.clock)
58
self.playerIntelligence) = commandutils.createPlayer(self.store,
62
self.player.moveTo(self.clock)
64
self.reactorTime = task.Clock()
65
self.mousehood._callLater = self.reactorTime.callLater
68
def test_mouseCanSqueak(self):
70
When explicitly told to challenge with a given romaji syllable, the
71
mouse should say a hiragana letter.
73
events.runEventTransaction(
75
self.mousehood.challenge,
76
character=u"\N{HIRAGANA LETTER A}")
78
self.assertEquals(len(self.playerIntelligence.concepts), 1)
79
event = self.playerIntelligence.concepts[0]
81
commandutils.flatten(event.otherMessage.plaintext(self.player)),
82
u"A %s says, '\N{HIRAGANA LETTER A}'" % (self.mouseName,))
85
def test_randomHiragana(self):
87
When explicitly told to challenge without specifying a syllable, the
88
mouse should say a random one.
90
events.runEventTransaction(self.store, self.mousehood.challenge)
91
self.assertEquals(len(self.playerIntelligence.concepts), 1)
92
event = self.playerIntelligence.concepts[0]
93
self.assertChallenge(event)
98
Two hiragana characters map to the romaji 'ji'. Test that we do the
101
self.mousehood.challenge(character=u"\N{HIRAGANA LETTER DI}")
102
self.failUnless(self.mousehood.vetteChallengeResponse(u"ji"))
103
self.mousehood.challenge(character=u"\N{HIRAGANA LETTER ZI}")
104
self.failUnless(self.mousehood.vetteChallengeResponse(u"ji"))
109
Two hiragana characters map to the romaji 'zu'. Test that we do the
110
right thing for them.
112
self.mousehood.challenge(character=u"\N{HIRAGANA LETTER DU}")
113
self.failUnless(self.mousehood.vetteChallengeResponse(u"zu"))
114
self.mousehood.challenge(character=u"\N{HIRAGANA LETTER ZU}")
115
self.failUnless(self.mousehood.vetteChallengeResponse(u"zu"))
118
def test_mouseStartsChallengingWhenPlayersArrive(self):
120
When a player arrives, the mouse should go into the 'I am
124
self.assertEquals(self.mousehood.challenging, False)
126
evt = events.ArrivalEvent(actor=self.player)
127
self.mouseActor.send(evt)
129
self.assertEquals(self.mousehood.challenging, True)
132
def test_mouseSchedulesChallenges(self):
134
After telling a mouse to start challenging, it should schedule timed
135
events to say challenges.
137
self.mousehood.startChallenging()
138
self.reactorTime.advance(self.mousehood.challengeInterval)
139
concepts = self.playerIntelligence.concepts
140
self.assertEquals(len(concepts), 1)
141
self.assertChallenge(concepts[0])
144
def test_mouseStopsChallengingWhenPlayersLeave(self):
146
When the 'last' player leaves, the mouse stops challenging.
149
self.mousehood.startChallenging()
151
evt = events.DepartureEvent(location=self.clock,
153
self.player.moveTo(None)
154
self.mouseActor.send(evt)
156
self.assertEquals(self.mousehood.challenging, False)
159
def test_mouseStopsSchedulingChallenges(self):
161
When a mouse is told to stop challenging, it should cancel any
162
challenges it had scheduled.
164
self.mousehood.startChallenging()
165
self.mousehood.stopChallenging()
167
self.reactorTime.advance(self.mousehood.challengeInterval)
168
self.assertEquals(self.playerIntelligence.concepts, [])
171
def test_stopChallengingWhenNotChallengingFails(self):
173
Don't stop challenging when you're not challenging.
175
self.assertRaises(mice.ChallengeVacuum, self.mousehood.stopChallenging)
178
def test_startChallengingTwiceFails(self):
180
Don't start challenging twice.
182
self.mousehood.startChallenging()
183
self.assertRaises(mice.ChallengeCollision, self.mousehood.startChallenging)
186
def test_challengeRecurrence(self):
188
After a challenge is issued another one should be issued later.
190
self.mousehood.startChallenging()
191
self.reactorTime.advance(self.mousehood.challengeInterval)
193
self.assertIn(self.mousehood.getCurrentChallenge(), japanese.hiragana)
195
self.mousehood._currentChallenge = None # Clear his challenge evilly
197
self.reactorTime.advance(self.mousehood.challengeInterval)
199
self.assertIn(self.mousehood.getCurrentChallenge(), japanese.hiragana)
202
def test_twoMenEnter(self):
204
Test that when *TWO* players join, the mouse doesn't schedule too many
207
otherPlayer = commandutils.createPlayer(self.store,
208
u"Polite Young Man")[0]
210
# Send an arrival event because setUp doesn't
211
firstEvent = events.ArrivalEvent(actor=self.player)
213
self.mouseActor.send(firstEvent)
214
otherPlayer.moveTo(self.clock, arrivalEventFactory=events.MovementArrivalEvent)
216
self.playerIntelligence.concepts = []
217
self.reactorTime.advance(self.mousehood.challengeInterval)
219
self.assertEquals(len(self.playerIntelligence.concepts), 1)
220
self.assertChallenge(self.playerIntelligence.concepts[0])
223
def test_twoMenLeave(self):
225
Test that when two players are near the mouse, the mouse doesn't
226
unschedule its challenge until they both leave.
228
otherPlayer = commandutils.createPlayer(self.store,
229
u"Polite Young Man")[0]
230
otherPlayer.moveTo(self.clock)
232
self.mousehood.startChallenging()
234
firstEvent = events.DepartureEvent(location=self.clock,
236
secondEvent = events.DepartureEvent(location=self.clock,
239
otherPlayer.moveTo(None)
240
self.mouseActor.send(secondEvent)
242
self.playerIntelligence.concepts = []
244
self.reactorTime.advance(self.mousehood.challengeInterval)
246
self.assertEquals(len(self.playerIntelligence.concepts), 1)
247
self.assertChallenge(self.playerIntelligence.concepts[0])
249
self.player.moveTo(None)
250
self.mouseActor.send(firstEvent)
252
self.failIf(self.mousehood.challenging)
255
def test_getCurrentChallenge(self):
257
Test that we can introspect the current challenge of a mouse.
259
self.mousehood.startChallenging()
260
self.reactorTime.advance(self.mousehood.challengeInterval)
261
self.failUnlessIn(self.mousehood.getCurrentChallenge(), japanese.hiragana)
263
self.mousehood.stopChallenging()
264
self.assertIdentical(self.mousehood.getCurrentChallenge(), None)
267
def test_vetteChallengeResponse(self):
269
Test that the correct response to the current challenge is accepted by
272
self.mousehood.startChallenging()
273
self.reactorTime.advance(self.mousehood.challengeInterval)
275
romaji = japanese.hiragana[self.mousehood.getCurrentChallenge()]
276
self.failUnless(self.mousehood.vetteChallengeResponse(romaji))
278
for romaji in japanese.hiragana.values():
279
if romaji != japanese.hiragana[self.mousehood.getCurrentChallenge()]:
280
self.failIf(self.mousehood.vetteChallengeResponse(romaji))
283
def test_respondToChallengeCorrectly(self):
285
Test that when a correct response is received, the current challenge is
286
expired and the mouse salutes you.
288
self.mousehood.startChallenging()
289
self.reactorTime.advance(self.mousehood.challengeInterval)
291
correctResponse = japanese.hiragana[
292
self.mousehood.getCurrentChallenge()]
294
self.mousehood.responseReceived(self.player, correctResponse)
295
self.reactorTime.advance(0)
297
self.assertIdentical(self.mousehood.getCurrentChallenge(), None)
299
self.assertEquals(len(self.playerIntelligence.concepts), 2)
300
c = self.playerIntelligence.concepts[1]
302
commandutils.flatten(c.plaintext(self.player)),
303
u"%s salutes you!\n" % (self.mouseName,))
306
def test_respondToChallengeInorrectly(self):
308
Test that when an incorrect response is received, the current challenge
309
is not expired and the mouse bites you.
311
self.mousehood.startChallenging()
312
self.reactorTime.advance(self.mousehood.challengeInterval)
314
correctResponse = japanese.hiragana[
315
self.mousehood.getCurrentChallenge()]
317
for ch in japanese.hiragana.values():
318
if ch != correctResponse:
319
self.mousehood.responseReceived(self.player, ch)
322
self.fail("Buggy test")
324
self.reactorTime.advance(0)
326
self.assertIn(self.mousehood.getCurrentChallenge(),
327
japanese.romajiToHiragana[correctResponse])
329
self.assertEquals(len(self.playerIntelligence.concepts), 2)
330
c = self.playerIntelligence.concepts[1]
332
commandutils.flatten(c.plaintext(self.player)),
333
u"%s bites you!\n" % (self.mouseName,))
336
def test_playerSaysCorrectThing(self):
338
Test that when someone gives voice to the correct response to a mouse's
339
current challenge, the mouse acknowledges this with a salute.
341
self.mousehood.startChallenging()
342
self.reactorTime.advance(self.mousehood.challengeInterval)
344
# http://divmod.org/trac/ticket/2917
345
iimaginary.IActor(self.player),
347
japanese.hiragana[self.mousehood.getCurrentChallenge()])
349
self.assertIdentical(self.mousehood.getCurrentChallenge(), None)
350
self.reactorTime.advance(0)
352
self.assertEquals(len(self.playerIntelligence.concepts), 3)
353
c = self.playerIntelligence.concepts[2]
355
commandutils.flatten(c.plaintext(self.player)),
356
u"%s salutes you!\n" % (self.mouseName,))
359
def test_playerSaysIncorrectThing(self):
361
Test that when someone gives voice to the correct response to a mouse's
362
current challenge, the mouse acknowledges this with a salute.
364
self.mousehood.startChallenging()
365
self.reactorTime.advance(self.mousehood.challengeInterval)
368
# http://divmod.org/trac/ticket/2917
369
iimaginary.IActor(self.player), None, u"lolololo pew")
371
self.failIfIdentical(self.mousehood.getCurrentChallenge(), None)
372
self.reactorTime.advance(0)
374
self.assertEquals(len(self.playerIntelligence.concepts), 3)
375
c = self.playerIntelligence.concepts[2]
377
commandutils.flatten(c.plaintext(self.player)),
378
u"%s bites you!\n" % (self.mouseName,))
381
def test_activationUsesReactorScheduling(self):
383
Test that the default scheduler of the mouse is the Twisted
384
reactor, since that is the scheduler that needs to be used
385
with the actual Imaginary server.
388
ref = weakref.ref(self.mousehood, deletions.append)
389
# This is a hack to reload the mouse since it gets its
390
# _callLater set in setUp.
394
self.assertEquals(deletions, [ref])
395
mousehood = self.store.findUnique(mice.HiraganaMouse)
396
from twisted.internet import reactor
397
self.assertEquals(mousehood._callLater, reactor.callLater)
401
class HiraganaMouseCommandTestCase(commandutils.CommandTestCaseMixin, unittest.TestCase):
403
H-mouse tests which use the command system.
406
mouseName = u"\N{KATAKANA LETTER PI}\N{KATAKANA LETTER SMALL YU}"
407
hiraganaCharacterPattern = u"'[" + u''.join(japanese.hiragana.keys()) + u"]'"
408
speechPattern = mouseName + u" says, " + hiraganaCharacterPattern
410
def test_oneManEnters(self):
412
Test that when a fellow jaunts into a venue inhabited by a mouse of the
413
Nipponese persuasion, a hiragana allocution follows.
417
closetContainer = commandutils.createLocation(
418
self.store, u"Closet", None)
419
closet = closetContainer.thing
421
mouse = mice.createHiraganaMouse(
425
mouseActor = iimaginary.IActor(mouse)
426
mousehood = mouseActor.getIntelligence()
427
mousehood._callLater = clock.callLater
430
objects.Exit.link(self.location, closet, u"north")
434
[commandutils.E("[ Closet ]"),
435
commandutils.E("( south )"),
436
commandutils.E(u"Here, you see " + self.mouseName + u".")],
437
["Test Player leaves north."])
439
clock.advance(mousehood.challengeInterval)
441
self._test(None, [self.speechPattern])
444
def test_creation(self):
446
Test the creation of a hiragana-speaking mouse using the thing creation
450
u"create the 'hiragana mouse' named " + self.mouseName,
451
[commandutils.E(u"You create " + self.mouseName + u".")],
452
[commandutils.E(u"Test Player creates %s." % (self.mouseName,))])
454
for thing in self.location.findProviders(iimaginary.IThing, 0):
455
if thing.name == self.mouseName:
458
self.fail("Could not find the mouse! Test bug.")
461
jimhood = iimaginary.IActor(thing).getIntelligence()
462
jimhood._callLater = clock.callLater
465
u"drop " + self.mouseName,
466
[commandutils.E(u"You drop %s." % (self.mouseName,))],
467
[commandutils.E(u"Test Player drops %s." % (self.mouseName,))])
469
clock.advance(jimhood.challengeInterval)
473
[self.speechPattern],
474
[self.speechPattern])