Add Container class with capacity and open/closed state
This commit is contained in:
parent
05a739da74
commit
621c42b833
2 changed files with 163 additions and 0 deletions
29
src/mudlib/container.py
Normal file
29
src/mudlib/container.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"""Container — a Thing that can hold other Things."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from mudlib.object import Object
|
||||
from mudlib.thing import Thing
|
||||
|
||||
|
||||
@dataclass
|
||||
class Container(Thing):
|
||||
"""A container that can hold other items.
|
||||
|
||||
Containers are Things with capacity limits and open/closed state.
|
||||
The locked flag is for command-layer logic (unlock/lock commands).
|
||||
"""
|
||||
|
||||
capacity: int = 10
|
||||
closed: bool = False
|
||||
locked: bool = False
|
||||
|
||||
def can_accept(self, obj: Object) -> bool:
|
||||
"""Accept Things when open and below capacity."""
|
||||
if not isinstance(obj, Thing):
|
||||
return False
|
||||
if self.closed:
|
||||
return False
|
||||
return len(self._contents) < self.capacity
|
||||
134
tests/test_container.py
Normal file
134
tests/test_container.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
"""Tests for the Container class."""
|
||||
|
||||
from mudlib.container import Container
|
||||
from mudlib.object import Object
|
||||
from mudlib.thing import Thing
|
||||
from mudlib.zone import Zone
|
||||
|
||||
# --- construction ---
|
||||
|
||||
|
||||
def test_container_creation_minimal():
|
||||
"""Container can be created with just a name."""
|
||||
c = Container(name="chest")
|
||||
assert c.name == "chest"
|
||||
assert c.capacity == 10
|
||||
assert c.closed is False
|
||||
assert c.locked is False
|
||||
|
||||
|
||||
def test_container_creation_with_custom_capacity():
|
||||
"""Container can have a custom capacity."""
|
||||
c = Container(name="pouch", capacity=5)
|
||||
assert c.capacity == 5
|
||||
|
||||
|
||||
def test_container_creation_closed():
|
||||
"""Container can be created in closed state."""
|
||||
c = Container(name="chest", closed=True)
|
||||
assert c.closed is True
|
||||
|
||||
|
||||
def test_container_creation_locked():
|
||||
"""Container can be created in locked state."""
|
||||
c = Container(name="chest", locked=True)
|
||||
assert c.locked is True
|
||||
|
||||
|
||||
def test_container_is_thing_subclass():
|
||||
"""Container is a Thing subclass."""
|
||||
c = Container(name="chest")
|
||||
assert isinstance(c, Thing)
|
||||
assert isinstance(c, Object)
|
||||
|
||||
|
||||
def test_container_inherits_thing_properties():
|
||||
"""Container has all Thing properties."""
|
||||
c = Container(
|
||||
name="ornate chest",
|
||||
description="a beautifully carved wooden chest",
|
||||
portable=False,
|
||||
aliases=["chest", "box"],
|
||||
)
|
||||
assert c.description == "a beautifully carved wooden chest"
|
||||
assert c.portable is False
|
||||
assert c.aliases == ["chest", "box"]
|
||||
|
||||
|
||||
# --- can_accept ---
|
||||
|
||||
|
||||
def test_container_accepts_thing_when_open():
|
||||
"""Container accepts Things when open and has capacity."""
|
||||
c = Container(name="chest")
|
||||
sword = Thing(name="sword")
|
||||
assert c.can_accept(sword) is True
|
||||
|
||||
|
||||
def test_container_rejects_when_closed():
|
||||
"""Container rejects Things when closed."""
|
||||
c = Container(name="chest", closed=True)
|
||||
sword = Thing(name="sword")
|
||||
assert c.can_accept(sword) is False
|
||||
|
||||
|
||||
def test_container_rejects_when_at_capacity():
|
||||
"""Container rejects Things when at capacity."""
|
||||
c = Container(name="pouch", capacity=2)
|
||||
# Add two items
|
||||
Thing(name="rock1", location=c)
|
||||
Thing(name="rock2", location=c)
|
||||
# Third should be rejected
|
||||
rock3 = Thing(name="rock3")
|
||||
assert c.can_accept(rock3) is False
|
||||
|
||||
|
||||
def test_container_accepts_when_below_capacity():
|
||||
"""Container accepts Things when below capacity."""
|
||||
c = Container(name="pouch", capacity=2)
|
||||
Thing(name="rock1", location=c)
|
||||
# Second item should be accepted
|
||||
rock2 = Thing(name="rock2")
|
||||
assert c.can_accept(rock2) is True
|
||||
|
||||
|
||||
def test_container_rejects_non_thing():
|
||||
"""Container rejects objects that aren't Things."""
|
||||
c = Container(name="chest")
|
||||
other = Object(name="abstract")
|
||||
assert c.can_accept(other) is False
|
||||
|
||||
|
||||
def test_container_locked_is_just_flag():
|
||||
"""Locked flag is stored but doesn't affect can_accept (used by commands)."""
|
||||
c = Container(name="chest", locked=True, closed=False)
|
||||
sword = Thing(name="sword")
|
||||
# can_accept doesn't check locked (commands will check it separately)
|
||||
# This test documents current behavior — locked is for command layer
|
||||
assert c.locked is True
|
||||
# can_accept only checks closed and capacity
|
||||
assert c.can_accept(sword) is True
|
||||
|
||||
|
||||
# --- integration with zones ---
|
||||
|
||||
|
||||
def test_container_in_zone():
|
||||
"""Container can be placed in a zone with coordinates."""
|
||||
terrain = [["." for _ in range(10)] for _ in range(10)]
|
||||
zone = Zone(name="test", width=10, height=10, terrain=terrain)
|
||||
chest = Container(name="chest", location=zone, x=5, y=5)
|
||||
assert chest.location is zone
|
||||
assert chest.x == 5
|
||||
assert chest.y == 5
|
||||
assert chest in zone.contents
|
||||
|
||||
|
||||
def test_container_with_contents():
|
||||
"""Container can hold Things."""
|
||||
chest = Container(name="chest")
|
||||
sword = Thing(name="sword", location=chest)
|
||||
gem = Thing(name="gem", location=chest)
|
||||
assert sword in chest.contents
|
||||
assert gem in chest.contents
|
||||
assert len(chest.contents) == 2
|
||||
Loading…
Reference in a new issue