#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Unit test module for Trait classes.
"""
from copy import copy
from anything import Something
from mock import MagicMock, patch
from evennia.objects.objects import DefaultCharacter
from evennia.utils.test_resources import BaseEvenniaTestCase, EvenniaTest
from . import traits
class _MockObj:
def __init__(self):
self.attributes = MagicMock()
self.attributes.get = self.get
self.attributes.add = self.add
self.dbstore = {}
self.category = "traits"
def get(self, key, category=None):
assert category == self.category
return self.dbstore.get(key)
def add(self, key, value, category=None):
assert category == self.category
self.dbstore[key] = value
# we want to test the base traits too
_TEST_TRAIT_CLASS_PATHS = [
"evennia.contrib.rpg.traits.Trait",
"evennia.contrib.rpg.traits.StaticTrait",
"evennia.contrib.rpg.traits.CounterTrait",
"evennia.contrib.rpg.traits.GaugeTrait",
]
class _TraitHandlerBase(BaseEvenniaTestCase):
"Base for trait tests"
@patch("evennia.contrib.rpg.traits.traits._TRAIT_CLASS_PATHS", new=_TEST_TRAIT_CLASS_PATHS)
def setUp(self):
self.obj = _MockObj()
self.traithandler = traits.TraitHandler(self.obj)
self.obj.traits = self.traithandler
def _get_dbstore(self, key):
return self.obj.dbstore["traits"][key]
[docs]class TraitHandlerTest(_TraitHandlerBase):
"""Testing for TraitHandler"""
[docs] def setUp(self):
super().setUp()
self.traithandler.add("test1", name="Test1", trait_type="trait")
self.traithandler.add(
"test2",
name="Test2",
trait_type="trait",
value=["foo", {"1": [1, 2, 3]}, 4],
)
[docs] def test_add_trait(self):
self.assertEqual(
self._get_dbstore("test1"),
{
"name": "Test1",
"trait_type": "trait",
"value": None,
},
)
self.assertEqual(
self._get_dbstore("test2"),
{
"name": "Test2",
"trait_type": "trait",
"value": ["foo", {"1": [1, 2, 3]}, 4],
},
)
self.assertEqual(len(self.traithandler), 2)
[docs] def test_cache(self):
"""
Cache should not be set until first get
"""
self.assertEqual(len(self.traithandler._cache), 0)
self.traithandler.all() # does not affect cache
self.assertEqual(len(self.traithandler._cache), 0)
self.traithandler.test1
self.assertEqual(len(self.traithandler._cache), 1)
self.traithandler.test2
self.assertEqual(len(self.traithandler._cache), 2)
[docs] def test_setting(self):
"Don't allow setting stuff on traithandler"
with self.assertRaises(traits.TraitException):
self.traithandler.foo = "bar"
with self.assertRaises(traits.TraitException):
self.traithandler["foo"] = "bar"
with self.assertRaises(traits.TraitException):
self.traithandler.test1 = "foo"
[docs] def test_getting(self):
"Test we are getting data from the dbstore"
self.assertEqual(
self.traithandler.test1._data, {"name": "Test1", "trait_type": "trait", "value": None}
)
self.assertEqual(self.traithandler._cache, Something)
self.assertEqual(
self.traithandler.test2._data,
{"name": "Test2", "trait_type": "trait", "value": ["foo", {"1": [1, 2, 3]}, 4]},
)
self.assertEqual(self.traithandler._cache, Something)
self.assertFalse(self.traithandler.get("foo"))
self.assertFalse(self.traithandler.bar)
[docs] def test_all(self):
"Test all method"
self.assertEqual(self.traithandler.all(), ["test1", "test2"])
[docs] def test_remove(self):
"Test remove method"
self.traithandler.remove("test2")
self.assertEqual(len(self.traithandler), 1)
self.assertTrue(bool(self.traithandler.get("test1"))) # this populates cache
self.assertEqual(len(self.traithandler._cache), 1)
with self.assertRaises(traits.TraitException):
self.traithandler.remove("foo")
[docs] def test_clear(self):
"Test clear method"
self.traithandler.clear()
self.assertEqual(len(self.traithandler), 0)
[docs] def test_trait_db_connection(self):
"Test that updating a trait property actually updates value in db"
trait = self.traithandler.test1
self.assertEqual(trait.value, None)
trait.value = 10
self.assertEqual(trait.value, 10)
self.assertEqual(self.obj.attributes.get("traits", category="traits")["test1"]["value"], 10)
trait.value = 20
self.assertEqual(trait.value, 20)
self.assertEqual(self.obj.attributes.get("traits", category="traits")["test1"]["value"], 20)
del trait.value
self.assertEqual(
self.obj.attributes.get("traits", category="traits")["test1"]["value"], None
)
[docs]class TestTrait(_TraitHandlerBase):
"""
Test the base Trait class
"""
[docs] def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="trait",
value="value",
extra_val1="xvalue1",
extra_val2="xvalue2",
)
self.trait = self.traithandler.get("test1")
[docs] def test_init(self):
self.assertEqual(
self.trait._data,
{
"name": "Test1",
"trait_type": "trait",
"value": "value",
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
},
)
[docs] def test_trait_getset(self):
"""Get-set-del operations on trait"""
self.assertEqual(self.trait.name, "Test1")
self.assertEqual(self.trait["name"], "Test1")
self.assertEqual(self.trait.value, "value")
self.assertEqual(self.trait["value"], "value")
self.assertEqual(self.trait.extra_val1, "xvalue1")
self.assertEqual(self.trait["extra_val2"], "xvalue2")
self.trait.value = 20
self.assertEqual(self.trait["value"], 20)
self.trait["value"] = 20
self.assertEqual(self.trait.value, 20)
self.trait.extra_val1 = 100
self.assertEqual(self.trait.extra_val1, 100)
# additional properties
self.trait.foo = "bar"
self.assertEqual(self.trait.foo, "bar")
del self.trait.foo
with self.assertRaises(KeyError):
self.trait["foo"]
with self.assertRaises(AttributeError):
self.trait.foo
del self.trait.extra_val1
with self.assertRaises(AttributeError):
self.trait.extra_val1
del self.trait.value
# fall back to default
self.assertTrue(self.trait.value == traits.Trait.default_keys["value"])
[docs] def test_repr(self):
self.assertEqual(repr(self.trait), Something)
self.assertEqual(str(self.trait), Something)
[docs]class TestTraitStatic(_TraitHandlerBase):
"""
Test for static Traits
"""
[docs] def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="static",
base=1,
mod=2,
mult=1.0,
extra_val1="xvalue1",
extra_val2="xvalue2",
)
self.trait = self.traithandler.get("test1")
def _get_values(self):
return self.trait.base, self.trait.mod, self.trait.mult, self.trait.value
[docs] def test_init(self):
self.assertEqual(
self._get_dbstore("test1"),
{
"name": "Test1",
"trait_type": "static",
"base": 1,
"mod": 2,
"mult": 1.0,
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
},
)
[docs] def test_value(self):
"""value is (base + mod) * mult"""
self.assertEqual(self._get_values(), (1, 2, 1.0, 3))
self.trait.base += 4
self.assertEqual(self._get_values(), (5, 2, 1.0, 7))
self.trait.mod -= 1
self.assertEqual(self._get_values(), (5, 1, 1.0, 6))
self.trait.mult += 1.0
self.assertEqual(self._get_values(), (5, 1, 2.0, 12))
self.trait.mult = 0.75
self.assertEqual(self._get_values(), (5, 1, 0.75, 4.5))
[docs] def test_delete(self):
"""Deleting resets to default."""
self.trait.mult = 2.0
del self.trait.base
self.assertEqual(self._get_values(), (0, 2, 2.0, 4))
del self.trait.mult
self.assertEqual(self._get_values(), (0, 2, 1.0, 2))
del self.trait.mod
self.assertEqual(self._get_values(), (0, 0, 1.0, 0))
[docs]class TestTraitCounter(_TraitHandlerBase):
"""
Test for counter- Traits
"""
[docs] def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="counter",
base=1,
mod=2,
mult=1.0,
min=0,
max=10,
extra_val1="xvalue1",
extra_val2="xvalue2",
descs={
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
)
self.trait = self.traithandler.get("test1")
def _get_values(self):
"""Get (base, mod, mult, value, min, max)."""
return (
self.trait.base,
self.trait.mod,
self.trait.mult,
self.trait.value,
self.trait.min,
self.trait.max,
)
[docs] def test_init(self):
self.assertEqual(
self._get_dbstore("test1"),
{
"name": "Test1",
"trait_type": "counter",
"base": 1,
"mod": 2,
"mult": 1.0,
"min": 0,
"max": 10,
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
"descs": {
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
"rate": 0,
"ratetarget": None,
"last_update": None,
},
)
[docs] def test_value(self):
"""value is (current + mod) * mult, where current defaults to base"""
self.assertEqual(self._get_values(), (1, 2, 1.0, 3, 0, 10))
self.trait.base += 4
self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 0, 10))
self.trait.mod -= 1
self.assertEqual(self._get_values(), (5, 1, 1.0, 6, 0, 10))
self.trait.mult += 1.0
self.assertEqual(self._get_values(), (5, 1, 2.0, 10, 0, 10))
[docs] def test_boundaries__minmax(self):
"""Test range"""
# should not exceed min/max values
self.trait.base += 20
self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10))
self.trait.base = 100
self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10))
self.trait.base -= 40
self.assertEqual(self._get_values(), (-2, 2, 1.0, 0, 0, 10))
self.trait.base = -100
self.assertEqual(self._get_values(), (-2, 2, 1.0, 0, 0, 10))
[docs] def test_boundaries__bigmod(self):
"""add a big mod"""
self.trait.base = 5
self.trait.mod = 100
self.assertEqual(self._get_values(), (5, 5, 1.0, 10, 0, 10))
self.trait.mod = -100
self.assertEqual(self._get_values(), (5, -5, 1.0, 0, 0, 10))
[docs] def test_boundaries__change_boundaries(self):
"""Change boundaries after base/mod change"""
self.trait.base = 5
self.trait.mod = -100
self.trait.min = -20
self.assertEqual(self._get_values(), (5, -5, 1.0, 0, -20, 10))
self.trait.mod -= 100
self.assertEqual(self._get_values(), (5, -25, 1.0, -20, -20, 10))
self.trait.mod = 100
self.trait.max = 20
self.assertEqual(self._get_values(), (5, 5, 1.0, 10, -20, 20))
self.trait.mod = 100
self.assertEqual(self._get_values(), (5, 15, 1.0, 20, -20, 20))
[docs] def test_boundaries__disable(self):
"""Disable and re-enable boundaries"""
self.trait.base = 5
self.trait.mod = 100
self.assertEqual(self._get_values(), (5, 5, 1.0, 10, 0, 10))
del self.trait.max
self.assertEqual(self.trait.max, None)
del self.trait.min
self.assertEqual(self.trait.min, None)
self.trait.base = 100
self.assertEqual(self._get_values(), (100, 5, 1.0, 105, None, None))
self.trait.base = -200
self.assertEqual(self._get_values(), (-200, 5, 1.0, -195, None, None))
# re-activate boundaries
self.trait.max = 15
self.trait.min = 10 # his is blocked since base+mod is lower
self.assertEqual(self._get_values(), (-200, 5, 1.0, -195, -195, 15))
[docs] def test_boundaries__inverse(self):
"""Set inverse boundaries - limited by base"""
self.trait.mod = 0
self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 0, 10))
self.trait.min = 20 # will be set to base
self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 1, 10))
self.trait.max = -20
self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 1, 1))
[docs] def test_current(self):
"""Modifying current value"""
self.trait.current = 5
self.assertEqual(self._get_values(), (1, 2, 1.0, 7, 0, 10))
self.trait.current = 10
self.assertEqual(self._get_values(), (1, 2, 1.0, 10, 0, 10))
self.trait.current = 12
self.assertEqual(self._get_values(), (1, 2, 1.0, 10, 0, 10))
self.trait.current = -1
self.assertEqual(self._get_values(), (1, 2, 1.0, 2, 0, 10))
self.trait.current -= 10
self.assertEqual(self._get_values(), (1, 2, 1.0, 2, 0, 10))
[docs] def test_delete(self):
"""Deleting resets to default."""
del self.trait.base
self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 10))
del self.trait.mod
self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 10))
del self.trait.min
del self.trait.max
self.assertEqual(self._get_values(), (0, 0, 1.0, 0, None, None))
[docs] def test_percentage(self):
"""Test percentage calculation"""
self.trait.base = 8
self.trait.mod = 2
self.trait.mult = 1.0
self.trait.min = 0
self.trait.max = 10
self.assertEqual(self.trait.percent(), "100.0%")
self.trait.current = 3
self.assertEqual(self.trait.percent(), "50.0%")
self.trait.current = 1
self.assertEqual(self.trait.percent(), "30.0%")
# have to lower this since max cannot be lowered below base+mod
self.trait.mod = 1
self.trait.current = 2
self.trait.max -= 1
self.assertEqual(self.trait.percent(), "33.3%")
# open boundary
del self.trait.min
self.assertEqual(self.trait.percent(), "100.0%")
[docs] def test_descs(self):
"""Test descriptions"""
self.trait.min = -5
self.trait.mod = 0
self.assertEqual(self._get_values(), (1, 0, 1.0, 1, -5, 10))
self.trait.current = -2
self.assertEqual(self.trait.desc(), "range0")
self.trait.current = 0
self.assertEqual(self.trait.desc(), "range0")
self.trait.current = 1
self.assertEqual(self.trait.desc(), "range1")
self.trait.current = 3
self.assertEqual(self.trait.desc(), "range2")
self.trait.current = 5
self.assertEqual(self.trait.desc(), "range2")
self.trait.current = 9
self.assertEqual(self.trait.desc(), "range3")
self.trait.current = 100
self.assertEqual(self.trait.desc(), "range3")
[docs]class TestTraitCounterTimed(_TraitHandlerBase):
"""
Test for trait with timer component
"""
[docs] @patch("evennia.contrib.rpg.traits.traits.time", new=MagicMock(return_value=1000))
def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="counter",
base=1,
mod=2,
mult=1.0,
min=0,
max=100,
extra_val1="xvalue1",
extra_val2="xvalue2",
descs={
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
rate=1,
ratetarget=None,
)
self.trait = self.traithandler.get("test1")
def _get_timer_data(self):
return (
self.trait.value,
self.trait.current,
self.trait.rate,
self.trait._data["last_update"],
self.trait.ratetarget,
)
[docs] @patch("evennia.contrib.rpg.traits.traits.time")
def test_timer_rate(self, mock_time):
"""Test time stepping"""
mock_time.return_value = 1000
self.assertEqual(self._get_timer_data(), (3, 1, 1, 1000, None))
mock_time.return_value = 1001
self.assertEqual(self._get_timer_data(), (4, 2, 1, 1001, None))
mock_time.return_value = 1096
self.assertEqual(self._get_timer_data(), (99, 97, 1, 1096, None))
# hit maximum boundary
mock_time.return_value = 1120
self.assertEqual(self._get_timer_data(), (100, 98, 1, None, None))
mock_time.return_value = 1200
self.assertEqual(self._get_timer_data(), (100, 98, 1, None, None))
# drop current
self.trait.current = 50
self.assertEqual(self._get_timer_data(), (52, 50, 1, 1200, None))
# set a new rate
self.trait.rate = 2
mock_time.return_value = 1210
self.assertEqual(self._get_timer_data(), (72, 70, 2, 1210, None))
self.trait.rate = -10
mock_time.return_value = 1214
self.assertEqual(self._get_timer_data(), (32, 30, -10, 1214, None))
mock_time.return_value = 1218
self.assertEqual(self._get_timer_data(), (0, -2, -10, None, None))
[docs] @patch("evennia.contrib.rpg.traits.traits.time")
def test_timer_ratetarget(self, mock_time):
"""test ratetarget"""
mock_time.return_value = 1000
self.trait.ratetarget = 60
self.assertEqual(self._get_timer_data(), (3, 1, 1, 1000, 60))
mock_time.return_value = 1056
self.assertEqual(self._get_timer_data(), (59, 57, 1, 1056, 60))
mock_time.return_value = 1057
self.assertEqual(self._get_timer_data(), (60, 58, 1, None, 60))
mock_time.return_value = 1060
self.assertEqual(self._get_timer_data(), (60, 58, 1, None, 60))
self.trait.ratetarget = 70
mock_time.return_value = 1066
self.assertEqual(self._get_timer_data(), (66, 64, 1, 1066, 70))
mock_time.return_value = 1070
self.assertEqual(self._get_timer_data(), (70, 68, 1, None, 70))
[docs]class TestTraitGauge(_TraitHandlerBase):
[docs] def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="gauge",
base=8, # max = (base + mod) * mult
mod=2,
mult=1.0,
extra_val1="xvalue1",
extra_val2="xvalue2",
descs={
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
)
self.trait = self.traithandler.get("test1")
def _get_values(self):
"""Get (base, mod, mult, value, min, max)."""
return (
self.trait.base,
self.trait.mod,
self.trait.mult,
self.trait.value,
self.trait.min,
self.trait.max,
)
[docs] def test_init(self):
self.assertEqual(
self._get_dbstore("test1"),
{
"name": "Test1",
"trait_type": "gauge",
"base": 8,
"mod": 2,
"mult": 1.0,
"min": 0,
"extra_val1": "xvalue1",
"extra_val2": "xvalue2",
"descs": {
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
"rate": 0,
"ratetarget": None,
"last_update": None,
},
)
[docs] def test_value(self):
"""value is current, where current defaults to base + mod"""
# current unset - follows base + mod
self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10))
self.trait.base += 4
self.assertEqual(self._get_values(), (12, 2, 1.0, 14, 0, 14))
self.trait.mod -= 1
self.assertEqual(self._get_values(), (12, 1, 1.0, 13, 0, 13))
self.trait.mult += 1.0
self.assertEqual(self._get_values(), (12, 1, 2.0, 26, 0, 26))
# set current, decouple from base + mod
self.trait.current = 5
self.assertEqual(self._get_values(), (12, 1, 2.0, 5, 0, 26))
self.trait.mod += 1
self.trait.base -= 4
self.trait.mult -= 1.0
self.assertEqual(self._get_values(), (8, 2, 1.0, 5, 0, 10))
self.trait.min = -100
self.trait.base = -20
self.assertEqual(self._get_values(), (-20, 2, 1.0, -18, -100, -18))
[docs] def test_boundaries__minmax(self):
"""Test range"""
# current unset - tied to base + mod
self.trait.base += 20
self.assertEqual(self._get_values(), (28, 2, 1.0, 30, 0, 30))
# set current - decouple from base + mod
self.trait.current = 19
self.assertEqual(self._get_values(), (28, 2, 1.0, 19, 0, 30))
# test upper bound
self.trait.current = 100
self.assertEqual(self._get_values(), (28, 2, 1.0, 30, 0, 30))
# with multiplier
self.trait.mult = 2.0
self.assertEqual(self._get_values(), (28, 2, 2.0, 30, 0, 60))
self.trait.current = 100
self.assertEqual(self._get_values(), (28, 2, 2.0, 60, 0, 60))
# min defaults to 0
self.trait.mult = 1.0
self.trait.current = -10
self.assertEqual(self._get_values(), (28, 2, 1.0, 0, 0, 30))
self.trait.min = -20
self.assertEqual(self._get_values(), (28, 2, 1.0, 0, -20, 30))
self.trait.current = -10
self.assertEqual(self._get_values(), (28, 2, 1.0, -10, -20, 30))
[docs] def test_boundaries__bigmod(self):
"""add a big mod"""
self.trait.base = 5
self.trait.mod = 100
self.assertEqual(self._get_values(), (5, 100, 1.0, 105, 0, 105))
# restricted by min
self.trait.mod = -100
self.assertEqual(self._get_values(), (5, -5, 1.0, 0, 0, 0))
self.trait.min = -200
self.assertEqual(self._get_values(), (5, -5, 1.0, 0, -200, 0))
[docs] def test_boundaries__change_boundaries(self):
"""Change boundaries after current change"""
self.trait.current = 20
self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10))
self.trait.mod = 102
self.assertEqual(self._get_values(), (8, 102, 1.0, 10, 0, 110))
# raising min past current value will force it upwards
self.trait.min = 20
self.assertEqual(self._get_values(), (8, 102, 1.0, 20, 20, 110))
[docs] def test_boundaries__disable(self):
"""Disable and re-enable boundary"""
self.trait.base = 5
self.trait.min = 1
self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 1, 7))
del self.trait.min
self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 0, 7))
del self.trait.base
del self.trait.mod
self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 0))
with self.assertRaises(traits.TraitException):
del self.trait.max
[docs] def test_boundaries__inverse(self):
"""Try to set reversed boundaries"""
self.trait.mod = 0
self.trait.base = -10 # limited by min
self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 0))
self.trait.min = -10
self.assertEqual(self._get_values(), (0, 0, 1.0, 0, -10, 0))
self.trait.base = -10
self.assertEqual(self._get_values(), (-10, 0, 1.0, -10, -10, -10))
self.min = 0 # limited by base + mod
self.assertEqual(self._get_values(), (-10, 0, 1.0, -10, -10, -10))
[docs] def test_current(self):
"""Modifying current value"""
self.trait.base = 10
self.trait.current = 5
self.assertEqual(self._get_values(), (10, 2, 1.0, 5, 0, 12))
self.trait.current = 10
self.assertEqual(self._get_values(), (10, 2, 1.0, 10, 0, 12))
self.trait.current = 12
self.assertEqual(self._get_values(), (10, 2, 1.0, 12, 0, 12))
self.trait.current = 0
self.assertEqual(self._get_values(), (10, 2, 1.0, 0, 0, 12))
self.trait.current = -1
self.assertEqual(self._get_values(), (10, 2, 1.0, 0, 0, 12))
[docs] def test_delete(self):
"""Deleting resets to default."""
del self.trait.mod
self.assertEqual(self._get_values(), (8, 0, 1.0, 8, 0, 8))
self.trait.mod = 2
del self.trait.base
self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 2))
del self.trait.min
self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 2))
self.trait.min = -10
self.assertEqual(self._get_values(), (0, 2, 1.0, 2, -10, 2))
del self.trait.min
self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 2))
[docs] def test_percentage(self):
"""Test percentage calculation"""
self.assertEqual(self.trait.percent(), "100.0%")
self.trait.current = 5
self.assertEqual(self.trait.percent(), "50.0%")
self.trait.current = 3
self.assertEqual(self.trait.percent(), "30.0%")
self.trait.mod -= 1
self.assertEqual(self.trait.percent(), "33.3%")
[docs] def test_descs(self):
"""Test descriptions"""
self.trait.min = -5
self.assertEqual(self._get_values(), (8, 2, 1.0, 10, -5, 10))
self.trait.current = -2
self.assertEqual(self.trait.desc(), "range0")
self.trait.current = 0
self.assertEqual(self.trait.desc(), "range0")
self.trait.current = 1
self.assertEqual(self.trait.desc(), "range1")
self.trait.current = 3
self.assertEqual(self.trait.desc(), "range2")
self.trait.current = 5
self.assertEqual(self.trait.desc(), "range2")
self.trait.current = 9
self.assertEqual(self.trait.desc(), "range3")
self.trait.current = 100
self.assertEqual(self.trait.desc(), "range3")
[docs]class TestTraitGaugeTimed(_TraitHandlerBase):
"""
Test for trait with timer component
"""
[docs] @patch("evennia.contrib.rpg.traits.traits.time", new=MagicMock(return_value=1000))
def setUp(self):
super().setUp()
self.traithandler.add(
"test1",
name="Test1",
trait_type="gauge",
base=98,
mod=2,
min=0,
extra_val1="xvalue1",
extra_val2="xvalue2",
descs={
0: "range0",
2: "range1",
5: "range2",
7: "range3",
},
rate=1,
ratetarget=None,
)
self.trait = self.traithandler.get("test1")
def _get_timer_data(self):
return (
self.trait.value,
self.trait.current,
self.trait.rate,
self.trait._data["last_update"],
self.trait.ratetarget,
)
[docs] @patch("evennia.contrib.rpg.traits.traits.time")
def test_timer_rate(self, mock_time):
"""Test time stepping"""
mock_time.return_value = 1000
self.trait.current = 1
self.assertEqual(self._get_timer_data(), (1, 1, 1, 1000, None))
mock_time.return_value = 1001
self.assertEqual(self._get_timer_data(), (2, 2, 1, 1001, None))
mock_time.return_value = 1096
self.assertEqual(self._get_timer_data(), (97, 97, 1, 1096, None))
# hit maximum boundary
mock_time.return_value = 1120
self.assertEqual(self._get_timer_data(), (100, 100, 1, None, None))
mock_time.return_value = 1200
self.assertEqual(self._get_timer_data(), (100, 100, 1, None, None))
# drop current
self.trait.current = 50
self.assertEqual(self._get_timer_data(), (50, 50, 1, 1200, None))
# set a new rate
self.trait.rate = 2
mock_time.return_value = 1210
self.assertEqual(self._get_timer_data(), (70, 70, 2, 1210, None))
self.trait.rate = -10
mock_time.return_value = 1214
self.assertEqual(self._get_timer_data(), (30, 30, -10, 1214, None))
mock_time.return_value = 1218
self.assertEqual(self._get_timer_data(), (0, 0, -10, None, None))
[docs] @patch("evennia.contrib.rpg.traits.traits.time")
def test_timer_ratetarget(self, mock_time):
"""test ratetarget"""
mock_time.return_value = 1000
self.trait.current = 1
self.trait.ratetarget = 60
self.assertEqual(self._get_timer_data(), (1, 1, 1, 1000, 60))
mock_time.return_value = 1056
self.assertEqual(self._get_timer_data(), (57, 57, 1, 1056, 60))
mock_time.return_value = 1059
self.assertEqual(self._get_timer_data(), (60, 60, 1, None, 60))
mock_time.return_value = 1060
self.assertEqual(self._get_timer_data(), (60, 60, 1, None, 60))
self.trait.ratetarget = 70
mock_time.return_value = 1066
self.assertEqual(self._get_timer_data(), (66, 66, 1, 1066, 70))
mock_time.return_value = 1070
self.assertEqual(self._get_timer_data(), (70, 70, 1, None, 70))
[docs]class TestNumericTraitOperators(BaseEvenniaTestCase):
"""Test case for numeric magic method implementations."""
[docs] def setUp(self):
# direct instantiation for testing only; use TraitHandler in production
self.st = traits.Trait(
{
"name": "Strength",
"trait_type": "trait",
"value": 8,
}
)
self.at = traits.Trait(
{
"name": "Attack",
"trait_type": "trait",
"value": 4,
}
)
[docs] def tearDown(self):
self.st, self.at = None, None
[docs] def test_pos_shortcut(self):
"""overridden unary + operator returns `value` property"""
self.assertIn(type(+self.st), (float, int))
self.assertEqual(+self.st, self.st.value)
self.assertEqual(+self.st, 8)
[docs] def test_add_traits(self):
"""test addition of `Trait` objects"""
# two Trait objects
self.assertEqual(self.st + self.at, 12)
# Trait and numeric
self.assertEqual(self.st + 1, 9)
self.assertEqual(1 + self.st, 9)
[docs] def test_sub_traits(self):
"""test subtraction of `Trait` objects"""
# two Trait objects
self.assertEqual(self.st - self.at, 4)
# Trait and numeric
self.assertEqual(self.st - 1, 7)
self.assertEqual(10 - self.st, 2)
[docs] def test_mul_traits(self):
"""test multiplication of `Trait` objects"""
# between two Traits
self.assertEqual(self.st * self.at, 32)
# between Trait and numeric
self.assertEqual(self.at * 4, 16)
self.assertEqual(4 * self.at, 16)
[docs] def test_floordiv(self):
"""test floor division of `Trait` objects"""
# between two Traits
self.assertEqual(self.st // self.at, 2)
# between Trait and numeric
self.assertEqual(self.st // 2, 4)
self.assertEqual(18 // self.st, 2)
[docs] def test_comparisons_traits(self):
"""test equality comparison between `Trait` objects"""
self.assertNotEqual(self.st, self.at)
self.assertLess(self.at, self.st)
self.assertLessEqual(self.at, self.st)
self.assertGreater(self.st, self.at)
self.assertGreaterEqual(self.st, self.at)
[docs] def test_comparisons_numeric(self):
"""equality comparisons between `Trait` and numeric"""
self.assertEqual(self.st, 8)
self.assertEqual(8, self.st)
self.assertNotEqual(self.st, 0)
self.assertNotEqual(0, self.st)
self.assertLess(self.st, 10)
self.assertLess(0, self.st)
self.assertLessEqual(self.st, 8)
self.assertLessEqual(8, self.st)
self.assertLessEqual(self.st, 10)
self.assertLessEqual(0, self.st)
self.assertGreater(self.st, 0)
self.assertGreater(10, self.st)
self.assertGreaterEqual(self.st, 8)
self.assertGreaterEqual(8, self.st)
self.assertGreaterEqual(self.st, 0)
self.assertGreaterEqual(10, self.st)
[docs]class DummyCharacter(_MockObj):
strength = traits.TraitProperty("Strength", trait_type="static", base=10, mod=2)
hunting = traits.TraitProperty("Hunting skill", trait_type="counter", base=10, mod=1, max=100)
health = traits.TraitProperty("Health value", trait_type="gauge", base=100)
[docs]class TestTraitFields(BaseEvenniaTestCase):
"""
Test the TraitField class.
"""
[docs] @patch("evennia.contrib.rpg.traits.traits._TRAIT_CLASS_PATHS", new=_TEST_TRAIT_CLASS_PATHS)
def test_traitfields(self):
obj = DummyCharacter()
obj2 = DummyCharacter()
self.assertEqual(12, obj.strength.value)
self.assertEqual(11, obj.hunting.value)
self.assertEqual(100, obj.health.value)
obj.strength.base += 5
self.assertEqual(17, obj.strength.value)
obj.strength.berserk = True
self.assertEqual(obj.strength.berserk, True)
self.assertEqual(100, obj.traits.health)
self.assertEqual(None, obj.traits.hp)
# the traithandler still works
obj.traits.health.current -= 1
self.assertEqual(99, obj.health.value)
# making sure Descriptors are separate
self.assertEqual(12, obj2.strength.value)
self.assertEqual(17, obj.strength.value)
obj2.strength.base += 1
obj.strength.base += 3
self.assertEqual(13, obj2.strength.value)
self.assertEqual(20, obj.strength.value)
[docs]class TraitContribTestingChar(DefaultCharacter):
HP = traits.TraitProperty("health", trait_type="trait", value=5)
[docs]class TraitPropertyTestCase(EvenniaTest):
"""
Test atomic updating.
"""
character_typeclass = TraitContribTestingChar
[docs] def test_round1(self):
self.char1.HP.value = 1
[docs] def test_round2(self):
self.char1.HP.value = 2