Refactor all test classes into evennia.utils.test_resources. Update docs.
This commit is contained in:
parent
7912351e01
commit
bbf45af2dd
28 changed files with 528 additions and 588 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
# Unit Testing
|
# Unit Testing
|
||||||
|
|
||||||
|
|
||||||
*Unit testing* means testing components of a program in isolation from each other to make sure every
|
*Unit testing* means testing components of a program in isolation from each other to make sure every
|
||||||
part works on its own before using it with others. Extensive testing helps avoid new updates causing
|
part works on its own before using it with others. Extensive testing helps avoid new updates causing
|
||||||
unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia
|
unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia
|
||||||
|
|
@ -31,9 +30,9 @@ how many tests were run and how long it took. If something went wrong you will g
|
||||||
If you contribute to Evennia, this is a useful sanity check to see you haven't introduced an
|
If you contribute to Evennia, this is a useful sanity check to see you haven't introduced an
|
||||||
unexpected bug.
|
unexpected bug.
|
||||||
|
|
||||||
## Running tests with custom settings file
|
## Running tests for your game dir
|
||||||
|
|
||||||
If you have implemented your own tests for your game (see below) you can run them from your game dir
|
If you have implemented your own tests for your game you can run them from your game dir
|
||||||
with
|
with
|
||||||
|
|
||||||
evennia test .
|
evennia test .
|
||||||
|
|
@ -41,8 +40,8 @@ with
|
||||||
The period (`.`) means to run all tests found in the current directory and all subdirectories. You
|
The period (`.`) means to run all tests found in the current directory and all subdirectories. You
|
||||||
could also specify, say, `typeclasses` or `world` if you wanted to just run tests in those subdirs.
|
could also specify, say, `typeclasses` or `world` if you wanted to just run tests in those subdirs.
|
||||||
|
|
||||||
Those tests will all be run using the default settings. To run the tests with your own settings file
|
An important thing to note is that those tests will all be run using the _default Evennia settings_.
|
||||||
you must use the `--settings` option:
|
To run the tests with your own settings file you must use the `--settings` option:
|
||||||
|
|
||||||
evennia test --settings settings.py .
|
evennia test --settings settings.py .
|
||||||
|
|
||||||
|
|
@ -50,108 +49,184 @@ The `--settings` option of Evennia takes a file name in the `mygame/server/conf`
|
||||||
normally used to swap settings files for testing and development. In combination with `test`, it
|
normally used to swap settings files for testing and development. In combination with `test`, it
|
||||||
forces Evennia to use this settings file over the default one.
|
forces Evennia to use this settings file over the default one.
|
||||||
|
|
||||||
|
You can also test specific things by giving their path
|
||||||
|
|
||||||
|
evennia test --settings settings.py .world.tests.YourTest
|
||||||
|
|
||||||
|
|
||||||
## Writing new tests
|
## Writing new tests
|
||||||
|
|
||||||
Evennia's test suite makes use of Django unit test system, which in turn relies on Python's
|
Evennia's test suite makes use of Django unit test system, which in turn relies on Python's
|
||||||
*unittest* module.
|
*unittest* module.
|
||||||
|
|
||||||
> If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io
|
|
||||||
page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of
|
|
||||||
test coverage and which does not.
|
|
||||||
|
|
||||||
To make the test runner find the tests, they must be put in a module named `test*.py` (so `test.py`,
|
To make the test runner find the tests, they must be put in a module named `test*.py` (so `test.py`,
|
||||||
`tests.py` etc). Such a test module will be found wherever it is in the package. It can be a good
|
`tests.py` etc). Such a test module will be found wherever it is in the package. It can be a good
|
||||||
idea to look at some of Evennia's `tests.py` modules to see how they look.
|
idea to look at some of Evennia's `tests.py` modules to see how they look.
|
||||||
|
|
||||||
Inside a testing file, a `unittest.TestCase` class is used to test a single aspect or component in
|
Inside the module you need to put a class inheriting (at any distance) from `unittest.TestCase`. Each
|
||||||
various ways. Each test case contains one or more *test methods* - these define the actual tests to
|
method on that class that starts with `test_` will be run separately as a unit test. There
|
||||||
run. You can name the test methods anything you want as long as the name starts with "`test_`".
|
are two special, optional methods `setUp` and `tearDown` that will (if you define them) run before
|
||||||
Your `TestCase` class can also have a method `setUp()`. This is run before each test, setting up and
|
_every_ test. This can be useful for setting up and deleting things.
|
||||||
storing whatever preparations the test methods need. Conversely, a `tearDown()` method can
|
|
||||||
optionally do cleanup after each test.
|
|
||||||
|
|
||||||
To test the results, you use special methods of the `TestCase` class. Many of those start with
|
To actually test things, you use special `assert...` methods on the class. Most common on is
|
||||||
"`assert`", such as `assertEqual` or `assertTrue`.
|
`assertEqual`, which makes sure a result is what you expect it to be.
|
||||||
|
|
||||||
Example of a `TestCase` class:
|
Here's an example of the principle. Let's assume you put this in `mygame/world/tests.py`
|
||||||
|
and want to test a function in `mygame/world/myfunctions.py`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# in a module tests.py somewhere i your game dir
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from evennia import create_object
|
||||||
# the function we want to test
|
# the function we want to test
|
||||||
from mypath import myfunc
|
from .myfunctions import myfunc
|
||||||
|
|
||||||
|
|
||||||
class TestObj(unittest.TestCase):
|
class TestObj(unittest.TestCase):
|
||||||
"This tests a function myfunc."
|
"This tests a function myfunc."
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""done before every of the test_ * methods below"""
|
||||||
|
self.obj = create_object("mytestobject")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""done after every test_* method below """
|
||||||
|
self.obj.delete()
|
||||||
|
|
||||||
def test_return_value(self):
|
def test_return_value(self):
|
||||||
"test method. Makes sure return value is as expected."
|
"""test method. Makes sure return value is as expected."""
|
||||||
expected_return = "This is me being nice."
|
actual_return = myfunc(self.obj)
|
||||||
actual_return = myfunc()
|
expected_return = "This is the good object 'mytestobject'."
|
||||||
# test
|
# test
|
||||||
self.assertEqual(expected_return, actual_return)
|
self.assertEqual(expected_return, actual_return)
|
||||||
def test_alternative_call(self):
|
def test_alternative_call(self):
|
||||||
"test method. Calls with a keyword argument."
|
"""test method. Calls with a keyword argument."""
|
||||||
expected_return = "This is me being baaaad."
|
actual_return = myfunc(self.obj, bad=True)
|
||||||
actual_return = myfunc(bad=True)
|
expected_return = "This is the baaad object 'mytestobject'."
|
||||||
# test
|
# test
|
||||||
self.assertEqual(expected_return, actual_return)
|
self.assertEqual(expected_return, actual_return)
|
||||||
```
|
```
|
||||||
|
|
||||||
You might also want to read the [documentation for the unittest
|
To test this, run
|
||||||
module](https://docs.python.org/library/unittest.html).
|
|
||||||
|
|
||||||
### Using the EvenniaTest class
|
evennia test --settings settings.py .
|
||||||
|
|
||||||
Evennia offers a custom TestCase, the `evennia.utils.test_resources.EvenniaTest` class. This class
|
to run the entire test module
|
||||||
initiates a range of useful properties on themselves for testing Evennia systems. Examples are
|
|
||||||
`.account` and `.session` representing a mock connected Account and its Session and `.char1` and
|
evennia test --settings setings.py .world.tests
|
||||||
`char2` representing Characters complete with a location in the test database. These are all useful
|
|
||||||
when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full
|
or a specific class:
|
||||||
definition of the `EvenniaTest` class in
|
|
||||||
[evennia/utils/test_resources.py](https://github.com/evennia/evennia/blob/master/evennia/utils/test_resources.py).
|
evennia test --settings settings.py .world.tests.TestObj
|
||||||
|
|
||||||
|
You can also run a specific test:
|
||||||
|
|
||||||
|
evennia test --settings settings.py .world.tests.TestObj.test_alternative_call
|
||||||
|
|
||||||
|
You might also want to read the [Python documentation for the unittest module](https://docs.python.org/library/unittest.html).
|
||||||
|
|
||||||
|
## Using the Evennia testing classes
|
||||||
|
|
||||||
|
Evennia offers many custom testing classes that helps with testing Evennia features.
|
||||||
|
They are all found in [evennia.utils.test_resources](evennia.utils.test_resources). Note that
|
||||||
|
these classes implement the `setUp` and `tearDown` already, so if you want to add stuff in them
|
||||||
|
yourself you should remember to use e.g. `super().setUp()` in your code.
|
||||||
|
|
||||||
|
### Classes for testing your game dir
|
||||||
|
|
||||||
|
These all use whatever setting you pass to them and works well for testing code in your game dir.
|
||||||
|
|
||||||
|
- `EvenniaTest` - this sets up a full object environment for your test. All the created entities
|
||||||
|
can be accesses as properties on the class:
|
||||||
|
- `.account` - A fake [Account](evennia.accounts.accounts.DefaultAccount) named "TestAccount".
|
||||||
|
- `.account2` - Another account named "TestAccount2"
|
||||||
|
- `char1` - A [Character](evennia.objects.objects.DefaultCharacter) linked to `.account`, named `Char`.
|
||||||
|
This has 'Developer' permissions but is not a superuser.
|
||||||
|
- `.char2` - Another character linked to `account`, named `Char2`. This has base permissions (player).
|
||||||
|
- `.obj1` - A regular [Object](evennia.objects.objects.DefaultObject) named "Obj".
|
||||||
|
- `.obj2` - Another object named "Obj2".
|
||||||
|
- `.room1` - A [Room](evennia.objects.objects.DefaultRoom) named "Room". Both characters and both
|
||||||
|
objects are located inside this room. It has a description of "room_desc".
|
||||||
|
- `.room2` - Another room named "Room2". It is empty and has no set description.
|
||||||
|
- `.exit` - An exit named "out" that leads from `.room1` to `.room2`.
|
||||||
|
- `.script` - A [Script](evennia.scripts.scripts.DefaultScript) named "Script". It's an inert script
|
||||||
|
without a timing component.
|
||||||
|
- `.session` - A fake [Session](evennia.server.serversession.ServerSession) that mimics a player
|
||||||
|
connecting to the game. It is used by `.account1` and has a sessid of 1.
|
||||||
|
- `EvenniaCommandTest` - has the same environment like `EvenniaTest` but also adds a special
|
||||||
|
[.call()](evennia.utils.test_resources.EvenniaCommandTestMixin.call) method specifically for
|
||||||
|
testing Evennia [Commands](Commands.md). It allows you to compare what the command _actually_
|
||||||
|
returns to the player with what you expect. Read the `call` api doc for more info.
|
||||||
|
- `EvenniaTestCase` - This is identical to the regular Python `TestCase` class, it's
|
||||||
|
just there for naming symmetry with `BaseEvenniaTestCase` below.
|
||||||
|
|
||||||
|
Here's an example of using `EvenniaTest`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# in a test module
|
# in a test module
|
||||||
|
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest
|
from evennia.utils.test_resources import EvenniaTest
|
||||||
|
|
||||||
|
class TestObject(EvenniaTest):
|
||||||
class TestObject(BaseEvenniaTest):
|
"""Remember that the testing class creates char1 and char2 inside room1 ..."""
|
||||||
def test_object_search(self):
|
def test_object_search_character(self):
|
||||||
# char1 and char2 are both created in room1
|
"""Check that char1 can search for char2 by name"""
|
||||||
self.assertEqual(self.char1.search(self.char2.key), self.char2)
|
self.assertEqual(self.char1.search(self.char2.key), self.char2)
|
||||||
|
|
||||||
|
def test_location_search(self):
|
||||||
|
"""Check so that char1 can find the current location by name"""
|
||||||
self.assertEqual(self.char1.search(self.char1.location.key), self.char1.location)
|
self.assertEqual(self.char1.search(self.char1.location.key), self.char1.location)
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### Testing in-game Commands
|
This example tests a custom command.
|
||||||
|
|
||||||
In-game Commands are a special case. Tests for the default commands are put in
|
|
||||||
`evennia/commands/default/tests.py`. This uses a custom `CommandTest` class that inherits from
|
|
||||||
`evennia.utils.test_resources.EvenniaTest` described above. `CommandTest` supplies extra convenience
|
|
||||||
functions for executing commands and check that their return values (calls of `msg()` returns
|
|
||||||
expected values. It uses Characters and Sessions generated on the `EvenniaTest` class to call each
|
|
||||||
class).
|
|
||||||
|
|
||||||
Each command tested should have its own `TestCase` class. Inherit this class from the `CommandTest`
|
|
||||||
class in the same module to get access to the command-specific utilities mentioned.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from evennia.commands.default.tests import CommandTest
|
from evennia.commands.default.tests import EvenniaCommandTest
|
||||||
from evennia.commands.default import general
|
from commands import command as mycommand
|
||||||
class TestSet(CommandTest):
|
|
||||||
"tests the look command by simple call, using Char2 as a target"
|
|
||||||
def test_mycmd_char(self):
|
class TestSet(EvenniaCommandTest):
|
||||||
self.call(general.CmdLook(), "Char2", "Char2(#7)")
|
"tests the look command by simple call, using Char2 as a target"
|
||||||
|
|
||||||
|
def test_mycmd_char(self):
|
||||||
|
self.call(mycommand.CmdMyLook(), "Char2", "Char2(#7)")
|
||||||
|
|
||||||
|
def test_mycmd_room(self):
|
||||||
"tests the look command by simple call, with target as room"
|
"tests the look command by simple call, with target as room"
|
||||||
def test_mycmd_room(self):
|
self.call(mycommand.CmdMyLook(), "Room",
|
||||||
self.call(general.CmdLook(), "Room",
|
"Room(#1)\nroom_desc\nExits: out(#3)\n"
|
||||||
"Room(#1)\nroom_desc\nExits: out(#3)\n"
|
"You see: Obj(#4), Obj2(#5), Char2(#7)")
|
||||||
"You see: Obj(#4), Obj2(#5), Char2(#7)")
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Unit testing contribs with custom models
|
When using `.call`, you don't need to specify the entire string; you can just give the beginning
|
||||||
|
of it and if it matches, that's enough. Use `\n` to denote line breaks and (this is a special for
|
||||||
|
the `.call` helper), `||` to indicate multiple uses of `.msg()` in the Command. The `.call` helper
|
||||||
|
has a lot of arguments for mimicing different ways of calling a Command, so make sure to
|
||||||
|
[read the API docs for .call()](evennia.utils.test_resources.EvenniaCommandTestMixin.call).
|
||||||
|
|
||||||
|
### Classes for testing Evennia core
|
||||||
|
|
||||||
|
These are used for testing Evennia itself. They provide the same resources as the classes
|
||||||
|
above but enforce Evennias default settings found in `evennia/settings_default.py`, ignoring
|
||||||
|
any settings changes in your game dir.
|
||||||
|
|
||||||
|
- `BaseEvenniaTest` - all the default objects above but with enforced default settings
|
||||||
|
- `BaseEvenniaCommandTest` - for testing Commands, but with enforced default settings
|
||||||
|
- `BaseEvenniaTestCase` - no default objects, only enforced default settings
|
||||||
|
|
||||||
|
There are also two special 'mixin' classes. These are uses in the classes above, but may also
|
||||||
|
be useful if you want to mix your own testing classes:
|
||||||
|
|
||||||
|
- `EvenniaTestMixin` - A class mixin that creates all test environment objects.
|
||||||
|
- `EvenniaCommandMixin` - A class mixin that adds the `.call()` Command-tester helper.
|
||||||
|
|
||||||
|
If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io
|
||||||
|
page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of
|
||||||
|
test coverage and which does not. All help is appreciated!
|
||||||
|
|
||||||
|
## Unit testing contribs with custom models
|
||||||
|
|
||||||
A special case is if you were to create a contribution to go to the `evennia/contrib` folder that
|
A special case is if you were to create a contribution to go to the `evennia/contrib` folder that
|
||||||
uses its [own database models](../Concepts/New-Models.md). The problem with this is that Evennia (and Django) will
|
uses its [own database models](../Concepts/New-Models.md). The problem with this is that Evennia (and Django) will
|
||||||
|
|
@ -216,14 +291,8 @@ class TestMyModel(BaseEvenniaTest):
|
||||||
# test case here
|
# test case here
|
||||||
```
|
```
|
||||||
|
|
||||||
### A note on adding new tests
|
|
||||||
|
|
||||||
Having an extensive tests suite is very important for avoiding code degradation as Evennia is
|
## A note on making the test runner faster
|
||||||
developed. Only a small fraction of the Evennia codebase is covered by test suites at this point.
|
|
||||||
Writing new tests is not hard, it's more a matter of finding the time to do so. So adding new tests
|
|
||||||
is really an area where everyone can contribute, also with only limited Python skills.
|
|
||||||
|
|
||||||
### A note on making the test runner faster
|
|
||||||
|
|
||||||
If you have custom models with a large number of migrations, creating the test database can take a
|
If you have custom models with a large number of migrations, creating the test database can take a
|
||||||
very long time. If you don't require migrations to run for your tests, you can disable them with the
|
very long time. If you don't require migrations to run for your tests, you can disable them with the
|
||||||
|
|
@ -247,155 +316,3 @@ After doing so, you can then run tests without migrations by adding the `--nomig
|
||||||
```
|
```
|
||||||
evennia test --settings settings.py --nomigrations .
|
evennia test --settings settings.py --nomigrations .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing for Game development (mini-tutorial)
|
|
||||||
|
|
||||||
Unit testing can be of paramount importance to game developers. When starting with a new game, it is
|
|
||||||
recommended to look into unit testing as soon as possible; an already huge game is much harder to
|
|
||||||
write tests for. The benefits of testing a game aren't different from the ones regarding library
|
|
||||||
testing. For example it is easy to introduce bugs that affect previously working code. Testing is
|
|
||||||
there to ensure your project behaves the way it should and continue to do so.
|
|
||||||
|
|
||||||
If you have never used unit testing (with Python or another language), you might want to check the
|
|
||||||
[official Python documentation about unit testing](https://docs.python.org/2/library/unittest.html),
|
|
||||||
particularly the first section dedicated to a basic example.
|
|
||||||
|
|
||||||
### Basic testing using Evennia
|
|
||||||
|
|
||||||
Evennia's test runner can be used to launch tests in your game directory (let's call it 'mygame').
|
|
||||||
Evennia's test runner does a few useful things beyond the normal Python unittest module:
|
|
||||||
|
|
||||||
* It creates and sets up an empty database, with some useful objects (accounts, characters and
|
|
||||||
rooms, among others).
|
|
||||||
* It provides simple ways to test commands, which can be somewhat tricky at times, if not tested
|
|
||||||
properly.
|
|
||||||
|
|
||||||
Therefore, you should use the command-line to execute the test runner, while specifying your own
|
|
||||||
game directories (not the one containing evennia). Go to your game directory (referred as 'mygame'
|
|
||||||
in this section) and execute the test runner:
|
|
||||||
|
|
||||||
evennia --settings settings.py test commands
|
|
||||||
|
|
||||||
This command will execute Evennia's test runner using your own settings file. It will set up a dummy
|
|
||||||
database of your choice and look into the 'commands' package defined in your game directory
|
|
||||||
(`mygame/commands` in this example) to find tests. The test module's name should begin with 'test'
|
|
||||||
and contain one or more `TestCase`. A full example can be found below.
|
|
||||||
|
|
||||||
### A simple example
|
|
||||||
|
|
||||||
In your game directory, go to `commands` and create a new file `tests.py` inside (it could be named
|
|
||||||
anything starting with `test`). We will start by making a test that has nothing to do with Commands,
|
|
||||||
just to show how unit testing works:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# mygame/commands/tests.py
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
class TestString(unittest.TestCase):
|
|
||||||
|
|
||||||
"""Unittest for strings (just a basic example)."""
|
|
||||||
|
|
||||||
def test_upper(self):
|
|
||||||
"""Test the upper() str method."""
|
|
||||||
self.assertEqual('foo'.upper(), 'FOO')
|
|
||||||
```
|
|
||||||
|
|
||||||
This example, inspired from the Python documentation, is used to test the 'upper()' method of the
|
|
||||||
'str' class. Not very useful, but it should give you a basic idea of how tests are used.
|
|
||||||
|
|
||||||
Let's execute that test to see if it works.
|
|
||||||
|
|
||||||
> evennia --settings settings.py test commands
|
|
||||||
|
|
||||||
TESTING: Using specified settings file 'server.conf.settings'.
|
|
||||||
|
|
||||||
(Obs: Evennia's full test suite may not pass if the settings are very
|
|
||||||
different from the default. Use 'test .' as arguments to run only tests
|
|
||||||
on the game dir.)
|
|
||||||
|
|
||||||
Creating test database for alias 'default'...
|
|
||||||
.
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 1 test in 0.001s
|
|
||||||
|
|
||||||
OK
|
|
||||||
Destroying test database for alias 'default'...
|
|
||||||
|
|
||||||
We specified the `commands` package to the evennia test command since that's where we put our test
|
|
||||||
file. In this case we could just as well just said `.` to search all of `mygame` for testing files.
|
|
||||||
If we have a lot of tests it may be useful to test only a single set at a time though. We get an
|
|
||||||
information text telling us we are using our custom settings file (instead of Evennia's default
|
|
||||||
file) and then the test runs. The test passes! Change the "FOO" string to something else in the test
|
|
||||||
to see how it looks when it fails.
|
|
||||||
|
|
||||||
### Testing commands
|
|
||||||
|
|
||||||
```{warning} This is not correct anymore.
|
|
||||||
```
|
|
||||||
|
|
||||||
This section will test the proper execution of the 'abilities' command, as described in the DELETED
|
|
||||||
tutorial to create the 'abilities' command, we will need it to test it.
|
|
||||||
|
|
||||||
Testing commands in Evennia is a bit more complex than the simple testing example we have seen.
|
|
||||||
Luckily, Evennia supplies a special test class to do just that ... we just need to inherit from it
|
|
||||||
and use it properly. This class is called 'CommandTest' and is defined in the
|
|
||||||
'evennia.commands.default.tests' package. To create a test for our 'abilities' command, we just
|
|
||||||
need to create a class that inherits from 'CommandTest' and add methods.
|
|
||||||
|
|
||||||
We could create a new test file for this but for now we just append to the `tests.py` file we
|
|
||||||
already have in `commands` from before.
|
|
||||||
|
|
||||||
```python
|
|
||||||
# bottom of mygame/commands/tests.py
|
|
||||||
|
|
||||||
from evennia.commands.default.tests import CommandTest
|
|
||||||
|
|
||||||
from commands.command import CmdAbilities
|
|
||||||
from typeclasses.characters import Character
|
|
||||||
|
|
||||||
class TestAbilities(CommandTest):
|
|
||||||
|
|
||||||
character_typeclass = Character
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
self.call(CmdAbilities(), "", "STR: 5, AGI: 4, MAG: 2")
|
|
||||||
```
|
|
||||||
|
|
||||||
* Line 1-4: we do some importing. 'CommandTest' is going to be our base class for our test, so we
|
|
||||||
need it. We also import our command ('CmdAbilities' in this case). Finally we import the
|
|
||||||
'Character' typeclass. We need it, since 'CommandTest' doesn't use 'Character', but
|
|
||||||
'DefaultCharacter', which means the character calling the command won't have the abilities we have
|
|
||||||
written in the 'Character' typeclass.
|
|
||||||
* Line 6-8: that's the body of our test. Here, a single command is tested in an entire class.
|
|
||||||
Default commands are usually grouped by category in a single class. There is no rule, as long as
|
|
||||||
you know where you put your tests. Note that we set the 'character_typeclass' class attribute to
|
|
||||||
Character. As explained above, if you didn't do that, the system would create a 'DefaultCharacter'
|
|
||||||
object, not a 'Character'. You can try to remove line 4 and 8 to see what happens when running the
|
|
||||||
test.
|
|
||||||
* Line 10-11: our unique testing method. Note its name: it should begin by 'test_'. Apart from
|
|
||||||
that, the method is quite simple: it's an instance method (so it takes the 'self' argument) but no
|
|
||||||
other arguments are needed. Line 11 uses the 'call' method, which is defined in 'CommandTest'.
|
|
||||||
It's a useful method that compares a command against an expected result. It would be like comparing
|
|
||||||
two strings with 'assertEqual', but the 'call' method does more things, including testing the
|
|
||||||
command in a realistic way (calling its hooks in the right order, so you don't have to worry about
|
|
||||||
that).
|
|
||||||
|
|
||||||
Line 11 can be understood as: test the 'abilities' command (first parameter), with no argument
|
|
||||||
(second parameter), and check that the character using it receives his/her abilities (third
|
|
||||||
parameter).
|
|
||||||
|
|
||||||
Let's run our new test:
|
|
||||||
|
|
||||||
> evennia --settings settings.py test commands
|
|
||||||
[...]
|
|
||||||
Creating test database for alias 'default'...
|
|
||||||
..
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 2 tests in 0.156s
|
|
||||||
|
|
||||||
OK
|
|
||||||
Destroying test database for alias 'default'...
|
|
||||||
|
|
||||||
Two tests were executed, since we have kept 'TestString' from last time. In case of failure, you
|
|
||||||
will get much more information to help you fix the bug.
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@ main test suite started with
|
||||||
> python game/manage.py test.
|
> python game/manage.py test.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import re
|
|
||||||
import types
|
|
||||||
import datetime
|
import datetime
|
||||||
from anything import Anything
|
from anything import Anything
|
||||||
|
|
||||||
|
|
@ -23,7 +21,7 @@ from unittest.mock import patch, Mock, MagicMock
|
||||||
|
|
||||||
from evennia import DefaultRoom, DefaultExit, ObjectDB
|
from evennia import DefaultRoom, DefaultExit, ObjectDB
|
||||||
from evennia.commands.default.cmdset_character import CharacterCmdSet
|
from evennia.commands.default.cmdset_character import CharacterCmdSet
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTest
|
from evennia.utils.test_resources import BaseEvenniaTest, BaseEvenniaCommandTest, EvenniaCommandTest # noqa
|
||||||
from evennia.commands.default import (
|
from evennia.commands.default import (
|
||||||
help as help_module,
|
help as help_module,
|
||||||
general,
|
general,
|
||||||
|
|
@ -40,305 +38,18 @@ from evennia.commands.default.muxcommand import MuxCommand
|
||||||
from evennia.commands.command import Command, InterruptCommand
|
from evennia.commands.command import Command, InterruptCommand
|
||||||
from evennia.commands import cmdparser
|
from evennia.commands import cmdparser
|
||||||
from evennia.commands.cmdset import CmdSet
|
from evennia.commands.cmdset import CmdSet
|
||||||
from evennia.utils import ansi, utils, gametime, create
|
from evennia.utils import utils, gametime, create
|
||||||
from evennia.server.sessionhandler import SESSIONS
|
from evennia.server.sessionhandler import SESSIONS
|
||||||
from evennia import search_object
|
from evennia import search_object
|
||||||
from evennia import DefaultObject, DefaultCharacter
|
from evennia import DefaultObject, DefaultCharacter
|
||||||
from evennia.prototypes import prototypes as protlib
|
from evennia.prototypes import prototypes as protlib
|
||||||
|
|
||||||
|
|
||||||
# set up signal here since we are not starting the server
|
|
||||||
|
|
||||||
_RE_STRIP_EVMENU = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE)
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# Command testing
|
# Command testing
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
@patch("evennia.server.portal.portal.LoopingCall", new=MagicMock())
|
|
||||||
class CommandTestMixin:
|
|
||||||
"""
|
|
||||||
Mixin to add to a test in order to provide the `.call` helper for
|
|
||||||
testing the execution and returns of a command.
|
|
||||||
|
|
||||||
Tests a Command by running it and comparing what messages it sends with
|
class TestGeneral(BaseEvenniaCommandTest):
|
||||||
expected values. This tests without actually spinning up the cmdhandler
|
|
||||||
for every test, which is more controlled.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
::
|
|
||||||
|
|
||||||
from commands.echo import CmdEcho
|
|
||||||
|
|
||||||
class MyCommandTest(EvenniaTest, CommandTestMixin):
|
|
||||||
|
|
||||||
def test_echo(self):
|
|
||||||
'''
|
|
||||||
Test that the echo command really returns
|
|
||||||
what you pass into it.
|
|
||||||
'''
|
|
||||||
self.call(MyCommand(), "hello world!",
|
|
||||||
"You hear your echo: 'Hello world!'")
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# formatting for .call's error message
|
|
||||||
_ERROR_FORMAT = """
|
|
||||||
=========================== Wanted message ===================================
|
|
||||||
{expected_msg}
|
|
||||||
=========================== Returned message =================================
|
|
||||||
{returned_msg}
|
|
||||||
==============================================================================
|
|
||||||
""".rstrip()
|
|
||||||
|
|
||||||
def call(
|
|
||||||
self,
|
|
||||||
cmdobj,
|
|
||||||
input_args,
|
|
||||||
msg=None,
|
|
||||||
cmdset=None,
|
|
||||||
noansi=True,
|
|
||||||
caller=None,
|
|
||||||
receiver=None,
|
|
||||||
cmdstring=None,
|
|
||||||
obj=None,
|
|
||||||
inputs=None,
|
|
||||||
raw_string=None,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Test a command by assigning all the needed properties to a cmdobj and
|
|
||||||
running the sequence. The resulting `.msg` calls will be mocked and
|
|
||||||
the text= calls to them compared to a expected output.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cmdobj (Command): The command object to use.
|
|
||||||
input_args (str): This should be the full input the Command should
|
|
||||||
see, such as 'look here'. This will become `.args` for the Command
|
|
||||||
instance to parse.
|
|
||||||
msg (str or dict, optional): This is the expected return value(s)
|
|
||||||
returned through `caller.msg(text=...)` calls in the command. If a string, the
|
|
||||||
receiver is controlled with the `receiver` kwarg (defaults to `caller`).
|
|
||||||
If this is a `dict`, it is a mapping
|
|
||||||
`{receiver1: "expected1", receiver2: "expected2",...}` and `receiver` is
|
|
||||||
ignored. The message(s) are compared with the actual messages returned
|
|
||||||
to the receiver(s) as the Command runs. Each check uses `.startswith`,
|
|
||||||
so you can choose to only include the first part of the
|
|
||||||
returned message if that's enough to verify a correct result. EvMenu
|
|
||||||
decorations (like borders) are stripped and should not be included. This
|
|
||||||
should also not include color tags unless `noansi=False`.
|
|
||||||
If the command returns texts in multiple separate `.msg`-
|
|
||||||
calls to a receiver, separate these with `|` if `noansi=True`
|
|
||||||
(default) and `||` if `noansi=False`. If no `msg` is given (`None`),
|
|
||||||
then no automatic comparison will be done.
|
|
||||||
cmdset (str, optional): If given, make `.cmdset` available on the Command
|
|
||||||
instance as it runs. While `.cmdset` is normally available on the
|
|
||||||
Command instance by default, this is usually only used by
|
|
||||||
commands that explicitly operates/displays cmdsets, like
|
|
||||||
`examine`.
|
|
||||||
noansi (str, optional): By default the color tags of the `msg` is
|
|
||||||
ignored, this makes them significant. If unset, `msg` must contain
|
|
||||||
the same color tags as the actual return message.
|
|
||||||
caller (Object or Account, optional): By default `self.char1` is used as the
|
|
||||||
command-caller (the `.caller` property on the Command). This allows to
|
|
||||||
execute with another caller, most commonly an Account.
|
|
||||||
receiver (Object or Account, optional): This is the object to receive the
|
|
||||||
return messages we want to test. By default this is the same as `caller`
|
|
||||||
(which in turn defaults to is `self.char1`). Note that if `msg` is
|
|
||||||
a `dict`, this is ignored since the receiver is already specified there.
|
|
||||||
cmdstring (str, optional): Normally this is the Command's `key`.
|
|
||||||
This allows for tweaking the `.cmdname` property of the
|
|
||||||
Command`. This isb used for commands with multiple aliases,
|
|
||||||
where the command explicitly checs which alias was used to
|
|
||||||
determine its functionality.
|
|
||||||
obj (str, optional): This sets the `.obj` property of the Command - the
|
|
||||||
object on which the Command 'sits'. By default this is the same as `caller`.
|
|
||||||
This can be used for testing on-object Command interactions.
|
|
||||||
inputs (list, optional): A list of strings to pass to functions that pause to
|
|
||||||
take input from the user (normally using `@interactive` and
|
|
||||||
`ret = yield(question)` or `evmenu.get_input`). Each element of the
|
|
||||||
list will be passed into the command as if the user wrote that at the prompt.
|
|
||||||
raw_string (str, optional): Normally the `.raw_string` property is set as
|
|
||||||
a combination of your `key/cmdname` and `input_args`. This allows
|
|
||||||
direct control of what this is, for example for testing edge cases
|
|
||||||
or malformed inputs.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str or dict: The message sent to `receiver`, or a dict of
|
|
||||||
`{receiver: "msg", ...}` if multiple are given. This is usually
|
|
||||||
only used with `msg=None` to do the validation externally.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
AssertionError: If the returns of `.msg` calls (tested with `.startswith`) does not
|
|
||||||
match `expected_input`.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
As part of the tests, all methods of the Command will be called in
|
|
||||||
the proper order:
|
|
||||||
|
|
||||||
- cmdobj.at_pre_cmd()
|
|
||||||
- cmdobj.parse()
|
|
||||||
- cmdobj.func()
|
|
||||||
- cmdobj.at_post_cmd()
|
|
||||||
|
|
||||||
"""
|
|
||||||
# The `self.char1` is created in the `EvenniaTest` base along with
|
|
||||||
# other helper objects like self.room and self.obj
|
|
||||||
caller = caller if caller else self.char1
|
|
||||||
cmdobj.caller = caller
|
|
||||||
cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key
|
|
||||||
cmdobj.raw_cmdname = cmdobj.cmdname
|
|
||||||
cmdobj.cmdstring = cmdobj.cmdname # deprecated
|
|
||||||
cmdobj.args = input_args
|
|
||||||
cmdobj.cmdset = cmdset
|
|
||||||
cmdobj.session = SESSIONS.session_from_sessid(1)
|
|
||||||
cmdobj.account = self.account
|
|
||||||
cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args
|
|
||||||
cmdobj.obj = obj or (caller if caller else self.char1)
|
|
||||||
inputs = inputs or []
|
|
||||||
|
|
||||||
# set up receivers
|
|
||||||
receiver_mapping = {}
|
|
||||||
if isinstance(msg, dict):
|
|
||||||
# a mapping {receiver: msg, ...}
|
|
||||||
receiver_mapping = {recv: str(msg).strip() if msg else None
|
|
||||||
for recv, msg in msg.items()}
|
|
||||||
else:
|
|
||||||
# a single expected string and thus a single receiver (defaults to caller)
|
|
||||||
receiver = receiver if receiver else caller
|
|
||||||
receiver_mapping[receiver] = str(msg).strip() if msg is not None else None
|
|
||||||
|
|
||||||
unmocked_msg_methods = {}
|
|
||||||
for receiver in receiver_mapping:
|
|
||||||
# save the old .msg method so we can get it back
|
|
||||||
# cleanly after the test
|
|
||||||
unmocked_msg_methods[receiver] = receiver.msg
|
|
||||||
# replace normal `.msg` with a mock
|
|
||||||
receiver.msg = Mock()
|
|
||||||
|
|
||||||
# Run the methods of the Command. This mimics what happens in the
|
|
||||||
# cmdhandler. This will have the mocked .msg be called as part of the
|
|
||||||
# execution. Mocks remembers what was sent to them so we will be able
|
|
||||||
# to retrieve what was sent later.
|
|
||||||
try:
|
|
||||||
if cmdobj.at_pre_cmd():
|
|
||||||
return
|
|
||||||
cmdobj.parse()
|
|
||||||
ret = cmdobj.func()
|
|
||||||
|
|
||||||
# handle func's with yield in them (making them generators)
|
|
||||||
if isinstance(ret, types.GeneratorType):
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
inp = inputs.pop() if inputs else None
|
|
||||||
if inp:
|
|
||||||
try:
|
|
||||||
# this mimics a user's reply to a prompt
|
|
||||||
ret.send(inp)
|
|
||||||
except TypeError:
|
|
||||||
next(ret)
|
|
||||||
ret = ret.send(inp)
|
|
||||||
else:
|
|
||||||
# non-input yield, like yield(10). We don't pause
|
|
||||||
# but fire it immediately.
|
|
||||||
next(ret)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
|
|
||||||
cmdobj.at_post_cmd()
|
|
||||||
except StopIteration:
|
|
||||||
pass
|
|
||||||
except InterruptCommand:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for inp in inputs:
|
|
||||||
# if there are any inputs left, we may have a non-generator
|
|
||||||
# input to handle (get_input/ask_yes_no that uses a separate
|
|
||||||
# cmdset rather than a yield
|
|
||||||
caller.execute_cmd(inp)
|
|
||||||
|
|
||||||
# At this point the mocked .msg methods on each receiver will have
|
|
||||||
# stored all calls made to them (that's a basic function of the Mock
|
|
||||||
# class). We will not extract them and compare to what we expected to
|
|
||||||
# go to each receiver.
|
|
||||||
|
|
||||||
returned_msgs = {}
|
|
||||||
for receiver, expected_msg in receiver_mapping.items():
|
|
||||||
# get the stored messages from the Mock with Mock.mock_calls.
|
|
||||||
stored_msg = [
|
|
||||||
args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs))
|
|
||||||
for name, args, kwargs in receiver.msg.mock_calls
|
|
||||||
]
|
|
||||||
# we can return this now, we are done using the mock
|
|
||||||
receiver.msg = unmocked_msg_methods[receiver]
|
|
||||||
|
|
||||||
# Get the first element of a tuple if msg received a tuple instead of a string
|
|
||||||
stored_msg = [str(smsg[0])
|
|
||||||
if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg]
|
|
||||||
if expected_msg is None:
|
|
||||||
# no expected_msg; just build the returned_msgs dict
|
|
||||||
|
|
||||||
returned_msg = "\n".join(str(msg) for msg in stored_msg)
|
|
||||||
returned_msgs[receiver] = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
|
|
||||||
else:
|
|
||||||
# compare messages to expected
|
|
||||||
|
|
||||||
# set our separator for returned messages based on parsing ansi or not
|
|
||||||
msg_sep = "|" if noansi else "||"
|
|
||||||
|
|
||||||
# We remove Evmenu decorations since that just makes it harder
|
|
||||||
# to write the comparison string. We also strip ansi before this
|
|
||||||
# comparison since otherwise it would mess with the regex.
|
|
||||||
returned_msg = msg_sep.join(
|
|
||||||
_RE_STRIP_EVMENU.sub(
|
|
||||||
"", ansi.parse_ansi(mess, strip_ansi=noansi))
|
|
||||||
for mess in stored_msg).strip()
|
|
||||||
|
|
||||||
# this is the actual test
|
|
||||||
if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg):
|
|
||||||
# failed the test
|
|
||||||
raise AssertionError(
|
|
||||||
self._ERROR_FORMAT.format(
|
|
||||||
expected_msg=expected_msg, returned_msg=returned_msg)
|
|
||||||
)
|
|
||||||
# passed!
|
|
||||||
returned_msgs[receiver] = returned_msg
|
|
||||||
|
|
||||||
if len(returned_msgs) == 1:
|
|
||||||
return list(returned_msgs.values())[0]
|
|
||||||
return returned_msgs
|
|
||||||
|
|
||||||
|
|
||||||
@patch("evennia.commands.account.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.admin.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.batchprocess.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.building.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.comms.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.general.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.help.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.syscommands.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.system.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
@patch("evennia.commands.unloggedin.COMMAND_DEFAULT_CLASS", MuxCommand)
|
|
||||||
class EvenniaCommandTest(BaseEvenniaTest, CommandTestMixin):
|
|
||||||
"""
|
|
||||||
Commands only using the default settings.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class CommandTest(EvenniaTest, CommandTestMixin):
|
|
||||||
"""
|
|
||||||
Parent class to inherit from - makes tests use your own
|
|
||||||
classes and settings in mygame.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Individual module Tests
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
class TestGeneral(EvenniaCommandTest):
|
|
||||||
def test_look(self):
|
def test_look(self):
|
||||||
rid = self.room1.id
|
rid = self.room1.id
|
||||||
self.call(general.CmdLook(), "here", "Room(#{})\nroom_desc".format(rid))
|
self.call(general.CmdLook(), "here", "Room(#{})\nroom_desc".format(rid))
|
||||||
|
|
@ -434,7 +145,7 @@ class TestGeneral(EvenniaCommandTest):
|
||||||
self.call(general.CmdAccess(), "", "Permission Hierarchy (climbing):")
|
self.call(general.CmdAccess(), "", "Permission Hierarchy (climbing):")
|
||||||
|
|
||||||
|
|
||||||
class TestHelp(EvenniaCommandTest):
|
class TestHelp(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
maxDiff = None
|
maxDiff = None
|
||||||
|
|
||||||
|
|
@ -584,7 +295,7 @@ class TestHelp(EvenniaCommandTest):
|
||||||
cmdset=TestCmdSet())
|
cmdset=TestCmdSet())
|
||||||
|
|
||||||
|
|
||||||
class TestSystem(EvenniaCommandTest):
|
class TestSystem(BaseEvenniaCommandTest):
|
||||||
def test_py(self):
|
def test_py(self):
|
||||||
# we are not testing CmdReload, CmdReset and CmdShutdown, CmdService or CmdTime
|
# we are not testing CmdReload, CmdReset and CmdShutdown, CmdService or CmdTime
|
||||||
# since the server is not running during these tests.
|
# since the server is not running during these tests.
|
||||||
|
|
@ -608,7 +319,7 @@ _TASK_HANDLER = None
|
||||||
def func_test_cmd_tasks():
|
def func_test_cmd_tasks():
|
||||||
return 'success'
|
return 'success'
|
||||||
|
|
||||||
class TestCmdTasks(EvenniaCommandTest):
|
class TestCmdTasks(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
@ -768,7 +479,7 @@ class TestCmdTasks(EvenniaCommandTest):
|
||||||
self.call(system.CmdTasks(), f'/cancel', wanted_msg)
|
self.call(system.CmdTasks(), f'/cancel', wanted_msg)
|
||||||
|
|
||||||
|
|
||||||
class TestAdmin(EvenniaCommandTest):
|
class TestAdmin(BaseEvenniaCommandTest):
|
||||||
def test_emit(self):
|
def test_emit(self):
|
||||||
self.call(admin.CmdEmit(), "Char2 = Test", "Emitted to Char2:\nTest")
|
self.call(admin.CmdEmit(), "Char2 = Test", "Emitted to Char2:\nTest")
|
||||||
|
|
||||||
|
|
@ -799,7 +510,7 @@ class TestAdmin(EvenniaCommandTest):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestAccount(EvenniaCommandTest):
|
class TestAccount(BaseEvenniaCommandTest):
|
||||||
def test_ooc_look(self):
|
def test_ooc_look(self):
|
||||||
if settings.MULTISESSION_MODE < 2:
|
if settings.MULTISESSION_MODE < 2:
|
||||||
self.call(
|
self.call(
|
||||||
|
|
@ -923,7 +634,7 @@ class TestAccount(EvenniaCommandTest):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBuilding(EvenniaCommandTest):
|
class TestBuilding(BaseEvenniaCommandTest):
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
name = settings.BASE_OBJECT_TYPECLASS.rsplit(".", 1)[1]
|
name = settings.BASE_OBJECT_TYPECLASS.rsplit(".", 1)[1]
|
||||||
self.call(
|
self.call(
|
||||||
|
|
@ -1991,7 +1702,7 @@ from evennia.comms.comms import DefaultChannel # noqa
|
||||||
|
|
||||||
|
|
||||||
@patch("evennia.commands.default.comms.CHANNEL_DEFAULT_TYPECLASS", DefaultChannel)
|
@patch("evennia.commands.default.comms.CHANNEL_DEFAULT_TYPECLASS", DefaultChannel)
|
||||||
class TestCommsChannel(EvenniaCommandTest):
|
class TestCommsChannel(BaseEvenniaCommandTest):
|
||||||
"""
|
"""
|
||||||
Test the central `channel` command.
|
Test the central `channel` command.
|
||||||
|
|
||||||
|
|
@ -2214,7 +1925,7 @@ class TestCommsChannel(EvenniaCommandTest):
|
||||||
from evennia.commands.default import comms # noqa
|
from evennia.commands.default import comms # noqa
|
||||||
|
|
||||||
|
|
||||||
class TestComms(EvenniaCommandTest):
|
class TestComms(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
def test_page(self):
|
def test_page(self):
|
||||||
self.call(
|
self.call(
|
||||||
|
|
@ -2226,7 +1937,7 @@ class TestComms(EvenniaCommandTest):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBatchProcess(EvenniaCommandTest):
|
class TestBatchProcess(BaseEvenniaCommandTest):
|
||||||
"""
|
"""
|
||||||
Test the batch processor.
|
Test the batch processor.
|
||||||
|
|
||||||
|
|
@ -2262,13 +1973,13 @@ class CmdInterrupt(Command):
|
||||||
self.msg("in func")
|
self.msg("in func")
|
||||||
|
|
||||||
|
|
||||||
class TestInterruptCommand(EvenniaCommandTest):
|
class TestInterruptCommand(BaseEvenniaCommandTest):
|
||||||
def test_interrupt_command(self):
|
def test_interrupt_command(self):
|
||||||
ret = self.call(CmdInterrupt(), "")
|
ret = self.call(CmdInterrupt(), "")
|
||||||
self.assertEqual(ret, "")
|
self.assertEqual(ret, "")
|
||||||
|
|
||||||
|
|
||||||
class TestUnconnectedCommand(EvenniaCommandTest):
|
class TestUnconnectedCommand(BaseEvenniaCommandTest):
|
||||||
def test_info_command(self):
|
def test_info_command(self):
|
||||||
# instead of using SERVER_START_TIME (0), we use 86400 because Windows won't let us use anything lower
|
# instead of using SERVER_START_TIME (0), we use 86400 because Windows won't let us use anything lower
|
||||||
gametime.SERVER_START_TIME = 86400
|
gametime.SERVER_START_TIME = 86400
|
||||||
|
|
@ -2288,7 +1999,7 @@ class TestUnconnectedCommand(EvenniaCommandTest):
|
||||||
# Test syscommands
|
# Test syscommands
|
||||||
|
|
||||||
|
|
||||||
class TestSystemCommands(EvenniaCommandTest):
|
class TestSystemCommands(BaseEvenniaCommandTest):
|
||||||
def test_simple_defaults(self):
|
def test_simple_defaults(self):
|
||||||
self.call(syscommands.SystemNoInput(), "")
|
self.call(syscommands.SystemNoInput(), "")
|
||||||
self.call(syscommands.SystemNoMatch(), "Huh?")
|
self.call(syscommands.SystemNoMatch(), "Huh?")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ Building menu tests.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . building_menu import BuildingMenu, CmdNoMatch
|
from . building_menu import BuildingMenu, CmdNoMatch
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ class Submenu(BuildingMenu):
|
||||||
self.add_choice("title", key="t", attr="key")
|
self.add_choice("title", key="t", attr="key")
|
||||||
|
|
||||||
|
|
||||||
class TestBuildingMenu(EvenniaCommandTest):
|
class TestBuildingMenu(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestBuildingMenu, self).setUp()
|
super(TestBuildingMenu, self).setUp()
|
||||||
self.menu = BuildingMenu(caller=self.char1, obj=self.room1, title="test")
|
self.menu = BuildingMenu(caller=self.char1, obj=self.room1, title="test")
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ Test email login.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import email_login
|
from . import email_login
|
||||||
|
|
||||||
|
|
||||||
class TestEmailLogin(EvenniaCommandTest):
|
class TestEmailLogin(BaseEvenniaCommandTest):
|
||||||
def test_connect(self):
|
def test_connect(self):
|
||||||
self.call(
|
self.call(
|
||||||
email_login.CmdUnconnectedConnect(),
|
email_login.CmdUnconnectedConnect(),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from textwrap import dedent
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia import ScriptDB
|
from evennia import ScriptDB
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.objects.objects import ExitCommand
|
from evennia.objects.objects import ExitCommand
|
||||||
from evennia.utils import ansi, utils
|
from evennia.utils import ansi, utils
|
||||||
from evennia.utils.create import create_object, create_script
|
from evennia.utils.create import create_object, create_script
|
||||||
|
|
@ -246,7 +246,7 @@ class TestEventHandler(BaseEvenniaTest):
|
||||||
self.assertEqual(self.room1.callbacks.all(), {})
|
self.assertEqual(self.room1.callbacks.all(), {})
|
||||||
|
|
||||||
|
|
||||||
class TestCmdCallback(EvenniaCommandTest):
|
class TestCmdCallback(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
"""Test the @callback command."""
|
"""Test the @callback command."""
|
||||||
|
|
||||||
|
|
@ -425,7 +425,7 @@ class TestCmdCallback(EvenniaCommandTest):
|
||||||
self.assertEqual(callback.valid, True)
|
self.assertEqual(callback.valid, True)
|
||||||
|
|
||||||
|
|
||||||
class TestDefaultCallbacks(EvenniaCommandTest):
|
class TestDefaultCallbacks(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
"""Test the default callbacks."""
|
"""Test the default callbacks."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ Test menu_login
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import menu_login
|
from . import menu_login
|
||||||
|
|
||||||
|
|
||||||
class TestMenuLogin(EvenniaCommandTest):
|
class TestMenuLogin(BaseEvenniaCommandTest):
|
||||||
def test_cmdunloggedlook(self):
|
def test_cmdunloggedlook(self):
|
||||||
self.call(menu_login.CmdUnloggedinLook(), "", "======")
|
self.call(menu_login.CmdUnloggedinLook(), "", "======")
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ Legacy Mux comms tests (extracted from 0.9.5)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import mux_comms_cmds as comms
|
from . import mux_comms_cmds as comms
|
||||||
|
|
||||||
|
|
||||||
class TestLegacyMuxComms(EvenniaCommandTest):
|
class TestLegacyMuxComms(BaseEvenniaCommandTest):
|
||||||
"""
|
"""
|
||||||
Test the legacy comms contrib.
|
Test the legacy comms contrib.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ Test of the Unixcommand.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from .unixcommand import UnixCommand
|
from .unixcommand import UnixCommand
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ class CmdDummy(UnixCommand):
|
||||||
self.msg("{} * {} = {}".format(nb1, nb2, result))
|
self.msg("{} * {} = {}".format(nb1, nb2, result))
|
||||||
|
|
||||||
|
|
||||||
class TestUnixCommand(EvenniaCommandTest):
|
class TestUnixCommand(BaseEvenniaCommandTest):
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
"""See the command parsing succeed."""
|
"""See the command parsing succeed."""
|
||||||
self.call(CmdDummy(), "5 10", "5 * 10 = 50")
|
self.call(CmdDummy(), "5 10", "5 * 10 = 50")
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ Unit tests for the Evscaperoom
|
||||||
import inspect
|
import inspect
|
||||||
import pkgutil
|
import pkgutil
|
||||||
from os import path
|
from os import path
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia import InterruptCommand
|
from evennia import InterruptCommand
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest
|
from evennia.utils.test_resources import BaseEvenniaTest
|
||||||
from evennia.utils import mod_import
|
from evennia.utils import mod_import
|
||||||
|
|
@ -15,7 +15,7 @@ from . import objects
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
|
|
||||||
class TestEvscaperoomCommands(EvenniaCommandTest):
|
class TestEvscaperoomCommands(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.room1 = utils.create_evscaperoom_object("evscaperoom.room.EvscapeRoom", key="Testroom")
|
self.room1 = utils.create_evscaperoom_object("evscaperoom.room.EvscapeRoom", key="Testroom")
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ Test the contrib barter system
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from . import barter
|
from . import barter
|
||||||
|
|
||||||
|
|
||||||
class TestBarter(EvenniaCommandTest):
|
class TestBarter(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.tradeitem1 = create_object(key="TradeItem1", location=self.char1)
|
self.tradeitem1 = create_object(key="TradeItem1", location=self.char1)
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ Testing clothing contrib
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from evennia.objects.objects import DefaultRoom
|
from evennia.objects.objects import DefaultRoom
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest
|
from evennia.utils.test_resources import BaseEvenniaTest
|
||||||
from . import clothing
|
from . import clothing
|
||||||
|
|
||||||
|
|
||||||
class TestClothingCmd(EvenniaCommandTest):
|
class TestClothingCmd(BaseEvenniaCommandTest):
|
||||||
def test_clothingcommands(self):
|
def test_clothingcommands(self):
|
||||||
wearer = create_object(clothing.ClothedCharacter, key="Wearer")
|
wearer = create_object(clothing.ClothedCharacter, key="Wearer")
|
||||||
friend = create_object(clothing.ClothedCharacter, key="Friend")
|
friend = create_object(clothing.ClothedCharacter, key="Friend")
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Unit tests for the crafting system contrib.
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.test_resources import BaseEvenniaTestCase
|
from evennia.utils.test_resources import BaseEvenniaTestCase
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from . import crafting, example_recipes
|
from . import crafting, example_recipes
|
||||||
|
|
@ -655,7 +655,7 @@ class TestCraftSword(BaseEvenniaTestCase):
|
||||||
@mock.patch("evennia.contrib.game_systems.crafting.crafting._load_recipes", new=mock.MagicMock())
|
@mock.patch("evennia.contrib.game_systems.crafting.crafting._load_recipes", new=mock.MagicMock())
|
||||||
@mock.patch("evennia.contrib.game_systems.crafting.crafting._RECIPE_CLASSES", new={"testrecipe": _MockRecipe})
|
@mock.patch("evennia.contrib.game_systems.crafting.crafting._RECIPE_CLASSES", new={"testrecipe": _MockRecipe})
|
||||||
@override_settings(CRAFT_RECIPE_MODULES=[])
|
@override_settings(CRAFT_RECIPE_MODULES=[])
|
||||||
class TestCraftCommand(EvenniaCommandTest):
|
class TestCraftCommand(BaseEvenniaCommandTest):
|
||||||
"""Test the crafting command"""
|
"""Test the crafting command"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ Test gendersub contrib.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from . import gendersub
|
from . import gendersub
|
||||||
|
|
||||||
|
|
||||||
class TestGenderSub(EvenniaCommandTest):
|
class TestGenderSub(BaseEvenniaCommandTest):
|
||||||
def test_setgender(self):
|
def test_setgender(self):
|
||||||
self.call(gendersub.SetGender(), "male", "Your gender was set to male.")
|
self.call(gendersub.SetGender(), "male", "Your gender was set to male.")
|
||||||
self.call(gendersub.SetGender(), "ambiguous", "Your gender was set to ambiguous.")
|
self.call(gendersub.SetGender(), "ambiguous", "Your gender was set to ambiguous.")
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ Test mail contrib
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import mail
|
from . import mail
|
||||||
|
|
||||||
|
|
||||||
class TestMail(EvenniaCommandTest):
|
class TestMail(BaseEvenniaCommandTest):
|
||||||
def test_mail(self):
|
def test_mail(self):
|
||||||
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account)
|
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account)
|
||||||
self.call(mail.CmdMail(), "test", "'test' is not a valid mail id.", caller=self.account)
|
self.call(mail.CmdMail(), "test", "'test' is not a valid mail id.", caller=self.account)
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ Test multidescer contrib.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import multidescer
|
from . import multidescer
|
||||||
|
|
||||||
|
|
||||||
class TestMultidescer(EvenniaCommandTest):
|
class TestMultidescer(BaseEvenniaCommandTest):
|
||||||
def test_cmdmultidesc(self):
|
def test_cmdmultidesc(self):
|
||||||
self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ncaller:")
|
self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ncaller:")
|
||||||
self.call(
|
self.call(
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import re
|
||||||
import itertools
|
import itertools
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
from evennia.utils import search
|
from evennia.utils import search
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from . import puzzles
|
from . import puzzles
|
||||||
|
|
||||||
|
|
||||||
class TestPuzzles(EvenniaCommandTest):
|
class TestPuzzles(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestPuzzles, self).setUp()
|
super(TestPuzzles, self).setUp()
|
||||||
self.steel = create_object(self.object_typeclass, key="steel", location=self.char1.location)
|
self.steel = create_object(self.object_typeclass, key="steel", location=self.char1.location)
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ Turnbattle tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from mock import patch, MagicMock
|
from mock import patch, MagicMock
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest
|
from evennia.utils.test_resources import BaseEvenniaTest
|
||||||
from evennia.objects.objects import DefaultRoom
|
from evennia.objects.objects import DefaultRoom
|
||||||
from . import tb_basic, tb_equip, tb_range, tb_items, tb_magic
|
from . import tb_basic, tb_equip, tb_range, tb_items, tb_magic
|
||||||
|
|
||||||
|
|
||||||
class TestTurnBattleBasicCmd(EvenniaCommandTest):
|
class TestTurnBattleBasicCmd(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
# Test basic combat commands
|
# Test basic combat commands
|
||||||
def test_turnbattlecmd(self):
|
def test_turnbattlecmd(self):
|
||||||
|
|
@ -22,7 +22,7 @@ class TestTurnBattleBasicCmd(EvenniaCommandTest):
|
||||||
self.call(tb_basic.CmdRest(), "", "Char rests to recover HP.")
|
self.call(tb_basic.CmdRest(), "", "Char rests to recover HP.")
|
||||||
|
|
||||||
|
|
||||||
class TestTurnBattleEquipCmd(EvenniaCommandTest):
|
class TestTurnBattleEquipCmd(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestTurnBattleEquipCmd, self).setUp()
|
super(TestTurnBattleEquipCmd, self).setUp()
|
||||||
self.testweapon = create_object(tb_equip.TBEWeapon, key="test weapon")
|
self.testweapon = create_object(tb_equip.TBEWeapon, key="test weapon")
|
||||||
|
|
@ -45,7 +45,7 @@ class TestTurnBattleEquipCmd(EvenniaCommandTest):
|
||||||
self.call(tb_equip.CmdRest(), "", "Char rests to recover HP.")
|
self.call(tb_equip.CmdRest(), "", "Char rests to recover HP.")
|
||||||
|
|
||||||
|
|
||||||
class TestTurnBattleRangeCmd(EvenniaCommandTest):
|
class TestTurnBattleRangeCmd(BaseEvenniaCommandTest):
|
||||||
# Test range commands
|
# Test range commands
|
||||||
def test_turnbattlerangecmd(self):
|
def test_turnbattlerangecmd(self):
|
||||||
# Start with range module specific commands.
|
# Start with range module specific commands.
|
||||||
|
|
@ -61,7 +61,7 @@ class TestTurnBattleRangeCmd(EvenniaCommandTest):
|
||||||
self.call(tb_range.CmdRest(), "", "Char rests to recover HP.")
|
self.call(tb_range.CmdRest(), "", "Char rests to recover HP.")
|
||||||
|
|
||||||
|
|
||||||
class TestTurnBattleItemsCmd(EvenniaCommandTest):
|
class TestTurnBattleItemsCmd(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestTurnBattleItemsCmd, self).setUp()
|
super(TestTurnBattleItemsCmd, self).setUp()
|
||||||
self.testitem = create_object(key="test item")
|
self.testitem = create_object(key="test item")
|
||||||
|
|
@ -78,7 +78,7 @@ class TestTurnBattleItemsCmd(EvenniaCommandTest):
|
||||||
self.call(tb_items.CmdRest(), "", "Char rests to recover HP.")
|
self.call(tb_items.CmdRest(), "", "Char rests to recover HP.")
|
||||||
|
|
||||||
|
|
||||||
class TestTurnBattleMagicCmd(EvenniaCommandTest):
|
class TestTurnBattleMagicCmd(BaseEvenniaCommandTest):
|
||||||
|
|
||||||
# Test magic commands
|
# Test magic commands
|
||||||
def test_turnbattlemagiccmd(self):
|
def test_turnbattlemagiccmd(self):
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Testing of ExtendedRoom contrib
|
||||||
import datetime
|
import datetime
|
||||||
from mock import patch, Mock
|
from mock import patch, Mock
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.objects.objects import DefaultRoom
|
from evennia.objects.objects import DefaultRoom
|
||||||
from . import extended_room
|
from . import extended_room
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ class ForceUTCDatetime(datetime.datetime):
|
||||||
@patch("evennia.contrib.grid.extended_room.extended_room.datetime.datetime", ForceUTCDatetime)
|
@patch("evennia.contrib.grid.extended_room.extended_room.datetime.datetime", ForceUTCDatetime)
|
||||||
# mock gametime to return April 9, 2064, at 21:06 (spring evening)
|
# mock gametime to return April 9, 2064, at 21:06 (spring evening)
|
||||||
@patch("evennia.utils.gametime.gametime", new=Mock(return_value=2975000766))
|
@patch("evennia.utils.gametime.gametime", new=Mock(return_value=2975000766))
|
||||||
class TestExtendedRoom(EvenniaCommandTest):
|
class TestExtendedRoom(BaseEvenniaCommandTest):
|
||||||
room_typeclass = extended_room.ExtendedRoom
|
room_typeclass = extended_room.ExtendedRoom
|
||||||
DETAIL_DESC = "A test detail."
|
DETAIL_DESC = "A test detail."
|
||||||
SPRING_DESC = "A spring description."
|
SPRING_DESC = "A spring description."
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ Test map builder.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import mapbuilder
|
from . import mapbuilder
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
@ -187,7 +187,7 @@ EXAMPLE2_LEGEND = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestMapBuilder(EvenniaCommandTest):
|
class TestMapBuilder(BaseEvenniaCommandTest):
|
||||||
def test_cmdmapbuilder(self):
|
def test_cmdmapbuilder(self):
|
||||||
self.call(
|
self.call(
|
||||||
mapbuilder.CmdMapBuilder(),
|
mapbuilder.CmdMapBuilder(),
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ Tests of simpledoor.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from . import simpledoor
|
from . import simpledoor
|
||||||
|
|
||||||
|
|
||||||
class TestSimpleDoor(EvenniaCommandTest):
|
class TestSimpleDoor(BaseEvenniaCommandTest):
|
||||||
def test_cmdopen(self):
|
def test_cmdopen(self):
|
||||||
self.call(
|
self.call(
|
||||||
simpledoor.CmdOpen(),
|
simpledoor.CmdOpen(),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Slow exit tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from . import slow_exit
|
from . import slow_exit
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ def _cancellable_mockdelay(time, callback, *args, **kwargs):
|
||||||
return Mock()
|
return Mock()
|
||||||
|
|
||||||
|
|
||||||
class TestSlowExit(EvenniaCommandTest):
|
class TestSlowExit(BaseEvenniaCommandTest):
|
||||||
@patch("evennia.utils.delay", _cancellable_mockdelay)
|
@patch("evennia.utils.delay", _cancellable_mockdelay)
|
||||||
def test_exit(self):
|
def test_exit(self):
|
||||||
exi = create_object(
|
exi = create_object(
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ Testing of TestDice.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from . import dice
|
from . import dice
|
||||||
|
|
||||||
|
|
||||||
@patch("evennia.contrib.rpg.dice.dice.randint", return_value=5)
|
@patch("evennia.contrib.rpg.dice.dice.randint", return_value=5)
|
||||||
class TestDice(EvenniaCommandTest):
|
class TestDice(BaseEvenniaCommandTest):
|
||||||
def test_roll_dice(self, mocked_randint):
|
def test_roll_dice(self, mocked_randint):
|
||||||
self.assertEqual(dice.roll_dice(6, 6, modifier=("+", 4)), mocked_randint() * 6 + 4)
|
self.assertEqual(dice.roll_dice(6, 6, modifier=("+", 4)), mocked_randint() * 6 + 4)
|
||||||
self.assertEqual(dice.roll_dice(6, 6, conditional=("<", 35)), True)
|
self.assertEqual(dice.roll_dice(6, 6, conditional=("<", 35)), True)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Tests for RP system
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
from anything import Anything
|
from anything import Anything
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest
|
from evennia.utils.test_resources import BaseEvenniaTest
|
||||||
from evennia import create_object
|
from evennia import create_object
|
||||||
|
|
||||||
|
|
@ -278,7 +278,7 @@ class TestRPSystem(BaseEvenniaTest):
|
||||||
self.assertEqual(result, (Anything, self.speaker, self.speaker.key))
|
self.assertEqual(result, (Anything, self.speaker, self.speaker.key))
|
||||||
|
|
||||||
|
|
||||||
class TestRPSystemCommands(EvenniaCommandTest):
|
class TestRPSystemCommands(BaseEvenniaCommandTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.char1.swap_typeclass(rpsystem.ContribRPCharacter)
|
self.char1.swap_typeclass(rpsystem.ContribRPCharacter)
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
Tutorial - talking NPC tests.
|
Tutorial - talking NPC tests.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from . import talking_npc
|
from . import talking_npc
|
||||||
|
|
||||||
|
|
||||||
class TestTalkingNPC(EvenniaCommandTest):
|
class TestTalkingNPC(BaseEvenniaCommandTest):
|
||||||
def test_talkingnpc(self):
|
def test_talkingnpc(self):
|
||||||
npc = create_object(talking_npc.TalkingNPC, key="npctalker", location=self.room1)
|
npc = create_object(talking_npc.TalkingNPC, key="npctalker", location=self.room1)
|
||||||
self.call(talking_npc.CmdTalk(), "", "(You walk up and talk to Char.)")
|
self.call(talking_npc.CmdTalk(), "", "(You walk up and talk to Char.)")
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Test tutorial_world/mob
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from twisted.trial.unittest import TestCase as TwistedTestCase
|
from twisted.trial.unittest import TestCase as TwistedTestCase
|
||||||
from twisted.internet.base import DelayedCall
|
from twisted.internet.base import DelayedCall
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
from evennia.utils.create import create_object
|
from evennia.utils.create import create_object
|
||||||
from evennia.utils.test_resources import BaseEvenniaTest, mockdelay, mockdeferLater
|
from evennia.utils.test_resources import BaseEvenniaTest, mockdelay, mockdeferLater
|
||||||
from . import mob, objects as tutobjects, rooms as tutrooms
|
from . import mob, objects as tutobjects, rooms as tutrooms
|
||||||
|
|
@ -30,7 +30,7 @@ class TestTutorialWorldMob(BaseEvenniaTest):
|
||||||
DelayedCall.debug = True
|
DelayedCall.debug = True
|
||||||
|
|
||||||
|
|
||||||
class TestTutorialWorldObjects(TwistedTestCase, EvenniaCommandTest):
|
class TestTutorialWorldObjects(TwistedTestCase, BaseEvenniaCommandTest):
|
||||||
def test_tutorialobj(self):
|
def test_tutorialobj(self):
|
||||||
obj1 = create_object(tutobjects.TutorialObject, key="tutobj")
|
obj1 = create_object(tutobjects.TutorialObject, key="tutobj")
|
||||||
obj1.reset()
|
obj1.reset()
|
||||||
|
|
@ -129,7 +129,7 @@ class TestTutorialWorldObjects(TwistedTestCase, EvenniaCommandTest):
|
||||||
self.call(tutobjects.CmdGetWeapon(), "", "You find Rusty sword.", obj=rack)
|
self.call(tutobjects.CmdGetWeapon(), "", "You find Rusty sword.", obj=rack)
|
||||||
|
|
||||||
|
|
||||||
class TestTutorialWorldRooms(EvenniaCommandTest):
|
class TestTutorialWorldRooms(BaseEvenniaCommandTest):
|
||||||
def test_cmdtutorial(self):
|
def test_cmdtutorial(self):
|
||||||
room = create_object(tutrooms.TutorialRoom, key="tutroom")
|
room = create_object(tutrooms.TutorialRoom, key="tutroom")
|
||||||
self.char1.location = room
|
self.char1.location = room
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@ Test the main server component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from mock import MagicMock, patch, DEFAULT, call
|
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from evennia.utils.test_resources import unload_module
|
from mock import MagicMock, patch, DEFAULT, call
|
||||||
|
|
||||||
|
|
||||||
@patch("evennia.server.server.LoopingCall", new=MagicMock())
|
@patch("evennia.server.server.LoopingCall", new=MagicMock())
|
||||||
|
|
@ -191,7 +190,7 @@ class TestServer(TestCase):
|
||||||
evennia.run_initial_setup()
|
evennia.run_initial_setup()
|
||||||
acct.delete()
|
acct.delete()
|
||||||
|
|
||||||
@override_settings(DEFAULT_HOME="#1")
|
@override_settings(_TEST_ENVIRONMENT=True)
|
||||||
def test_run_init_hooks(self):
|
def test_run_init_hooks(self):
|
||||||
from evennia.utils import create
|
from evennia.utils import create
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,34 @@
|
||||||
"""
|
"""
|
||||||
Various helper resources for writing unittests.
|
Various helper resources for writing unittests.
|
||||||
|
|
||||||
|
Classes for testing Evennia core:
|
||||||
|
|
||||||
|
- `BaseEvenniaTestCase` - no default objects, only enforced default settings
|
||||||
|
- `BaseEvenniaTest` - all default objects, enforced default settings
|
||||||
|
- `BaseEvenniaCommandTest` - for testing Commands, enforced default settings
|
||||||
|
|
||||||
|
Classes for testing game folder content:
|
||||||
|
|
||||||
|
- `EvenniaTestCase` - no default objects, using gamedir settings (identical to
|
||||||
|
standard Python TestCase)
|
||||||
|
- `EvenniaTest` - all default objects, using gamedir settings
|
||||||
|
- `EvenniaCommandTest` - for testing game folder commands, using gamedir settings
|
||||||
|
|
||||||
|
Other:
|
||||||
|
|
||||||
|
- `EvenniaTestMixin` - A class mixin for creating the test environment objects, for
|
||||||
|
making custom tests.
|
||||||
|
- `EvenniaCommandMixin` - A class mixin that adds support for command testing with the .call()
|
||||||
|
helper. Used by the command-test classes, but can be used for making a customt test class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
import types
|
||||||
from twisted.internet.defer import Deferred
|
from twisted.internet.defer import Deferred
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from mock import Mock, patch
|
from mock import Mock, patch, MagicMock
|
||||||
from evennia.objects.objects import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
|
from evennia.objects.objects import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
|
||||||
from evennia.accounts.accounts import DefaultAccount
|
from evennia.accounts.accounts import DefaultAccount
|
||||||
from evennia.scripts.scripts import DefaultScript
|
from evennia.scripts.scripts import DefaultScript
|
||||||
|
|
@ -14,8 +36,14 @@ from evennia.server.serversession import ServerSession
|
||||||
from evennia.server.sessionhandler import SESSIONS
|
from evennia.server.sessionhandler import SESSIONS
|
||||||
from evennia.utils import create
|
from evennia.utils import create
|
||||||
from evennia.utils.idmapper.models import flush_cache
|
from evennia.utils.idmapper.models import flush_cache
|
||||||
from evennia.utils.utils import all_from_module
|
from evennia.utils.utils import all_from_module, to_str
|
||||||
|
from evennia.utils import ansi
|
||||||
from evennia import settings_default
|
from evennia import settings_default
|
||||||
|
from evennia.commands.default.muxcommand import MuxCommand
|
||||||
|
from evennia.commands.command import InterruptCommand
|
||||||
|
|
||||||
|
|
||||||
|
_RE_STRIP_EVMENU = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
# set up a 'pristine' setting, unaffected by any changes in mygame
|
# set up a 'pristine' setting, unaffected by any changes in mygame
|
||||||
|
|
@ -242,14 +270,275 @@ class EvenniaTestMixin:
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
@patch("evennia.server.portal.portal.LoopingCall", new=MagicMock())
|
||||||
|
class EvenniaCommandTestMixin:
|
||||||
|
"""
|
||||||
|
Mixin to add to a test in order to provide the `.call` helper for
|
||||||
|
testing the execution and returns of a command.
|
||||||
|
|
||||||
|
Tests a Command by running it and comparing what messages it sends with
|
||||||
|
expected values. This tests without actually spinning up the cmdhandler
|
||||||
|
for every test, which is more controlled.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
::
|
||||||
|
|
||||||
|
from commands.echo import CmdEcho
|
||||||
|
|
||||||
|
class MyCommandTest(EvenniaTest, CommandTestMixin):
|
||||||
|
|
||||||
|
def test_echo(self):
|
||||||
|
'''
|
||||||
|
Test that the echo command really returns
|
||||||
|
what you pass into it.
|
||||||
|
'''
|
||||||
|
self.call(MyCommand(), "hello world!",
|
||||||
|
"You hear your echo: 'Hello world!'")
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# formatting for .call's error message
|
||||||
|
_ERROR_FORMAT = """
|
||||||
|
=========================== Wanted message ===================================
|
||||||
|
{expected_msg}
|
||||||
|
=========================== Returned message =================================
|
||||||
|
{returned_msg}
|
||||||
|
==============================================================================
|
||||||
|
""".rstrip()
|
||||||
|
|
||||||
|
def call(
|
||||||
|
self,
|
||||||
|
cmdobj,
|
||||||
|
input_args,
|
||||||
|
msg=None,
|
||||||
|
cmdset=None,
|
||||||
|
noansi=True,
|
||||||
|
caller=None,
|
||||||
|
receiver=None,
|
||||||
|
cmdstring=None,
|
||||||
|
obj=None,
|
||||||
|
inputs=None,
|
||||||
|
raw_string=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Test a command by assigning all the needed properties to a cmdobj and
|
||||||
|
running the sequence. The resulting `.msg` calls will be mocked and
|
||||||
|
the text= calls to them compared to a expected output.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cmdobj (Command): The command object to use.
|
||||||
|
input_args (str): This should be the full input the Command should
|
||||||
|
see, such as 'look here'. This will become `.args` for the Command
|
||||||
|
instance to parse.
|
||||||
|
msg (str or dict, optional): This is the expected return value(s)
|
||||||
|
returned through `caller.msg(text=...)` calls in the command. If a string, the
|
||||||
|
receiver is controlled with the `receiver` kwarg (defaults to `caller`).
|
||||||
|
If this is a `dict`, it is a mapping
|
||||||
|
`{receiver1: "expected1", receiver2: "expected2",...}` and `receiver` is
|
||||||
|
ignored. The message(s) are compared with the actual messages returned
|
||||||
|
to the receiver(s) as the Command runs. Each check uses `.startswith`,
|
||||||
|
so you can choose to only include the first part of the
|
||||||
|
returned message if that's enough to verify a correct result. EvMenu
|
||||||
|
decorations (like borders) are stripped and should not be included. This
|
||||||
|
should also not include color tags unless `noansi=False`.
|
||||||
|
If the command returns texts in multiple separate `.msg`-
|
||||||
|
calls to a receiver, separate these with `|` if `noansi=True`
|
||||||
|
(default) and `||` if `noansi=False`. If no `msg` is given (`None`),
|
||||||
|
then no automatic comparison will be done.
|
||||||
|
cmdset (str, optional): If given, make `.cmdset` available on the Command
|
||||||
|
instance as it runs. While `.cmdset` is normally available on the
|
||||||
|
Command instance by default, this is usually only used by
|
||||||
|
commands that explicitly operates/displays cmdsets, like
|
||||||
|
`examine`.
|
||||||
|
noansi (str, optional): By default the color tags of the `msg` is
|
||||||
|
ignored, this makes them significant. If unset, `msg` must contain
|
||||||
|
the same color tags as the actual return message.
|
||||||
|
caller (Object or Account, optional): By default `self.char1` is used as the
|
||||||
|
command-caller (the `.caller` property on the Command). This allows to
|
||||||
|
execute with another caller, most commonly an Account.
|
||||||
|
receiver (Object or Account, optional): This is the object to receive the
|
||||||
|
return messages we want to test. By default this is the same as `caller`
|
||||||
|
(which in turn defaults to is `self.char1`). Note that if `msg` is
|
||||||
|
a `dict`, this is ignored since the receiver is already specified there.
|
||||||
|
cmdstring (str, optional): Normally this is the Command's `key`.
|
||||||
|
This allows for tweaking the `.cmdname` property of the
|
||||||
|
Command`. This isb used for commands with multiple aliases,
|
||||||
|
where the command explicitly checs which alias was used to
|
||||||
|
determine its functionality.
|
||||||
|
obj (str, optional): This sets the `.obj` property of the Command - the
|
||||||
|
object on which the Command 'sits'. By default this is the same as `caller`.
|
||||||
|
This can be used for testing on-object Command interactions.
|
||||||
|
inputs (list, optional): A list of strings to pass to functions that pause to
|
||||||
|
take input from the user (normally using `@interactive` and
|
||||||
|
`ret = yield(question)` or `evmenu.get_input`). Each element of the
|
||||||
|
list will be passed into the command as if the user wrote that at the prompt.
|
||||||
|
raw_string (str, optional): Normally the `.raw_string` property is set as
|
||||||
|
a combination of your `key/cmdname` and `input_args`. This allows
|
||||||
|
direct control of what this is, for example for testing edge cases
|
||||||
|
or malformed inputs.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or dict: The message sent to `receiver`, or a dict of
|
||||||
|
`{receiver: "msg", ...}` if multiple are given. This is usually
|
||||||
|
only used with `msg=None` to do the validation externally.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
AssertionError: If the returns of `.msg` calls (tested with `.startswith`) does not
|
||||||
|
match `expected_input`.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
As part of the tests, all methods of the Command will be called in
|
||||||
|
the proper order:
|
||||||
|
|
||||||
|
- cmdobj.at_pre_cmd()
|
||||||
|
- cmdobj.parse()
|
||||||
|
- cmdobj.func()
|
||||||
|
- cmdobj.at_post_cmd()
|
||||||
|
|
||||||
|
"""
|
||||||
|
# The `self.char1` is created in the `EvenniaTest` base along with
|
||||||
|
# other helper objects like self.room and self.obj
|
||||||
|
caller = caller if caller else self.char1
|
||||||
|
cmdobj.caller = caller
|
||||||
|
cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key
|
||||||
|
cmdobj.raw_cmdname = cmdobj.cmdname
|
||||||
|
cmdobj.cmdstring = cmdobj.cmdname # deprecated
|
||||||
|
cmdobj.args = input_args
|
||||||
|
cmdobj.cmdset = cmdset
|
||||||
|
cmdobj.session = SESSIONS.session_from_sessid(1)
|
||||||
|
cmdobj.account = self.account
|
||||||
|
cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args
|
||||||
|
cmdobj.obj = obj or (caller if caller else self.char1)
|
||||||
|
inputs = inputs or []
|
||||||
|
|
||||||
|
# set up receivers
|
||||||
|
receiver_mapping = {}
|
||||||
|
if isinstance(msg, dict):
|
||||||
|
# a mapping {receiver: msg, ...}
|
||||||
|
receiver_mapping = {recv: str(msg).strip() if msg else None
|
||||||
|
for recv, msg in msg.items()}
|
||||||
|
else:
|
||||||
|
# a single expected string and thus a single receiver (defaults to caller)
|
||||||
|
receiver = receiver if receiver else caller
|
||||||
|
receiver_mapping[receiver] = str(msg).strip() if msg is not None else None
|
||||||
|
|
||||||
|
unmocked_msg_methods = {}
|
||||||
|
for receiver in receiver_mapping:
|
||||||
|
# save the old .msg method so we can get it back
|
||||||
|
# cleanly after the test
|
||||||
|
unmocked_msg_methods[receiver] = receiver.msg
|
||||||
|
# replace normal `.msg` with a mock
|
||||||
|
receiver.msg = Mock()
|
||||||
|
|
||||||
|
# Run the methods of the Command. This mimics what happens in the
|
||||||
|
# cmdhandler. This will have the mocked .msg be called as part of the
|
||||||
|
# execution. Mocks remembers what was sent to them so we will be able
|
||||||
|
# to retrieve what was sent later.
|
||||||
|
try:
|
||||||
|
if cmdobj.at_pre_cmd():
|
||||||
|
return
|
||||||
|
cmdobj.parse()
|
||||||
|
ret = cmdobj.func()
|
||||||
|
|
||||||
|
# handle func's with yield in them (making them generators)
|
||||||
|
if isinstance(ret, types.GeneratorType):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
inp = inputs.pop() if inputs else None
|
||||||
|
if inp:
|
||||||
|
try:
|
||||||
|
# this mimics a user's reply to a prompt
|
||||||
|
ret.send(inp)
|
||||||
|
except TypeError:
|
||||||
|
next(ret)
|
||||||
|
ret = ret.send(inp)
|
||||||
|
else:
|
||||||
|
# non-input yield, like yield(10). We don't pause
|
||||||
|
# but fire it immediately.
|
||||||
|
next(ret)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
|
||||||
|
cmdobj.at_post_cmd()
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
except InterruptCommand:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for inp in inputs:
|
||||||
|
# if there are any inputs left, we may have a non-generator
|
||||||
|
# input to handle (get_input/ask_yes_no that uses a separate
|
||||||
|
# cmdset rather than a yield
|
||||||
|
caller.execute_cmd(inp)
|
||||||
|
|
||||||
|
# At this point the mocked .msg methods on each receiver will have
|
||||||
|
# stored all calls made to them (that's a basic function of the Mock
|
||||||
|
# class). We will not extract them and compare to what we expected to
|
||||||
|
# go to each receiver.
|
||||||
|
|
||||||
|
returned_msgs = {}
|
||||||
|
for receiver, expected_msg in receiver_mapping.items():
|
||||||
|
# get the stored messages from the Mock with Mock.mock_calls.
|
||||||
|
stored_msg = [
|
||||||
|
args[0] if args and args[0] else kwargs.get("text", to_str(kwargs))
|
||||||
|
for name, args, kwargs in receiver.msg.mock_calls
|
||||||
|
]
|
||||||
|
# we can return this now, we are done using the mock
|
||||||
|
receiver.msg = unmocked_msg_methods[receiver]
|
||||||
|
|
||||||
|
# Get the first element of a tuple if msg received a tuple instead of a string
|
||||||
|
stored_msg = [str(smsg[0])
|
||||||
|
if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg]
|
||||||
|
if expected_msg is None:
|
||||||
|
# no expected_msg; just build the returned_msgs dict
|
||||||
|
|
||||||
|
returned_msg = "\n".join(str(msg) for msg in stored_msg)
|
||||||
|
returned_msgs[receiver] = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
|
||||||
|
else:
|
||||||
|
# compare messages to expected
|
||||||
|
|
||||||
|
# set our separator for returned messages based on parsing ansi or not
|
||||||
|
msg_sep = "|" if noansi else "||"
|
||||||
|
|
||||||
|
# We remove Evmenu decorations since that just makes it harder
|
||||||
|
# to write the comparison string. We also strip ansi before this
|
||||||
|
# comparison since otherwise it would mess with the regex.
|
||||||
|
returned_msg = msg_sep.join(
|
||||||
|
_RE_STRIP_EVMENU.sub(
|
||||||
|
"", ansi.parse_ansi(mess, strip_ansi=noansi))
|
||||||
|
for mess in stored_msg).strip()
|
||||||
|
|
||||||
|
# this is the actual test
|
||||||
|
if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg):
|
||||||
|
# failed the test
|
||||||
|
raise AssertionError(
|
||||||
|
self._ERROR_FORMAT.format(
|
||||||
|
expected_msg=expected_msg, returned_msg=returned_msg)
|
||||||
|
)
|
||||||
|
# passed!
|
||||||
|
returned_msgs[receiver] = returned_msg
|
||||||
|
|
||||||
|
if len(returned_msgs) == 1:
|
||||||
|
return list(returned_msgs.values())[0]
|
||||||
|
return returned_msgs
|
||||||
|
|
||||||
|
|
||||||
|
# Base testing classes
|
||||||
|
|
||||||
@override_settings(**DEFAULT_SETTINGS)
|
@override_settings(**DEFAULT_SETTINGS)
|
||||||
class BaseEvenniaTestCase(TestCase):
|
class BaseEvenniaTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
Base test (with no default objects) but with
|
Base test (with no default objects) but with enforced default settings.
|
||||||
enforced default settings.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class EvenniaTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
For use with gamedir settings; Just like the normal test case, only for naming consistency.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@override_settings(**DEFAULT_SETTINGS)
|
@override_settings(**DEFAULT_SETTINGS)
|
||||||
class BaseEvenniaTest(EvenniaTestMixin, TestCase):
|
class BaseEvenniaTest(EvenniaTestMixin, TestCase):
|
||||||
|
|
@ -258,7 +547,6 @@ class BaseEvenniaTest(EvenniaTestMixin, TestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class EvenniaTest(EvenniaTestMixin, TestCase):
|
class EvenniaTest(EvenniaTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
This test class is intended for inheriting in mygame tests.
|
This test class is intended for inheriting in mygame tests.
|
||||||
|
|
@ -273,3 +561,28 @@ class EvenniaTest(EvenniaTestMixin, TestCase):
|
||||||
exit_typeclass = settings.BASE_EXIT_TYPECLASS
|
exit_typeclass = settings.BASE_EXIT_TYPECLASS
|
||||||
room_typeclass = settings.BASE_ROOM_TYPECLASS
|
room_typeclass = settings.BASE_ROOM_TYPECLASS
|
||||||
script_typeclass = settings.BASE_SCRIPT_TYPECLASS
|
script_typeclass = settings.BASE_SCRIPT_TYPECLASS
|
||||||
|
|
||||||
|
|
||||||
|
@patch("evennia.commands.account.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.admin.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.batchprocess.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.building.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.comms.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.general.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.help.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.syscommands.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.system.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
@patch("evennia.commands.unloggedin.COMMAND_DEFAULT_CLASS", MuxCommand)
|
||||||
|
class BaseEvenniaCommandTest(BaseEvenniaTest, EvenniaCommandTestMixin):
|
||||||
|
"""
|
||||||
|
Commands only using the default settings.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class EvenniaCommandTest(EvenniaTest, EvenniaCommandTestMixin):
|
||||||
|
"""
|
||||||
|
Parent class to inherit from - makes tests use your own
|
||||||
|
classes and settings in mygame.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ Test eveditor
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia.utils import eveditor
|
from evennia.utils import eveditor
|
||||||
from evennia.commands.default.tests import EvenniaCommandTest
|
from evennia.commands.default.tests import BaseEvenniaCommandTest
|
||||||
|
|
||||||
|
|
||||||
class TestEvEditor(EvenniaCommandTest):
|
class TestEvEditor(BaseEvenniaCommandTest):
|
||||||
def test_eveditor_view_cmd(self):
|
def test_eveditor_view_cmd(self):
|
||||||
eveditor.EvEditor(self.char1)
|
eveditor.EvEditor(self.char1)
|
||||||
self.call(
|
self.call(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue