Add Container class with capacity and open/closed state

This commit is contained in:
Jared Miller 2026-02-11 20:38:40 -05:00
parent 05a739da74
commit 621c42b833
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 163 additions and 0 deletions

29
src/mudlib/container.py Normal file
View 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
View 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