"""
Tests for RP system
"""
import time
from anything import Anything
from evennia import DefaultObject, create_object, default_cmds
from evennia.commands.default import building
from evennia.commands.default.tests import BaseEvenniaCommandTest
from evennia.utils.test_resources import BaseEvenniaTest
from . import rplanguage, rpsystem
mtrans = {"testing": "1", "is": "2", "a": "3", "human": "4"}
atrans = ["An", "automated", "advantageous", "repeatable", "faster"]
text = (
"Automated testing is advantageous for a number of reasons: "
"tests may be executed Continuously without the need for human "
"intervention, They are easily repeatable, and often faster."
)
[docs]class TestLanguage(BaseEvenniaTest):
[docs] def setUp(self):
super().setUp()
rplanguage.add_language(
key="testlang",
word_length_variance=1,
noun_prefix="bara",
noun_postfix="'y",
manual_translations=mtrans,
auto_translations=atrans,
force=True,
)
rplanguage.add_language(
key="binary",
phonemes="oo ii a ck w b d t",
grammar="cvvv cvv cvvcv cvvcvv cvvvc cvvvcvv cvvc",
noun_prefix="beep-",
word_length_variance=4,
)
[docs] def tearDown(self):
super().tearDown()
rplanguage._LANGUAGE_HANDLER.delete()
rplanguage._LANGUAGE_HANDLER = None
[docs] def test_obfuscate_language(self):
result0 = rplanguage.obfuscate_language(text, level=0.0, language="testlang")
self.assertEqual(result0, text)
result1 = rplanguage.obfuscate_language(text, level=1.0, language="testlang")
result2 = rplanguage.obfuscate_language(text, level=1.0, language="testlang")
result3 = rplanguage.obfuscate_language(text, level=1.0, language="binary")
self.assertNotEqual(result1, text)
self.assertNotEqual(result3, text)
result1, result2 = result1.split(), result2.split()
self.assertEqual(result1[:4], result2[:4])
self.assertEqual(result1[1], "1")
self.assertEqual(result1[2], "2")
self.assertEqual(result2[-1], result2[-1])
[docs] def test_faulty_language(self):
self.assertRaises(
rplanguage.LanguageError,
rplanguage.add_language,
key="binary2",
phonemes="w b d t oe ee, oo e o a wh dw bw", # erroneous comma
grammar="cvvv cvv cvvcv cvvcvvo cvvvc cvvvcvv cvvc c v cc vv ccvvc ccvvccvv ",
vowels="oea",
word_length_variance=4,
)
[docs] def test_available_languages(self):
self.assertEqual(list(sorted(rplanguage.available_languages())), ["binary", "testlang"])
[docs] def test_obfuscate_whisper(self):
self.assertEqual(rplanguage.obfuscate_whisper(text, level=0.0), text)
assert rplanguage.obfuscate_whisper(text, level=0.1).startswith(
"-utom-t-d t-sting is -dv-nt-g-ous for - numb-r of r--sons: t-sts m-y b- -x-cut-d"
" Continuously"
)
assert rplanguage.obfuscate_whisper(text, level=0.5).startswith(
"--------- --s---- -s -----------s f-- - ------ -f ---s--s: --s-s "
)
self.assertEqual(rplanguage.obfuscate_whisper(text, level=1.0), "...")
# Testing of emoting / sdesc / recog system
sdesc0 = "A nice sender of emotes"
sdesc1 = "The first receiver of emotes."
sdesc2 = "Another nice colliding sdesc-guy for tests"
recog01 = "Mr Receiver"
recog02 = "Mr Receiver2"
recog10 = "Mr Sender"
emote = 'With a flair, /me looks at /first and /colliding sdesc-guy. She says "This is a test."'
fallback_emote = "/Me is distracted from /first by /nomatch."
case_emote = "/Me looks at /first. Then, /me looks at /FIRST, /First and /Colliding twice."
poss_emote = "/Me frowns at /first for trying to steal /me's test."
[docs]class TestRPSystem(BaseEvenniaTest):
maxDiff = None
[docs] def setUp(self):
super().setUp()
self.room = create_object(rpsystem.ContribRPRoom, key="Location")
self.speaker = create_object(rpsystem.ContribRPCharacter, key="Sender", location=self.room)
self.receiver1 = create_object(
rpsystem.ContribRPCharacter, key="Receiver1", location=self.room
)
self.receiver2 = create_object(
rpsystem.ContribRPCharacter, key="Receiver2", location=self.room
)
[docs] def test_posed_contents(self):
self.obj1 = create_object(rpsystem.ContribRPObject, key="thing", location=self.room)
self.obj2 = create_object(rpsystem.ContribRPObject, key="thing", location=self.room)
self.obj3 = create_object(rpsystem.ContribRPObject, key="object", location=self.room)
room_display = self.room.return_appearance(self.speaker)
self.assertIn("An object and two things are here.", room_display)
self.obj3.db.pose = "is on the ground."
room_display = self.room.return_appearance(self.speaker)
self.assertIn("Two things are here.", room_display)
self.assertIn("An object is on the ground.", room_display)
[docs] def test_sdesc_handler(self):
self.speaker.sdesc.add(sdesc0)
self.assertEqual(self.speaker.sdesc.get(), sdesc0)
self.speaker.sdesc.add("This is {#324} ignored")
self.assertEqual(self.speaker.sdesc.get(), "This is 324 ignored")
[docs] def test_recog_handler(self):
self.speaker.sdesc.add(sdesc0)
self.receiver1.sdesc.add(sdesc1)
self.speaker.recog.add(self.receiver1, recog01)
self.speaker.recog.add(self.receiver2, recog02)
self.assertEqual(self.speaker.recog.get(self.receiver1), recog01)
self.assertEqual(self.speaker.recog.get(self.receiver2), recog02)
self.speaker.recog.remove(self.receiver1)
self.assertEqual(self.speaker.recog.get(self.receiver1), None)
self.assertEqual(self.speaker.recog.all(), {"Mr Receiver2": self.receiver2})
[docs] def test_parse_language(self):
self.assertEqual(
rpsystem.parse_language(self.speaker, emote),
(
"With a flair, /me looks at /first and /colliding sdesc-guy. She says {##0}",
{"##0": (None, '"This is a test."')},
),
)
language_emote = 'For a change of pace, /me says, elvish"This is in elvish!"'
self.assertEqual(
rpsystem.parse_language(self.speaker, language_emote),
(
"For a change of pace, /me says, {##0}",
{"##0": ("elvish", '"This is in elvish!"')},
),
)
[docs] def test_parse_sdescs_and_recogs(self):
speaker = self.speaker
speaker.sdesc.add(sdesc0)
self.receiver1.sdesc.add(sdesc1)
self.receiver2.sdesc.add(sdesc2)
id0 = f"#{speaker.id}"
id1 = f"#{self.receiver1.id}"
id2 = f"#{self.receiver2.id}"
candidates = (self.receiver1, self.receiver2)
result = (
"With a flair, {"
+ id0
+ "} looks at {"
+ id1
+ "} and {"
+ id2
+ '}. She says "This is a test."',
{
id2: self.receiver2,
id1: self.receiver1,
id0: speaker,
},
)
self.assertEqual(
rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote, case_sensitive=False),
result,
)
self.speaker.recog.add(self.receiver1, recog01)
self.assertEqual(
rpsystem.parse_sdescs_and_recogs(speaker, candidates, emote, case_sensitive=False),
result,
)
[docs] def test_possessive_selfref(self):
speaker = self.speaker
speaker.sdesc.add(sdesc0)
self.receiver1.sdesc.add(sdesc1)
self.receiver2.sdesc.add(sdesc2)
id0 = f"#{speaker.id}"
id1 = f"#{self.receiver1.id}"
id2 = f"#{self.receiver2.id}"
candidates = (self.receiver1, self.receiver2)
result = (
"{" + id0 + "} frowns at {" + id1 + "} for trying to steal {" + id0 + "}'s test.",
{
id1: self.receiver1,
id0: speaker,
},
)
self.assertEqual(
rpsystem.parse_sdescs_and_recogs(speaker, candidates, poss_emote, case_sensitive=False),
result,
)
[docs] def test_get_sdesc(self):
looker = self.speaker # Sender
target = self.receiver1 # Receiver1
looker.sdesc.add(sdesc0) # A nice sender of emotes
target.sdesc.add(sdesc1) # The first receiver of emotes.
# sdesc with no processing
self.assertEqual(looker.get_sdesc(target), "The first receiver of emotes.")
# sdesc with processing
self.assertEqual(
looker.get_sdesc(target, process=True), "|bThe first receiver of emotes.|n"
)
looker.recog.add(target, recog01) # Mr Receiver
# recog with no processing
self.assertEqual(looker.get_sdesc(target), "Mr Receiver")
# recog with processing
self.assertEqual(looker.get_sdesc(target, process=True), "|mMr Receiver|n")
[docs] def test_send_emote(self):
speaker = self.speaker
receiver1 = self.receiver1
receiver2 = self.receiver2
receivers = [speaker, receiver1, receiver2]
speaker.sdesc.add(sdesc0)
receiver1.sdesc.add(sdesc1)
receiver2.sdesc.add(sdesc2)
speaker.msg = lambda text, **kwargs: setattr(self, "out0", text)
receiver1.msg = lambda text, **kwargs: setattr(self, "out1", text)
receiver2.msg = lambda text, **kwargs: setattr(self, "out2", text)
rpsystem.send_emote(speaker, receivers, emote, case_sensitive=False)
self.assertEqual(
self.out0[0],
(
"With a flair, |mSender|n looks at |bThe first receiver of emotes.|n "
'and |bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n'
),
)
self.assertEqual(
self.out1[0],
(
"With a flair, |bA nice sender of emotes|n looks at |mReceiver1|n and "
'|bAnother nice colliding sdesc-guy for tests|n. She says |w"This is a test."|n'
),
)
self.assertEqual(
self.out2[0],
(
"With a flair, |bA nice sender of emotes|n looks at |bThe first "
'receiver of emotes.|n and |mReceiver2|n. She says |w"This is a test."|n'
),
)
[docs] def test_send_emote_fallback(self):
speaker = self.speaker
receiver1 = self.receiver1
receiver2 = self.receiver2
receivers = [speaker, receiver1, receiver2]
speaker.sdesc.add(sdesc0)
receiver1.sdesc.add(sdesc1)
receiver2.sdesc.add(sdesc2)
speaker.msg = lambda text, **kwargs: setattr(self, "out0", text)
receiver1.msg = lambda text, **kwargs: setattr(self, "out1", text)
receiver2.msg = lambda text, **kwargs: setattr(self, "out2", text)
rpsystem.send_emote(speaker, receivers, fallback_emote, fallback="something")
self.assertEqual(
self.out0[0],
"|mSender|n is distracted from |bthe first receiver of emotes.|n by something.",
)
self.assertEqual(
self.out1[0],
"|bA nice sender of emotes|n is distracted from |mReceiver1|n by something.",
)
self.assertEqual(
self.out2[0],
(
"|bA nice sender of emotes|n is distracted from |bthe first receiver of emotes.|n"
" by something."
),
)
[docs] def test_send_case_sensitive_emote(self):
"""Test new case-sensitive rp-parsing"""
speaker = self.speaker
receiver1 = self.receiver1
receiver2 = self.receiver2
receivers = [speaker, receiver1, receiver2]
speaker.sdesc.add(sdesc0)
receiver1.sdesc.add(sdesc1)
receiver2.sdesc.add(sdesc2)
speaker.msg = lambda text, **kwargs: setattr(self, "out0", text)
receiver1.msg = lambda text, **kwargs: setattr(self, "out1", text)
receiver2.msg = lambda text, **kwargs: setattr(self, "out2", text)
rpsystem.send_emote(speaker, receivers, case_emote)
self.assertEqual(
self.out0[0],
(
"|mSender|n looks at |bthe first receiver of emotes.|n. Then, |mSender|n "
"looks at |bTHE FIRST RECEIVER OF EMOTES.|n, |bThe first receiver of emotes.|n "
"and |bAnother nice colliding sdesc-guy for tests|n twice."
),
)
self.assertEqual(
self.out1[0],
(
"|bA nice sender of emotes|n looks at |mReceiver1|n. Then, "
"|ba nice sender of emotes|n looks at |mReceiver1|n, |mReceiver1|n "
"and |bAnother nice colliding sdesc-guy for tests|n twice."
),
)
self.assertEqual(
self.out2[0],
(
"|bA nice sender of emotes|n looks at |bthe first receiver of emotes.|n. "
"Then, |ba nice sender of emotes|n looks at |bTHE FIRST RECEIVER OF EMOTES.|n, "
"|bThe first receiver of emotes.|n and |mReceiver2|n twice."
),
)
[docs] def test_rpsearch(self):
self.speaker.sdesc.add(sdesc0)
self.receiver1.sdesc.add(sdesc1)
self.receiver2.sdesc.add(sdesc2)
self.speaker.msg = lambda text, **kwargs: setattr(self, "out0", text)
self.assertEqual(self.speaker.search("receiver of emotes"), self.receiver1)
self.assertEqual(self.speaker.search("colliding"), self.receiver2)
[docs] def test_get_search_result(self):
self.obj1 = create_object(rpsystem.ContribRPObject, key="Obj1", location=self.room)
self.obj1.sdesc.add("something")
self.obj2 = create_object(rpsystem.ContribRPCharacter, key="Obj2", location=self.room)
self.obj2.sdesc.add("something")
candidates = [self.obj1, self.obj2]
# search candidates by sdesc: both objects should be found
result = self.speaker.get_search_result("something", candidates)
self.assertEqual(list(result), candidates)
# search by sdesc with 2-disambiguator: only second object should be found
result = self.speaker.get_search_result("2-something", candidates)
self.assertEqual(list(result), [self.obj2])
# search empty candidates: no objects should be found
result = self.speaker.get_search_result("something", candidates=[])
self.assertEqual(list(result), [])
# typeclass was given: only matching object should be found
result = self.speaker.get_search_result(
"something", candidates=candidates, typeclass=rpsystem.ContribRPCharacter
)
self.assertEqual(list(result), [self.obj2])
# search by key with player permissions: no objects should be found
result = self.speaker.get_search_result("obj1", candidates)
self.assertEqual(list(result), [])
# search by key with builder permissions: object should be found
self.speaker.permissions.add("builder")
result = self.speaker.get_search_result("obj1", candidates)
self.assertEqual(list(result), [self.obj1])
# search by key with builder permissions when NOT IN candidates: object should NOT be found
result = self.speaker.get_search_result("obj1", [self.obj2])
self.assertEqual(list(result), [])
[docs]class TestRPSystemCommands(BaseEvenniaCommandTest):
[docs] def setUp(self):
super().setUp()
self.char1.swap_typeclass(rpsystem.ContribRPCharacter)
self.char2.swap_typeclass(rpsystem.ContribRPCharacter)
[docs] def test_commands(self):
self.call(
rpsystem.CmdSdesc(), "Foobar Character", "Char's sdesc was set to 'Foobar Character'."
)
self.call(
rpsystem.CmdSdesc(),
"BarFoo Character",
"Char2's sdesc was set to 'BarFoo Character'.",
caller=self.char2,
)
self.call(rpsystem.CmdSdesc(), "", 'Your short description is "Foobar Character".')
self.call(rpsystem.CmdSay(), "Hello!", 'Char says, "Hello!"')
self.call(rpsystem.CmdEmote(), "/me smiles to /BarFoo.", "Char smiles to BarFoo Character")
# escape urls in say
self.call(rpsystem.CmdSay(), "https://evennia.com", 'Char says, "https://evennia.com"')
self.call(rpsystem.CmdSay(), "http://evennia.com", 'Char says, "http://evennia.com"')
self.call(
rpsystem.CmdPose(),
"stands by the bar",
"Pose will read 'Foobar Character stands by the bar.'.",
)
self.call(
rpsystem.CmdRecog(),
"barfoo as friend",
"You will now remember BarFoo Character as friend.",
)
self.call(
rpsystem.CmdRecog(),
"",
(
"Currently recognized (use 'recog <sdesc> as <alias>' to add new "
"and 'forget <alias>' to remove):\n friend (BarFoo Character)"
),
)
self.call(
rpsystem.CmdRecog(),
"friend",
"You will now know them only as 'BarFoo Character'",
cmdstring="forget",
)
self.call(rpsystem.CmdSdesc(), "clear", 'Cleared sdesc, using name "Char".', inputs=["Y"])
[docs] def test_multi_match_search(self):
"""
Test that the multi-match search works as expected
"""
mushroom1 = create_object(rpsystem.ContribRPObject, key="Mushroom", location=self.room1)
mushroom1.db.desc = "The first mushroom is brown."
mushroom2 = create_object(rpsystem.ContribRPObject, key="Mushroom", location=self.room1)
mushroom2.db.desc = "The second mushroom is red."
# check locations and contents
self.assertEqual(self.char1.location, self.room1)
self.assertTrue(set(self.room1.contents).intersection(set([mushroom1, mushroom2])))
expected_first_call = [
"More than one match for 'Mushroom' (please narrow target):",
f" Mushroom-1",
f" Mushroom-2",
]
self.call(default_cmds.CmdLook(), "Mushroom", "\n".join(expected_first_call)) # PASSES
expected_second_call = f"Mushroom(#{mushroom1.id})\nThe first mushroom is brown."
self.call(default_cmds.CmdLook(), "Mushroom-1", expected_second_call) # FAILS
expected_third_call = f"Mushroom(#{mushroom2.id})\nThe second mushroom is red."
self.call(default_cmds.CmdLook(), "Mushroom-2", expected_third_call) # FAILS
expected_fourth_call = "Alias(es) for 'Mushroom' set to 'fungus'."
self.call(building.CmdSetObjAlias(), "Mushroom-1 = fungus", expected_fourth_call) # PASSES
expected_fifth_call = [
"More than one match for 'Mushroom' (please narrow target):",
f" Mushroom-1 [fungus]",
f" Mushroom-2",
]
self.call(default_cmds.CmdLook(), "Mushroom", "\n".join(expected_fifth_call)) # PASSES