tabletop-frog/test/test_schema.py

186 lines
6.6 KiB
Python
Raw Normal View History

import json
2024-04-20 20:35:24 -07:00
2024-03-24 16:56:13 -07:00
from ttfrog.db import schema
def test_manage_character(db, classes_factory, ancestries_factory):
2024-03-24 16:56:13 -07:00
with db.transaction():
2024-04-14 11:37:34 -07:00
# load the fixtures so they are bound to the current session
classes = classes_factory()
ancestries = ancestries_factory()
darkvision = db.AncestryTrait.filter_by(name="Darkvision")[0]
2024-03-24 16:56:13 -07:00
# create a human character (the default)
2024-03-26 00:53:21 -07:00
char = schema.Character(name="Test Character")
db.add_or_update(char)
2024-03-24 16:56:13 -07:00
assert char.id == 1
2024-03-26 00:53:21 -07:00
assert char.name == "Test Character"
assert char.ancestry.name == "human"
2024-04-21 02:17:47 -07:00
assert char.AC == 10
assert char.HP == 10
assert char.STR == 10
assert char.DEX == 10
assert char.CON == 10
assert char.INT == 10
assert char.WIS == 10
assert char.CHA == 10
2024-03-24 16:56:13 -07:00
assert darkvision not in char.traits
# switch ancestry to tiefling
2024-03-26 00:53:21 -07:00
char.ancestry = ancestries["tiefling"]
db.add_or_update(char)
2024-03-24 16:56:13 -07:00
char = db.session.get(schema.Character, 1)
2024-03-26 00:53:21 -07:00
assert char.ancestry.name == "tiefling"
2024-03-24 16:56:13 -07:00
assert darkvision in char.traits
2024-04-20 23:27:47 -07:00
# switch ancestry to dragonborn and assert darkvision persists
char.ancestry = ancestries["dragonborn"]
db.add_or_update(char)
assert darkvision in char.traits
# switch ancestry to human and assert darkvision is removed
char.ancestry = ancestries["human"]
db.add_or_update(char)
assert darkvision not in char.traits
2024-03-24 16:56:13 -07:00
# assign a class and level
2024-03-26 00:53:21 -07:00
char.add_class(classes["fighter"], level=1)
db.add_or_update(char)
2024-03-26 00:53:21 -07:00
assert char.levels == {"fighter": 1}
2024-03-24 16:56:13 -07:00
assert char.level == 1
2024-03-26 21:58:04 -07:00
assert char.class_attributes == {}
# 'fighting style' is available, but not at this level
2024-04-20 23:27:47 -07:00
fighter = classes["fighter"]
fighting_style = fighter.attributes_by_level[2]["Fighting Style"]
2024-03-26 21:58:04 -07:00
assert char.add_class_attribute(fighting_style, fighting_style.options[0]) is False
db.add_or_update(char)
2024-03-26 21:58:04 -07:00
assert char.class_attributes == {}
2024-03-24 16:56:13 -07:00
# level up
2024-03-26 00:53:21 -07:00
char.add_class(classes["fighter"], level=2)
db.add_or_update(char)
2024-03-26 00:53:21 -07:00
assert char.levels == {"fighter": 2}
2024-03-24 16:56:13 -07:00
assert char.level == 2
# Assert the fighting style is added automatically and idempotent...ly?
2024-03-26 21:58:04 -07:00
assert char.class_attributes[fighting_style.name] == fighting_style.options[0]
assert char.add_class_attribute(fighting_style, fighting_style.options[0]) is True
db.add_or_update(char)
2024-03-26 21:58:04 -07:00
# classes
2024-03-26 00:53:21 -07:00
char.add_class(classes["rogue"], level=1)
db.add_or_update(char)
2024-03-24 16:56:13 -07:00
assert char.level == 3
2024-03-26 00:53:21 -07:00
assert char.levels == {"fighter": 2, "rogue": 1}
2024-03-24 16:56:13 -07:00
# remove a class
2024-03-26 00:53:21 -07:00
char.remove_class(classes["rogue"])
db.add_or_update(char)
2024-03-26 00:53:21 -07:00
assert char.levels == {"fighter": 2}
2024-03-24 16:56:13 -07:00
assert char.level == 2
# remove remaining class by setting level to zero
char.add_class(classes["fighter"], level=0)
db.add_or_update(char)
assert char.levels == {}
2024-03-24 16:56:13 -07:00
2024-03-26 21:58:04 -07:00
# ensure we're not persisting any orphan records in the map tables
dump = json.loads(db.dump())
assert dump["class_map"] == []
2024-03-26 21:58:04 -07:00
assert dump["character_class_attribute_map"] == []
2024-04-20 23:27:47 -07:00
def test_ancestries(db):
with db.transaction():
# create the Pygmy Orc ancestry
porc = schema.Ancestry(
name="Pygmy Orc",
size="Small",
walk_speed=25,
2024-04-20 23:27:47 -07:00
)
db.add_or_update(porc)
assert porc.name == "Pygmy Orc"
assert porc.creature_type == "humanoid"
assert porc.size == "Small"
assert porc.speed == 25
# create the Relentless Endurance trait and add it to the Orc
endurance = schema.AncestryTrait(name="Relentless Endurance")
db.add_or_update(endurance)
porc.add_trait(endurance, level=1)
db.add_or_update(porc)
assert endurance in porc.traits
2024-04-21 02:17:47 -07:00
# add a +1 STR modifier
2024-04-21 21:30:24 -07:00
str_plus_one = schema.Modifier(
2024-04-21 02:17:47 -07:00
name="STR+1 (Pygmy Orc)",
target="strength",
relative_value=1,
2024-04-21 21:30:24 -07:00
description="Your Strength score is increased by 1.",
2024-04-21 02:17:47 -07:00
)
assert porc.add_modifier(str_plus_one) is True
assert porc.add_modifier(str_plus_one) is False # test idempotency
2024-04-21 21:30:24 -07:00
assert str_plus_one in porc.modifiers["strength"]
2024-04-21 02:17:47 -07:00
# now create an orc character and assert it gets traits and modifiers
2024-04-20 23:27:47 -07:00
grognak = schema.Character(name="Grognak the Mighty", ancestry=porc)
2024-04-21 02:17:47 -07:00
db.add_or_update(grognak)
2024-04-20 23:27:47 -07:00
assert endurance in grognak.traits
2024-04-21 02:17:47 -07:00
# verify the strength bonus is applied
assert grognak.strength == 10
2024-04-21 21:30:24 -07:00
assert str_plus_one in grognak.modifiers["strength"]
2024-04-21 02:17:47 -07:00
assert grognak.STR == 11
def test_modifiers(db, classes_factory, ancestries_factory):
with db.transaction():
classes_factory()
ancestries = ancestries_factory()
# no modifiers; speed is ancestry speed
carl = schema.Character(name="Carl", ancestry=ancestries["elf"])
marx = schema.Character(name="Marx", ancestry=ancestries["human"])
db.add_or_update([carl, marx])
2024-04-21 02:17:47 -07:00
assert carl.speed == carl.ancestry.speed == 30
2024-04-21 21:30:24 -07:00
cold = schema.Modifier(target="speed", relative_value=-10, name="Cold")
hasted = schema.Modifier(target="speed", multiply_value=2.0, name="Hasted")
slowed = schema.Modifier(target="speed", multiply_value=0.5, name="Slowed")
restrained = schema.Modifier(target="speed", absolute_value=0, name="Restrained")
reduced = schema.Modifier(target="size", new_value="Tiny", name="Reduced")
2024-04-21 02:17:47 -07:00
# reduce speed by 10
2024-04-21 21:30:24 -07:00
assert carl.add_modifier(cold)
2024-04-21 02:17:47 -07:00
assert carl.speed == 20
# make sure modifiers only apply to carl. Carl is having a bad day.
assert marx.speed == 30
2024-04-21 02:17:47 -07:00
# speed is doubled
2024-04-21 21:30:24 -07:00
assert carl.remove_modifier(cold)
assert carl.add_modifier(hasted)
2024-04-21 02:17:47 -07:00
assert carl.speed == 60
# speed is halved
2024-04-21 21:30:24 -07:00
assert carl.remove_modifier(hasted)
assert carl.add_modifier(slowed)
2024-04-21 02:17:47 -07:00
assert carl.speed == 15
# speed is 0
2024-04-21 21:30:24 -07:00
assert carl.add_modifier(restrained)
2024-04-21 02:17:47 -07:00
assert carl.speed == 0
# no longer restrained, but still slowed
2024-04-21 21:30:24 -07:00
assert carl.remove_modifier(restrained)
2024-04-21 02:17:47 -07:00
assert carl.speed == 15
# back to normal
2024-04-21 21:30:24 -07:00
assert carl.remove_modifier(slowed)
2024-04-21 02:17:47 -07:00
assert carl.speed == carl.ancestry.speed
# modifiers can modify string values too
2024-04-21 21:30:24 -07:00
assert carl.add_modifier(reduced)
2024-04-21 02:17:47 -07:00
assert carl.size == "Tiny"