Files
gogobee/cmd/open5e-import/desc_overrides_test.go
prosolis 3369d7d8fe gofmt: bring internal/ and cmd/ back to gofmt -l clean
Mechanical `gofmt -w ./internal ./cmd`. Mostly struct-field realignment that
had drifted, plus a few trailing-newline fixes. No behaviour change — gofmt is
semantics-preserving, and build/vet/test are green either side.

Split out from the code-review fixes that follow so those stay reviewable
instead of hiding inside a wall of realignment.
2026-07-10 07:18:07 -07:00

123 lines
3.8 KiB
Go

package main
import (
"strings"
"testing"
)
// TestCleanDescStripsJargon — the S3 acceptance criteria translated into
// regression cases. Any phrase listed here must not survive the sanitizer.
func TestCleanDescStripsJargon(t *testing.T) {
cases := []struct {
name string
in string
mustNot []string
}{
{
name: "saving throw + DC",
in: "Each creature in the area must make a Dexterity saving throw (DC 15) or take damage.",
mustNot: []string{
"saving throw", "DC 15", "DC15",
},
},
{
name: "saving throws plural",
in: "You have advantage on saving throws against spells.",
mustNot: []string{"saving throws"},
},
{
name: "within range",
in: "Hurl a bolt at a creature within range.",
mustNot: []string{"within range"},
},
{
name: "5-foot radius",
in: "Each creature in a 5-foot radius takes damage.",
mustNot: []string{"5-foot"},
},
{
name: "spell slot upcast clause",
in: "When you cast this spell using a spell slot of 2nd level or higher, the damage increases.",
mustNot: []string{"spell slot"},
},
{
name: "constitution score",
in: "Your Constitution score is 19 while you wear this amulet.",
mustNot: []string{"Constitution score"},
},
{
name: "(save DC X) parenthetical",
in: "You can use an action to cast the detect thoughts spell (save DC 13) from it.",
mustNot: []string{"(save", "DC 13"},
},
{
name: "wisdom save",
in: "Forces a wisdom save against the caster.",
mustNot: []string{"wisdom save"},
},
{
name: "out to a range of feet",
in: "You have darkvision out to a range of 60 feet.",
mustNot: []string{"feet", "out to a range"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := cleanDesc(tc.in)
low := strings.ToLower(got)
for _, ban := range tc.mustNot {
if strings.Contains(low, strings.ToLower(ban)) {
t.Errorf("cleanDesc kept banned phrase %q\n in: %q\n out: %q", ban, tc.in, got)
}
}
})
}
}
// TestCleanDescRepairsOrphans — the strippers leave dangling stubs ("must
// make.", " and."); the post-pass is meant to tidy them so player-facing
// prose doesn't end mid-clause.
func TestCleanDescRepairsOrphans(t *testing.T) {
in := "You gain a +1 bonus to ability checks and saving throws."
got := cleanDesc(in)
if strings.HasSuffix(got, " and.") {
t.Errorf("orphan trailing 'and.' survived: %q", got)
}
in2 := "Up to three creatures of your choice that you can see must make charisma saving throws."
got2 := cleanDesc(in2)
if strings.Contains(strings.ToLower(got2), "must make.") {
t.Errorf("orphan 'must make.' survived: %q", got2)
}
}
// TestStripNameParenthetical — bestiary R21 / magic-item alias names.
func TestStripNameParenthetical(t *testing.T) {
cases := map[string]string{
"Giant Rat (Diseased)": "Giant Rat",
"Deep Gnome (Svirfneblin)": "Deep Gnome",
"Stone of Good Luck (Luckstone)": "Stone of Good Luck",
"Ordinary Name": "Ordinary Name",
"": "",
}
for in, want := range cases {
if got := stripNameParenthetical(in); got != want {
t.Errorf("stripNameParenthetical(%q) = %q, want %q", in, got, want)
}
}
}
// TestSpellOverrideWins — the curated descriptions for the SRD-only default
// spells must beat the auto first-sentence path.
func TestSpellOverrideWins(t *testing.T) {
got := spellDescription("vicious_mockery", "anything could go here")
if got != spellDescOverride["vicious_mockery"] {
t.Errorf("override didn't win: got %q", got)
}
// Unknown ID falls through to cleanDesc.
in := "Hurl a bolt at a creature within range."
got = spellDescription("unknown_spell_xyz", in)
if strings.Contains(got, "within range") {
t.Errorf("fallthrough didn't sanitize: %q", got)
}
}