evennia/src/commands/default/tests.py

503 lines
21 KiB
Python

# -*- coding: utf-8 -*-
"""
** OBS - this is not a normal command module! **
** You cannot import anything in this module as a command! **
This is part of the Evennia unittest framework, for testing the
stability and integrity of the codebase during updates. This module
test the default command set. It is instantiated by the
src/objects/tests.py module, which in turn is run by as part of the
main test suite started with
> python game/manage.py test.
"""
import re, time
try:
# this is a special optimized Django version, only available in current Django devel
from django.utils.unittest import TestCase
except ImportError:
from django.test import TestCase
from django.conf import settings
from src.utils import create, ansi
from src.server import serversession, sessionhandler
from src.locks.lockhandler import LockHandler
from src.server.models import ServerConfig
from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
from django.contrib.auth.models import User
from src.players.models import PlayerDB
from src.objects.models import ObjectDB
#------------------------------------------------------------
# Command testing
# ------------------------------------------------------------
# print all feedback from test commands (can become very verbose!)
VERBOSE = False
def cleanup():
User.objects.all().delete()
PlayerDB.objects.all().delete()
ObjectDB.objects.all().delete()
Channel.objects.all().delete()
Msg.objects.all().delete()
PlayerChannelConnection.objects.all().delete()
ExternalChannelConnection.objects.all().delete()
ServerConfig.objects.all().delete()
class FakeSessionHandler(sessionhandler.ServerSessionHandler):
"""
Fake sessionhandler, without an amp connection
"""
def portal_shutdown(self):
pass
def disconnect(self, session, reason=""):
pass
def login(self, session):
pass
def session_sync(self):
pass
def data_out(self, session, string="", data=""):
return string
SESSIONS = FakeSessionHandler()
class FakeSession(serversession.ServerSession):
"""
A fake session that
implements dummy versions of the real thing; this is needed to
mimic a logged-in player.
"""
protocol_key = "TestProtocol"
sessdict = {'protocol_key':'telnet', 'address':('0.0.0.0','5000'), 'sessid':2, 'uid':2, 'uname':None,
'logged_in':False, 'cid':None, 'ndb':{}, 'encoding':'utf-8',
'conn_time':time.time(), 'cmd_last':time.time(), 'cmd_last_visible':time.time(), 'cmd_total':1}
def connectionMade(self):
self.load_sync_data(self.sessdict)
self.sessionhandler = SESSIONS
def disconnectClient(self):
pass
def lineReceived(self, raw_string):
pass
def msg(self, message, data=None):
if message.startswith("Traceback (most recent call last):"):
#retval = "Traceback last line: %s" % message.split('\n')[-4:]
raise AssertionError(message)
if self.player.character.ndb.return_string != None:
return_list = self.player.character.ndb.return_string
if hasattr(return_list, '__iter__'):
rstring = return_list.pop(0)
self.player.character.ndb.return_string = return_list
else:
rstring = return_list
self.player.character.ndb.return_string = None
message_noansi = ansi.parse_ansi(message, strip_ansi=True).strip()
rstring = rstring.strip()
if not message_noansi.startswith(rstring):
sep1 = "\n" + "="*30 + "Wanted message" + "="*34 + "\n"
sep2 = "\n" + "="*30 + "Returned message" + "="*32 + "\n"
sep3 = "\n" + "="*78
retval = sep1 + rstring + sep2 + message_noansi + sep3
raise AssertionError(retval)
if VERBOSE:
print message
class CommandTest(TestCase):
"""
Sets up the basics of testing the default commands and the generic things
that should always be present in a command.
Inherit new tests from this.
"""
NOMANGLE = True # mangle command input for extra testing
def setUp(self):
"sets up the testing environment"
#ServerConfig.objects.conf("default_home", 2)
self.addCleanup(cleanup)
self.room1 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room1")
self.room2 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room2")
# create a faux player/character for testing.
self.char1 = create.create_player("TestChar", "testplayer@test.com", "testpassword", character_location=self.room1)
self.char1.player.user.is_superuser = True
self.char1.lock_storage = ""
self.char1.locks = LockHandler(self.char1)
self.char1.ndb.return_string = None
sess = FakeSession()
sess.connectionMade()
sess.session_login(self.char1.player)
# create second player
self.char2 = create.create_player("TestChar2", "testplayer2@test.com", "testpassword2", character_location=self.room1)
self.char2.player.user.is_superuser = False
self.char2.lock_storage = ""
self.char2.locks = LockHandler(self.char2)
self.char2.ndb.return_string = None
sess2 = FakeSession()
sess2.connectionMade()
sess2.session_login(self.char2.player)
# A non-player-controlled character
self.char3 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="TestChar3", location=self.room1)
# create some objects
self.obj1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=self.room1)
self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
self.exit1 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit1", location=self.room1)
self.exit2 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit2", location=self.room2)
def tearDown(self):
"Cleans up testing environment after test has run."
User.objects.all().delete()
PlayerDB.objects.all().delete()
ObjectDB.objects.all().delete()
Channel.objects.all().delete()
Msg.objects.all().delete()
PlayerChannelConnection.objects.all().delete()
ExternalChannelConnection.objects.all().delete()
ServerConfig.objects.all().delete()
def get_cmd(self, cmd_class, argument_string=""):
"""
Obtain a cmd instance from a class and an input string
Note: This does not make use of the cmdhandler functionality.
"""
cmd = cmd_class()
cmd.caller = self.char1
cmd.cmdstring = cmd_class.key
cmd.args = argument_string
cmd.cmdset = None
cmd.obj = self.char1
return cmd
def execute_cmd(self, raw_string, wanted_return_string=None, nomangle=False):
"""
Creates the command through faking a normal command call;
This also mangles the input in various ways to test if the command
will be fooled.
"""
if not nomangle and not VERBOSE and not self.NOMANGLE:
# only mangle if not VERBOSE, to make fewer return lines
test1 = re.sub(r'\s', '', raw_string) # remove all whitespace inside it
test2 = "%s/åäö öäö;-:$£@*~^' 'test" % raw_string # inserting weird characters in call
test3 = "%s %s" % (raw_string, raw_string) # multiple calls
self.char1.execute_cmd(test1)
self.char1.execute_cmd(test2)
self.char1.execute_cmd(test3)
# actual call, we potentially check so return is ok.
self.char1.ndb.return_string = wanted_return_string
try:
self.char1.execute_cmd(raw_string)
except AssertionError, e:
self.fail(e)
self.char1.ndb.return_string = None
class BuildTest(CommandTest):
"""
We need to turn of mangling for build commands since
it creates arbitrary objects that mess up tests later.
"""
NOMANGLE = True
#------------------------------------------------------------
# Default set Command testing
#------------------------------------------------------------
# # general.py tests
class TestLook(CommandTest):
def test_call(self):
self.execute_cmd("look here")
class TestHome(CommandTest):
def test_call(self):
self.char1.location = self.room1
self.char1.home = self.room2
self.execute_cmd("home")
self.assertEqual(self.char1.location, self.room2)
class TestPassword(CommandTest):
def test_call(self):
self.execute_cmd("@password testpassword = newpassword")
class TestInventory(CommandTest):
def test_call(self):
self.execute_cmd("inv")
class TestQuit(CommandTest):
def test_call(self):
self.execute_cmd("@quit")
class TestPose(CommandTest):
def test_call(self):
self.execute_cmd("pose is testing","TestChar is testing")
class TestNick(CommandTest):
def test_call(self):
self.char1.player.user.is_superuser = False
self.execute_cmd("nickname testalias = testaliasedstring1")
self.execute_cmd("nickname/player testalias = testaliasedstring2")
self.execute_cmd("nickname/object testalias = testaliasedstring3")
self.assertEqual(u"testaliasedstring1", self.char1.nicks.get("testalias"))
self.assertEqual(u"testaliasedstring2", self.char1.nicks.get("testalias",nick_type="player"))
self.assertEqual(u"testaliasedstring3", self.char1.nicks.get("testalias",nick_type="object"))
class TestGet(CommandTest):
def test_call(self):
self.obj1.location = self.room1
self.execute_cmd("get obj1", "You pick up obj1.")
class TestDrop(CommandTest):
def test_call(self):
self.obj1.location = self.char1
self.execute_cmd("drop obj1", "You drop obj1.")
class TestWho(CommandTest):
def test_call(self):
self.execute_cmd("who")
class TestSay(CommandTest):
def test_call(self):
self.execute_cmd("say Hello", 'You say, "Hello')
class TestAccess(CommandTest):
def test_call(self):
self.execute_cmd("access")
class TestEncoding(CommandTest):
def test_call(self):
global NOMANGLE
NOMANGLE = True
self.char1.db.encoding="utf-8"
self.execute_cmd("@encoding", "Default encoding:")
NOMANGLE = False
# help.py command tests
class TestHelpSystem(CommandTest):
def test_call(self):
self.NOMANGLE = True
sep = "-"*78 + "\n"
self.execute_cmd("@help/add TestTopic,TestCategory = Test1", )
self.execute_cmd("help TestTopic",sep + "Help topic for Testtopic\nTest1" + "\n" + sep)
self.execute_cmd("@help/merge TestTopic = Test2", "Added the new text right after")
self.execute_cmd("help TestTopic", sep + "Help topic for Testtopic\nTest1 Test2")
self.execute_cmd("@help/append TestTopic = Test3", "Added the new text as a")
self.execute_cmd("help TestTopic",sep + "Help topic for Testtopic\nTest1 Test2\n\nTest3")
self.execute_cmd("@help/delete TestTopic","Deleted the help entry")
self.execute_cmd("help TestTopic","No help entry found for 'TestTopic'")
# system.py command tests
class TestPy(CommandTest):
def test_call(self):
self.execute_cmd("@py 1+2", [">>> 1+2", "<<< 3"])
class TestScripts(CommandTest):
def test_call(self):
script = create.create_script(None, "test")
self.execute_cmd("@scripts", "id")
class TestObjects(CommandTest):
def test_call(self):
self.execute_cmd("@objects", "Database totals")
# Cannot be tested since we don't have an active server running at this point.
# class TestListService(CommandTest):
# def test_call(self):
# self.execute_cmd("@service/list", "---")
class TestVersion(CommandTest):
def test_call(self):
self.execute_cmd("@version", '---')
class TestTime(CommandTest):
def test_call(self):
self.execute_cmd("@time", "Current server uptime")
class TestServerLoad(CommandTest):
def test_call(self):
self.execute_cmd("@serverload", "Server load")
class TestPs(CommandTest):
def test_call(self):
self.execute_cmd("@ps","Non-timed scripts")
# admin.py command tests
class TestBoot(CommandTest):
def test_call(self):
self.execute_cmd("@boot TestChar2","You booted TestChar2.")
class TestDelPlayer(CommandTest):
def test_call(self):
self.execute_cmd("@delplayer TestChar2","Booting and informing player ...")
class TestEmit(CommandTest):
def test_call(self):
self.execute_cmd("@emit Test message", "Emitted to room1.")
class TestUserPassword(CommandTest):
def test_call(self):
self.execute_cmd("@userpassword TestChar2 = newpass", "TestChar2 - new password set to 'newpass'.")
class TestPerm(CommandTest):
def test_call(self):
self.execute_cmd("@perm TestChar2 = Builders", "Permission 'Builders' given to")
# cannot test this here; screws up the test suite
#class TestPuppet(CommandTest):
# def test_call(self):
# self.execute_cmd("@puppet TestChar3", "You now control TestChar3.")
# self.execute_cmd("@puppet TestChar", "You now control TestChar.")
class TestWall(CommandTest):
def test_call(self):
self.execute_cmd("@wall = This is a test message", "TestChar shouts")
# building.py command tests
class TestObjAlias(BuildTest):
def test_call(self):
self.execute_cmd("@alias obj1 = obj1alias, obj1alias2", "Aliases for")
self.execute_cmd("look obj1alias2", "obj1")
class TestCopy(BuildTest):
def test_call(self):
self.execute_cmd("@copy obj1 = obj1_copy;alias1;alias2", "Copied obj1 to 'obj1_copy'")
self.execute_cmd("look alias2","obj1_copy")
class TestSet(BuildTest):
def test_call(self):
self.execute_cmd("@set obj1/test = value", "Created attribute obj1/test = value")
self.execute_cmd("@set obj1/test", "Attribute obj1/test = value")
self.assertEqual(self.obj1.db.test, u"value")
class TestCpAttr(BuildTest):
def test_call(self):
self.execute_cmd("@set obj1/test = value")
self.execute_cmd("@set me/test2 = value2")
self.execute_cmd("@cpattr obj1/test = obj2/test")
self.execute_cmd("@cpattr test2 = obj2")
self.assertEqual(self.obj2.db.test, u"value")
self.assertEqual(self.obj2.db.test2, u"value2")
class TestMvAttr(BuildTest):
def test_call(self):
self.execute_cmd("@set obj1/test = value")
self.execute_cmd("@mvattr obj1/test = obj2")
self.assertEqual(self.obj2.db.test, u"value")
self.assertEqual(self.obj1.db.test, None)
class TestCreate(BuildTest):
def test_call(self):
self.execute_cmd("@create testobj;alias1;alias2")
self.execute_cmd("look alias1", "testobj")
class TestDebug(BuildTest):
def test_call(self):
self.execute_cmd("@debug/obj obj1")
class TestDesc(BuildTest):
def test_call(self):
self.execute_cmd("@desc obj1 = Test object", "The description was set on")
self.assertEqual(self.obj1.db.desc, u"Test object")
class TestDestroy(BuildTest):
def test_call(self):
self.execute_cmd("@destroy obj1, obj2", "obj1 was destroyed.\nobj2 was destroyed.")
class TestFind(BuildTest):
def test_call(self):
self.execute_cmd("@find obj1", "One Match")
class TestDig(BuildTest):
def test_call(self):
self.execute_cmd("@dig room3;roomalias1;roomalias2 = north;n,south;s")
self.execute_cmd("@find room3", "One Match")
self.execute_cmd("@find roomalias1", "One Match")
self.execute_cmd("@find roomalias2", "One Match")
self.execute_cmd("@find/room roomalias2", "One Match")
self.execute_cmd("@find/exit south", "One Match")
self.execute_cmd("@find/exit n", "One Match")
class TestUnLink(BuildTest):
def test_call(self):
self.execute_cmd("@dig room3;roomalias1, north, south")
self.execute_cmd("@unlink north")
class TestLink(BuildTest):
def test_call(self):
self.execute_cmd("@dig room3;roomalias1, north, south")
self.execute_cmd("@unlink north")
self.execute_cmd("@link north = room3")
class TestHome(BuildTest):
def test_call(self):
self.obj1.db_home = self.obj2.dbobj
self.obj1.save()
self.execute_cmd("@home obj1")
self.assertEqual(self.obj1.db_home, self.obj2.dbobj)
class TestCmdSets(BuildTest):
def test_call(self):
self.execute_cmd("@cmdsets")
self.execute_cmd("@cmdsets obj1")
class TestDesc(BuildTest):
def test_call(self):
self.execute_cmd("@name obj1 = Test object", "Object's name changed to 'Test object'.")
self.assertEqual(self.obj1.key, u"Test object")
class TestOpen(BuildTest):
def test_call(self):
self.execute_cmd("@dig room4;roomalias4")
self.execute_cmd("@open testexit4;aliasexit4 = roomalias4", "Created new Exit")
class TestScript(BuildTest):
def test_call(self):
self.execute_cmd("@typeclass obj1 = src.objects.objects.Character", "obj's type is now")
self.assertEqual(self.obj1.db_typeclass_path, u"src.objects.objects.Character")
class TestScript(BuildTest):
def test_call(self):
self.execute_cmd("@set box1/test = value")
self.execute_cmd("@wipe box1", "Wiped")
self.assertEqual(self.obj1.db.all(), [])
class TestLock(BuildTest):
# lock functionality itseld is tested separately
def test_call(self):
self.char1.permissions = ["TestPerm"]
self.execute_cmd("@lock obj1 = test:perm(TestPerm)")
self.assertEqual(True, self.obj1.access(self.char1, u"test"))
class TestExamine(BuildTest):
def test_call(self):
self.execute_cmd("examine obj1", "------------")
class TestTeleport(BuildTest):
def test_call(self):
self.execute_cmd("@tel obj1 = obj2")
self.assertEqual(self.obj1.location, self.obj2.dbobj)
class TestScript(BuildTest):
def test_call(self):
self.execute_cmd("@script TestChar = examples.bodyfunctions.BodyFunctions", "Script successfully added")
# Comms commands
class TestChannelCreate(CommandTest):
def test_call(self):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("testchan1 Hello", "[testchannel1] TestChar: Hello")
class TestAddCom(CommandTest):
def test_call(self):
self.execute_cmd("@cdestroy testchannel1", "Channel 'testchannel1'")
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("addcom chan1 = testchannel1")
self.execute_cmd("addcom chan2 = testchan1")
self.execute_cmd("delcom testchannel1")
self.execute_cmd("addcom testchannel1" "You now listen to the channel channel.")
class TestDelCom(CommandTest):
def test_call(self):
self.execute_cmd("@cdestroy testchannel1", "Channel 'testchannel1'")
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("addcom chan1 = testchan1")
self.execute_cmd("addcom chan2 = testchan1b")
self.execute_cmd("addcom chan3 = testchannel1")
self.execute_cmd("delcom chan1", "Your alias 'chan1' for ")
self.execute_cmd("delcom chan2", "Your alias 'chan2' for ")
self.execute_cmd("delcom testchannel1" "You stop listening to")
class TestAllCom(CommandTest):
def test_call(self):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("allcom off")
self.execute_cmd("allcom on")
self.execute_cmd("allcom destroy")
class TestChannels(CommandTest):
def test_call(self):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("@cdestroy testchannel1", "Channel 'testchannel1'")
class TestCBoot(CommandTest):
def test_call(self):
self.execute_cmd("@cdestroy testchannel1", "Channel 'testchannel1'")
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("addcom testchan = testchannel1")
self.execute_cmd("@cboot testchannel1 = TestChar", "TestChar boots TestChar from channel.")
class TestCemit(CommandTest):
def test_call(self):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("@cemit testchan1 = Testing!", "[testchannel1] Testing!")
class TestCwho(CommandTest):
def test_call(self):
self.execute_cmd("@ccreate testchannel1;testchan1;testchan1b = This is a test channel")
self.execute_cmd("@cwho testchan1b", "Channel subscriptions")
# OOC commands
#class TestOOC_and_IC(CommandTest): # can't be tested it seems, causes errors in other commands (?)
# def test_call(self):
# self.execute_cmd("@ooc", "\nYou go OOC.")
# self.execute_cmd("@ic", "\nYou become TestChar")
# Unloggedin commands
# these cannot be tested from here.