Added a test to check that all spells are valid rst.

This commit is contained in:
Mark Wolfman
2021-04-14 13:04:46 -05:00
parent 4aa43d2bec
commit c8577187b0
7 changed files with 133 additions and 111 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
from dungeonsheets.spells.spells import Spell, create_spell from dungeonsheets.spells.spells import Spell, create_spell, all_spells
from dungeonsheets.spells.spells_a import * from dungeonsheets.spells.spells_a import *
from dungeonsheets.spells.spells_b import * from dungeonsheets.spells.spells_b import *
from dungeonsheets.spells.spells_c import * from dungeonsheets.spells.spells_c import *
+11
View File
@@ -1,3 +1,14 @@
from dungeonsheets import spells
def all_spells():
"""Generate all the valid spell classes so far defined."""
for spell_name, spell in spells.__dict__.items():
# Check if it's (a) a class and (b) a subclass of ``Spell``
if isinstance(spell, type) and issubclass(spell, Spell):
yield spell
def create_spell(**params): def create_spell(**params):
"""Create a new subclass of ``Spell`` with given default parameters. """Create a new subclass of ``Spell`` with given default parameters.
+6 -6
View File
@@ -734,15 +734,15 @@ class AstralProjection(Spell):
class Augury(Spell): class Augury(Spell):
"""By casting gem-inlaid sticks, rolling dragon bones, laying out ornate cards, or """By casting gem-inlaid sticks, rolling dragon bones, laying out
employing some other divining tool, you receive an omen from an otherworldly ornate cards, or employing some other divining tool, you receive
entity about the results of a specific course of action that you plan to take an omen from an otherworldly entity about the results of a
within the next 30 minutes. The DM chooses from the following possible omens: specific course of action that you plan to take within the next 30
minutes. The DM chooses from the following possible omens:
- Weal, for good results - Weal, for good results
- Woe, for bad results - Woe, for bad results
- Weal and woe, for both good - Weal and woe, for both good and bad results
and bad results
- Nothing, for results that aren't especially good or bad - Nothing, for results that aren't especially good or bad
The spell doesn't take into account any possible circumstances The spell doesn't take into account any possible circumstances
+19 -18
View File
@@ -214,20 +214,22 @@ class ChainLightning(Spell):
class ChaosBolt(Spell): class ChaosBolt(Spell):
"""You hurl an undulating, warbling mass of chaotic energy at one """You hurl an undulating, warbling mass of chaotic energy at one
creature in range. Make a ranged spell attack against the creature in range. Make a ranged spell attack against the
target. On a hit, the target takes 2d8 + 1d6 damage. Choose one of target. On a hit, the target takes ``2d8+1d6`` damage. Choose one
the dSs. The number rolled on that die determines the attacks of the d8s. The number rolled on that die determines the attacks
damage type, as shown below. damage type, as shown below.
d8 / Damage Type == ===========
1 / Acid d8 Damage Type
2 == ===========
/ Cold 1 Acid
3 / Fire 2 Cold
4 / Force 3 Fire
5 / Lightning 4 Force
6 / Poison 5 Lightning
7 / Psychic 6 Poison
8 / Thunder 7 Psychic
8 Thunder
== ===========
If you roll the same number on both d8s, the chaotic energy leaps If you roll the same number on both d8s, the chaotic energy leaps
from the target to a different creature of your choice within 30 from the target to a different creature of your choice within 30
@@ -624,10 +626,8 @@ class CommuneWithNature(Spell):
about any of the following subjects as they relate to the area: about any of the following subjects as they relate to the area:
- terrain and bodies of water - terrain and bodies of water
- prevalent plants, - prevalent plants, minerals, animals, or peoples
minerals, animals, or peoples - powerful celestials, fey, fiends, elementals, or undead
- powerful celestials, fey, fiends, elementals,
or undead
- influence from other planes of existence - influence from other planes of existence
- buildings - buildings
@@ -1211,8 +1211,9 @@ class ContinualFlame(Spell):
class ControlFlames(Spell): class ControlFlames(Spell):
"""You choose a nonmagical flame that you can see within range and that fits within """You choose a nonmagical flame that you can see within range and
a 5-foot cube. You affect it in one of the following ways: that fits within a 5-foot cube. You affect it in one of the
following ways:
- You instantaneously expand the flame 5 feet in one direction, - You instantaneously expand the flame 5 feet in one direction,
provided that wood or other fuel is present in the new location. provided that wood or other fuel is present in the new location.
+21 -30
View File
@@ -456,7 +456,8 @@ class GuardianOfNature(Spell):
- You gain 10 temporary hit points. - You gain 10 temporary hit points.
- You make Constitution saving throws with advantage. - You make Constitution saving throws with advantage.
- You make Dexterity- and Wisdom-based attack rolls with advantage. - You make Dexterity- and Wisdom-based attack rolls with
advantage.
- While you are on the ground, the ground within 15 feet of you is - While you are on the ground, the ground within 15 feet of you is
difficult terrain for your enemies. difficult terrain for your enemies.
@@ -489,47 +490,39 @@ class GuardsAndWards(Spell):
Guards and wards creates the following effects within the warded Guards and wards creates the following effects within the warded
area. area.
Corridors: Fog fills all the warded corridors, making them heavily - **Corridors.** Fog fills all the warded corridors, making them
obscured. In addition, at each intersection or branching passage heavily obscured. In addition, at each intersection or branching
offering a choice of direction, there is a 50 percent chance that passage offering a choice of direction, there is a 50 percent
a creature other than you will believe it is going in the opposite chance that a creature other than you will believe it is going
direction from the one it chooses. in the opposite direction from the one it chooses.
- **Doors.** All doors in the warded area are magically locked, as
Doors: All doors in the warded area are magically locked, as if if sealed by an arcane lock spell. In addition, you can cover up
sealed by an arcane lock spell. In addition, you can cover up to to ten doors with an illusion (equivalent to the illusory object
ten doors with an illusion (equivalent to the illusory object
function of the m inor illusion spell) to make them appear as function of the m inor illusion spell) to make them appear as
plain sections of wall. plain sections of wall.
- **Stairs.** Webs fill all stairs in the warded area from top to
Stairs: Webs fill all stairs in the warded area from top to
bottom, as the web spell. These strands regrow in 10 minutes if bottom, as the web spell. These strands regrow in 10 minutes if
they are burned or torn away while guards and wards lasts. they are burned or torn away while guards and wards lasts.
- **Other Spell Effect.** You can place your choice of one of the
Other Spell Effect: You can place your choice of one of the
following magical effects within the warded area of the following magical effects within the warded area of the
stronghold. stronghold.
- Place dancing lights in four corridors. You can designate a - Place dancing lights in four corridors. You can designate a
simple program that the lights repeat as long as guards and simple program that the lights repeat as long as guards and
wards lasts. wards lasts.
- Place magic mouth in two locations. - Place magic mouth in two locations.
- Place stinking cloud in two locations. The vapors appear in
- Place stinking cloud in two locations. The vapors appear in the the places you designate; they return within 10 minutes if
places you designate; they return within 10 minutes if dispersed dispersed by wind while guards and wards lasts.
by wind while guards and wards lasts.
- Place a constant gust of wind in one corridor or room. - Place a constant gust of wind in one corridor or room.
- Place a suggestion in one location. You select an area of up
- Place a suggestion in one location. You select an area of up to to 5 feet square, and any creature that enters or passes
5 feet square, and any creature that enters or passes through through the area receives the suggestion mentally.
the area receives the suggestion mentally.
The whole warded area radiates magic. A dispel magic cast on a The whole warded area radiates magic. A dispel magic cast on a
specific effect, if successful, removes only that effect. specific effect, if successful, removes only that effect. You can
create a permanently guarded and warded structure by casting this
You can create a permanently guarded and warded structure by spell there every day for one year.
casting this spell there every day for one year.
""" """
name = "Guards And Wards" name = "Guards And Wards"
@@ -622,12 +615,10 @@ class Gust(Spell):
- One Medium or smaller creature that you choose must succeed on a - One Medium or smaller creature that you choose must succeed on a
Strength saving throw or be pushed up to 5 feet away from you. Strength saving throw or be pushed up to 5 feet away from you.
- You create a small blast of air capable of moving one object - You create a small blast of air capable of moving one object
that is neither held nor carried and that weighs no more than 5 that is neither held nor carried and that weighs no more than 5
pounds. The object is pushed up to 10 feet away from you. It pounds. The object is pushed up to 10 feet away from you. It
isn't pushed with enough force to cause damage. isn't pushed with enough force to cause damage.
- You create a harmless sensory affect using air, such as causing - You create a harmless sensory affect using air, such as causing
leaves to rustle, wind to slam shutters shut, or your clothing leaves to rustle, wind to slam shutters shut, or your clothing
to ripple in a breeze. to ripple in a breeze.
+7 -1
View File
@@ -3,7 +3,7 @@ import os
from pathlib import Path from pathlib import Path
import subprocess import subprocess
from dungeonsheets import make_sheets, character from dungeonsheets import make_sheets, character, spells
EG_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], '../examples/')) EG_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], '../examples/'))
CHARFILE = os.path.join(EG_DIR, 'rogue1.py') CHARFILE = os.path.join(EG_DIR, 'rogue1.py')
@@ -136,3 +136,9 @@ class MarkdownTestCase(unittest.TestCase):
self.assertNotIn("endfoot", tex) self.assertNotIn("endfoot", tex)
self.assertNotIn("endhead", tex) self.assertNotIn("endhead", tex)
self.assertNotIn("endfirsthead", tex) self.assertNotIn("endfirsthead", tex)
def test_rst_all_spells(self):
for spell in spells.all_spells():
tex = make_sheets.rst_to_latex(spell.__doc__)
self.assertNotIn("DUadmonition", tex,
f"spell {spell} is not valid reStructured text")
+13 -1
View File
@@ -2,11 +2,23 @@
from unittest import TestCase from unittest import TestCase
from dungeonsheets.spells import create_spell, Spell from dungeonsheets import spells
from dungeonsheets.spells import create_spell, Spell, all_spells
class TestSpells(TestCase): class TestSpells(TestCase):
"""Tests for spells and spell-related activities.""" """Tests for spells and spell-related activities."""
def test_all_spells(self):
# Make sure only spells are returned
for ThisSpell in all_spells():
self.assertTrue(isinstance(ThisSpell, type),
f"``all_spells`` returned {ThisSpell} (not a class)")
self.assertTrue(issubclass(ThisSpell, Spell),
f"``all_spells`` returned {ThisSpell} (not a spell)")
# Pick a couple of known spells to spot-check for
all_the_spells = list(all_spells())
self.assertIn(spells.MagicMissile, all_the_spells)
self.assertIn(spells.Thunderwave, all_the_spells)
def test_create_spell(self): def test_create_spell(self):
NewSpell = create_spell(name="Hello world") NewSpell = create_spell(name="Hello world")