Available Feats Support

This commit is contained in:
2026-05-22 01:29:07 +02:00
parent afd40f0682
commit e6fdcdec87
4 changed files with 333 additions and 11 deletions
+81
View File
@@ -311,6 +311,87 @@ func TestWikiTemplateEachBlockRendersExplicitClassProgressionTable(t *testing.T)
}
}
func TestWikiTemplateClassProgressionProviderProjectsConfiguredClassFeats(t *testing.T) {
root := t.TempDir()
dataPath := filepath.Join(root, "data.yaml")
writeFile(t, dataPath, `
providers:
ClassProgression:
source: class_progression
levels: 1-4
class_feats:
fields:
GrantedFeats:
when: "{{GrantedOnLevel > 0 && List == 3}}"
AvailableFeats:
when: "{{GrantedOnLevel > 0 && List != 3}}"
`+"\n")
providers, err := loadWikiDataProviders(dataPath)
if err != nil {
t.Fatalf("load data providers: %v", err)
}
ctx := testWikiTableContext(t, "")
ctx.wikiDataPath = dataPath
ctx.wikiDataProviders = providers
ctx.featRows["feat:weapon_focus"] = map[string]any{"FEAT": map[string]any{"tlk": map[string]any{"text": "Weapon Focus"}}}
ctx.classFeatTables["classes/feats:fighter"] = wikiTable{OutputStem: "cls_feat_fight", Rows: []map[string]any{
{"FeatIndex": map[string]any{"id": "feat:literate"}, "GrantedOnLevel": "1", "List": "3"},
{"FeatIndex": map[string]any{"id": "feat:weapon_specialization"}, "GrantedOnLevel": "4", "List": "1"},
{"FeatIndex": map[string]any{"id": "feat:weapon_focus"}, "GrantedOnLevel": "4", "List": "1"},
{"FeatIndex": map[string]any{"id": "feat:weapon_proficiency_simple"}, "GrantedOnLevel": "1", "List": "3"},
}}
page := wikiTemplatePage{
PageID: "classes:fighter",
Category: "classes",
Key: "classes:fighter",
Title: "Fighter",
Row: map[string]any{
"AttackBonusTable": "cls_atk_1",
"BonusFeatsTable": map[string]any{"table": "classes/bonusfeats:fighter"},
"FeatsTable": map[string]any{"table": "classes/feats:fighter"},
},
}
got, err := ctx.renderWikiTemplateString("classes.html", `{{#each ClassProgression}}
{{Level}}|{{GrantedFeats|join:", "|wiki}}|{{AvailableFeats|join:", "|wiki}}|{{BonusFeat}}
{{/each}}`, page)
if err != nil {
t.Fatalf("render template: %v", err)
}
for _, expected := range []string{
`1|[[feat/literate|Literate]], [[feat/simple-weapon-proficiency|Simple Weapon Proficiency]]||1`,
`4||[[feat/weapon-specialization|Weapon Specialization]], [[feat/weapon-focus|Weapon Focus]]|1`,
} {
if !strings.Contains(got, expected) {
t.Fatalf("expected %q in rendered progression:\n%s", expected, got)
}
}
}
func TestWikiDataProvidersRejectEmptyClassFeatProjectionCondition(t *testing.T) {
root := t.TempDir()
dataPath := filepath.Join(root, "data.yaml")
writeFile(t, dataPath, `
providers:
ClassProgression:
source: class_progression
class_feats:
fields:
AvailableFeats:
when: ""
`+"\n")
_, err := loadWikiDataProviders(dataPath)
if err == nil {
t.Fatal("expected invalid class feat projection condition")
}
for _, expected := range []string{"data.yaml", "ClassProgression", "AvailableFeats"} {
if !strings.Contains(err.Error(), expected) {
t.Fatalf("expected error to contain %q, got %v", expected, err)
}
}
}
func TestWikiTemplateEachBlockRendersClassSkillsAsIndividualListItems(t *testing.T) {
ctx := &wikiContext{
wikiDataProviders: map[string]wikiDataProviderDefinition{