Wiki Template-First Rendering (#9)

Reviewed-on: https://gitea.westgate.pw/ShadowsOverWestgate/sow-tools/pulls/9
Co-authored-by: vickydotbat <vickydotbat@tutamail.com>
Co-committed-by: vickydotbat <vickydotbat@tutamail.com>
This commit is contained in:
2026-05-21 21:45:21 +02:00
committed by archvillainette
parent 6790274d95
commit 4495feb128
6 changed files with 904 additions and 12 deletions
+171
View File
@@ -268,6 +268,177 @@ func TestWikiTemplateMissingFieldFailsUnlessDefaultProvided(t *testing.T) {
}
}
func TestWikiTemplateEachBlockRendersExplicitClassProgressionTable(t *testing.T) {
ctx := &wikiContext{
wikiDataProviders: map[string]wikiDataProviderDefinition{
"ClassProgression": {Source: "class_progression", Levels: "1-2"},
},
}
page := wikiTemplatePage{
PageID: "classes:fighter",
Category: "classes",
Key: "classes:fighter",
Title: "Fighter",
Row: map[string]any{
"HitDie": "10",
"AttackBonusTable": "cls_atk_1",
},
}
template := `<table class="wiki-table wiki-class-progression">
<thead>
<tr><th>Lvl</th><th>BAB</th><th>HP</th></tr>
</thead>
<tbody>
{{#each ClassProgression}}
<tr><td>{{Level|ordinal}}</td><td>{{BAB}}</td><td>{{HPMin}}-{{HPMax}}</td></tr>
{{/each}}
</tbody>
</table>`
got, err := ctx.renderWikiTemplateString("classes.html", template, page)
if err != nil {
t.Fatalf("render template: %v", err)
}
for _, want := range []string{
`<table class="wiki-table wiki-class-progression">`,
`<tr><td>1st</td><td>+1</td><td>1-10</td></tr>`,
`<tr><td>2nd</td><td>+2</td><td>2-20</td></tr>`,
} {
if !strings.Contains(got, want) {
t.Fatalf("expected rendered output to contain %q:\n%s", want, got)
}
}
}
func TestWikiTemplateCanRenderRacialFactsAndFeatListInHTML(t *testing.T) {
ctx := &wikiContext{
wikiDataProviders: map[string]wikiDataProviderDefinition{
"RaceFeats": {Source: "race_feats"},
},
classIDToKey: map[int]string{7: "classes:paladin"},
featIDToKey: map[int]string{
10: "feat:darkvision",
11: "feat:daylight:aasimar",
},
classRows: map[string]map[string]any{
"classes:paladin": {"Name": "Paladin"},
},
featRows: map[string]map[string]any{
"feat:darkvision": {"FEAT": "Darkvision"},
"feat:daylight:aasimar": {"FEAT": "Daylight (aasimar)"},
},
visibleWikiKeys: map[string]bool{
"classes:paladin": true,
"feat:darkvision": true,
"feat:daylight:aasimar": true,
},
}
page := wikiTemplatePage{
PageID: "racialtypes:aasimar",
Category: "racialtypes",
Key: "racialtypes:aasimar",
Title: "Aasimar",
Row: map[string]any{
"WISAdjust": "2",
"CHAAdjust": "2",
"Favored": "7",
"FeatsTable": []any{"10", "11"},
},
}
template := `<table class="wiki-facts">
<tbody>
<tr><th scope="row">Ability Adjustments</th><td>{{ability_adjustments()}}</td></tr>
{{#if present(Favored)}}
<tr><th scope="row">Favored Class</th><td>{{Favored|ref:"classes"|wiki}}</td></tr>
{{/if}}
</tbody>
</table>
<ul class="wiki-race-feats">
{{#each RaceFeats}}
<li>{{FeatKey|link:FeatName|wiki}}</li>
{{/each}}
</ul>`
got, err := ctx.renderWikiTemplateString("racialtypes.html", template, page)
if err != nil {
t.Fatalf("render template: %v", err)
}
for _, want := range []string{
`<th scope="row">Ability Adjustments</th><td>+2 Wisdom, +2 Charisma</td>`,
`<th scope="row">Favored Class</th><td>[[classes/paladin|Paladin]]</td>`,
`<li>[[feat/darkvision|Darkvision]]</li>`,
`<li>[[feat/daylight-aasimar|Daylight (aasimar)]]</li>`,
} {
if !strings.Contains(got, want) {
t.Fatalf("expected rendered output to contain %q:\n%s", want, got)
}
}
}
func TestWikiTemplateDescriptionFiltersExtractParagraphsAndSections(t *testing.T) {
ctx := &wikiContext{}
page := wikiTemplatePage{
PageID: "feat:test",
Category: "feat",
Key: "feat:test",
Title: "Test Feat",
Row: map[string]any{
"DESCRIPTION": map[string]any{"tlk": map[string]any{"text": strings.Join([]string{
"Type of Feat: General",
"",
"Prerequisite: Dexterity 13+",
"",
"Specifics: You gain a +2 dodge bonus.",
"The bonus applies only while unarmored.",
"",
"Use: Automatic.",
}, "\n")}},
},
}
tests := []struct {
name string
template string
want string
reject string
}{
{
name: "first paragraph",
template: `<div>{{DESCRIPTION|text|paragraph:first}}</div>`,
want: `<div>Type of Feat: General</div>`,
reject: `Prerequisite`,
},
{
name: "specifics after marker as html",
template: `<section>{{DESCRIPTION|text|after:"Specifics:"|before:"Use:"|trim|html}}</section>`,
want: `<section><p>You gain a +2 dodge bonus.<br>The bonus applies only while unarmored.</p></section>`,
reject: `Use: Automatic`,
},
{
name: "first and last paragraphs",
template: `<div>{{DESCRIPTION|text|paragraphs:"first,last"|html}}</div>`,
want: `<div><p>Type of Feat: General</p><p>Use: Automatic.</p></div>`,
reject: `Specifics`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ctx.renderWikiTemplateString("feat.html", tt.template, page)
if err != nil {
t.Fatalf("render template: %v", err)
}
if !strings.Contains(got, tt.want) {
t.Fatalf("expected output to contain %q:\n%s", tt.want, got)
}
if tt.reject != "" && strings.Contains(got, tt.reject) {
t.Fatalf("expected output not to contain %q:\n%s", tt.reject, got)
}
})
}
}
func TestWikiTemplateRendersConfiguredClassProgressionTable(t *testing.T) {
ctx := testWikiTableContext(t, `
tables: