Global json adjustments
This commit is contained in:
@@ -180,6 +180,69 @@ func TestValidateProjectRejectsInvalidModuleColumnExpansionFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProjectRejectsInvalidGlobalJSONDefaults(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "spells"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "base.json"), `{
|
||||
"output": "spells.2da",
|
||||
"columns": ["Label", "ImpactScript"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "lock.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "global.json"), `{
|
||||
"defaults": [
|
||||
{"match": {"source": "entries"}, "values": {"ImpactScript": {"format": "ss_{missing}"}}},
|
||||
{"match": {"source": "unknown"}, "values": {"ImpactScript": "x"}},
|
||||
{"match": {"source": "entries", "extra": "bad"}, "values": {"ImpactScript": "x"}},
|
||||
{"match": {"source": "entries"}, "values": {"NotAColumn": "x"}},
|
||||
{"match": {"source": "entries"}}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
report := ValidateProject(testProject(root))
|
||||
if !report.HasErrors() {
|
||||
t.Fatal("expected invalid global defaults to fail validation")
|
||||
}
|
||||
text := diagnosticsText(report.Diagnostics)
|
||||
for _, want := range []string{
|
||||
"default 0 values.ImpactScript format token {missing} is not supported",
|
||||
"default 1 match.source is not supported",
|
||||
"default 2 match.extra is not supported",
|
||||
"default 3 values.NotAColumn is not a known column",
|
||||
"default 4 values is required",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("expected diagnostic %q, got:\n%s", want, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProjectRejectsGlobalJSONDefaultsWithoutBaseDataset(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "classes", "skills"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "classes", "skills", "global.json"), `{
|
||||
"defaults": [
|
||||
{"match": "all", "values": {"ClassSkill": 1}}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "classes", "skills", "fighter.json"), `{
|
||||
"columns": ["SkillLabel", "ClassSkill"],
|
||||
"rows": [
|
||||
{"id": 0, "SkillLabel": "Concentration", "ClassSkill": 1}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
report := ValidateProject(testProject(root))
|
||||
if !report.HasErrors() {
|
||||
t.Fatal("expected global defaults without a base dataset to fail validation")
|
||||
}
|
||||
if !diagnosticsContain(report.Diagnostics, "global defaults require a sibling base.json dataset") {
|
||||
t.Fatalf("expected unsupported defaults diagnostic, got:\n%s", diagnosticsText(report.Diagnostics))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeEncodesConfiguredPackedHexLists(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "modules"))
|
||||
@@ -678,6 +741,54 @@ func TestBuildNativeAppliesConfiguredValueDefaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeGlobalJSONDefaultsReplaceConfiguredValueDefaults(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "racialtypes", "core"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "base.json"), `{
|
||||
"output": "racialtypes.2da",
|
||||
"columns": ["Label", "ECL", "DefaultScale"],
|
||||
"rows": [
|
||||
{"id": 6, "key": "racialtypes:human", "Label": "Human"},
|
||||
{"id": 7, "key": "racialtypes:elf", "Label": "Elf", "ECL": null, "DefaultScale": null},
|
||||
{"id": 8, "key": "racialtypes:drow", "Label": "Drow", "ECL": 2, "DefaultScale": "0.95"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "lock.json"), `{"racialtypes:human":6,"racialtypes:elf":7,"racialtypes:drow":8}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "global.json"), `{
|
||||
"defaults": [
|
||||
{
|
||||
"match": "all",
|
||||
"values": {
|
||||
"ECL": 0,
|
||||
"DefaultScale": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNativeWithOptions failed: %v", err)
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(result.Output2DADir, "racialtypes.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read racialtypes.2da: %v", err)
|
||||
}
|
||||
got := string(raw)
|
||||
for _, want := range []string{
|
||||
"6\tHuman\t0\t1\n",
|
||||
"7\tElf\t0\t1\n",
|
||||
"8\tDrow\t2\t0.95\n",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("expected racialtypes.2da to contain %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProjectRejectsInvalidConfiguredPackedHexList(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "modules"))
|
||||
@@ -11754,6 +11865,58 @@ func TestBuildSupportsCanonicalSpells(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCanonicalSpellsImpactScriptsComeFromGlobalDefaults(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "spells", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "base.json"), `{
|
||||
"output": "spells.2da",
|
||||
"columns": ["Label", "ImpactScript"],
|
||||
"rows": [
|
||||
{"id": 0, "key": "spells:acid_fog", "Label": "AcidFog", "ImpactScript": "NW_S0_AcidFog"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "lock.json"), `{
|
||||
"spells:acid_fog": 0,
|
||||
"spells:special_attacks": 840
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "modules", "specialattacks.json"), `{
|
||||
"entries": {
|
||||
"spells:special_attacks": {
|
||||
"Label": "SpecialAttacks"
|
||||
}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "global.json"), `{
|
||||
"defaults": [
|
||||
{
|
||||
"match": {"source": "entries"},
|
||||
"values": {
|
||||
"ImpactScript": {"format": "ss_{id}"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(result.Output2DADir, "spells.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read spells.2da: %v", err)
|
||||
}
|
||||
text := string(raw)
|
||||
if !strings.Contains(text, "0\tAcidFog\tNW_S0_AcidFog\n") {
|
||||
t.Fatalf("expected base ImpactScript to be preserved, got:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "840\tSpecialAttacks\tss_840\n") {
|
||||
t.Fatalf("expected global default generated ImpactScript, got:\n%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCanonicalSpellsMatchesReference(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data"))
|
||||
@@ -14019,6 +14182,232 @@ func TestBuildNativeAppliesGlobalJSONAllOverrideToBaseDataset(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeAppliesGlobalJSONDefaultsToEntryRows(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "spells", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "base.json"), `{
|
||||
"output": "spells.2da",
|
||||
"columns": ["Label", "ImpactScript"],
|
||||
"rows": [
|
||||
{"id": 0, "key": "spells:base_missing", "Label": "BaseMissing"},
|
||||
{"id": 1, "key": "spells:base_null", "Label": "BaseNull", "ImpactScript": null}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "lock.json"), `{
|
||||
"spells:base_missing": 0,
|
||||
"spells:base_null": 1,
|
||||
"spells:new_missing": 10,
|
||||
"spells:new_null": 11,
|
||||
"spells:new_stars": 12,
|
||||
"spells:new_empty": 13,
|
||||
"spells:new_explicit": 14
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "modules", "new.json"), `{
|
||||
"entries": {
|
||||
"spells:new_missing": {"Label": "NewMissing"},
|
||||
"spells:new_null": {"Label": "NewNull", "ImpactScript": null},
|
||||
"spells:new_stars": {"Label": "NewStars", "ImpactScript": "****"},
|
||||
"spells:new_empty": {"Label": "NewEmpty", "ImpactScript": ""},
|
||||
"spells:new_explicit": {"Label": "NewExplicit", "ImpactScript": "custom_spell_script"}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "global.json"), `{
|
||||
"defaults": [
|
||||
{
|
||||
"match": {"source": "entries"},
|
||||
"values": {
|
||||
"ImpactScript": {"format": "ss_{id}"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
|
||||
got, err := os.ReadFile(filepath.Join(result.Output2DADir, "spells.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read spells.2da: %v", err)
|
||||
}
|
||||
text := string(got)
|
||||
for _, want := range []string{
|
||||
"0\tBaseMissing\t****\n",
|
||||
"1\tBaseNull\t****\n",
|
||||
"10\tNewMissing\tss_10\n",
|
||||
"11\tNewNull\tss_11\n",
|
||||
"12\tNewStars\tss_12\n",
|
||||
"13\tNewEmpty\tss_13\n",
|
||||
"14\tNewExplicit\tcustom_spell_script\n",
|
||||
} {
|
||||
if !strings.Contains(text, want) {
|
||||
t.Fatalf("expected spells.2da to contain %q, got:\n%s", want, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeGlobalJSONDefaultsUseDistinctProvenanceForDuplicateIDs(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "spells", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "base.json"), `{
|
||||
"output": "spells.2da",
|
||||
"columns": ["Label", "ImpactScript"],
|
||||
"rows": [
|
||||
{"id": 10, "key": "spells:base", "Label": "BaseDuplicate"},
|
||||
{"id": 10, "key": "spells:entry", "Label": "EntryDuplicate"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "modules", "entry.json"), `{
|
||||
"entries": {
|
||||
"spells:entry": {"Label": "EntryDuplicate"}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "global.json"), `{
|
||||
"defaults": [
|
||||
{
|
||||
"match": {"source": "entries"},
|
||||
"values": {
|
||||
"ImpactScript": {"format": "ss_{key}"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(filepath.Join(result.Output2DADir, "spells.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read spells.2da: %v", err)
|
||||
}
|
||||
got := string(raw)
|
||||
for _, want := range []string{
|
||||
"10\tBaseDuplicate\t****\n",
|
||||
"10\tEntryDuplicate\tss_spells:entry\n",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("expected spells.2da to contain %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeGlobalJSONDefaultsPreserveProvenanceForDisplacedRows(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "spells", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "base.json"), `{
|
||||
"output": "spells.2da",
|
||||
"columns": ["Label", "ImpactScript"],
|
||||
"rows": [
|
||||
{"id": 0, "key": "spells:base", "Label": "BaseMoved"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "lock.json"), `{
|
||||
"spells:base": 0,
|
||||
"spells:entry": 10
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "modules", "entry.json"), `{
|
||||
"entries": {
|
||||
"spells:entry": {"Label": "EntryDisplaced"}
|
||||
}
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "spells", "global.json"), `{
|
||||
"overrides": [
|
||||
{"id": 0, "key": "spells:entry"}
|
||||
],
|
||||
"defaults": [
|
||||
{
|
||||
"match": {"source": "entries"},
|
||||
"values": {
|
||||
"ImpactScript": "entry_default"
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(filepath.Join(result.Output2DADir, "spells.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read spells.2da: %v", err)
|
||||
}
|
||||
got := string(raw)
|
||||
for _, want := range []string{
|
||||
"0\tBaseMoved\t****\n",
|
||||
"10\tEntryDisplaced\tentry_default\n",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("expected spells.2da to contain %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeGlobalJSONDefaultsSupportLiteralAllRows(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "racialtypes", "core"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "base.json"), `{
|
||||
"output": "racialtypes.2da",
|
||||
"columns": ["Label", "ECL", "DefaultScale"],
|
||||
"rows": [
|
||||
{"id": 6, "key": "racialtypes:human", "Label": "Human"},
|
||||
{"id": 7, "key": "racialtypes:elf", "Label": "Elf", "ECL": null, "DefaultScale": null},
|
||||
{"id": 8, "key": "racialtypes:drow", "Label": "Drow", "ECL": 2, "DefaultScale": "0.95"}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "lock.json"), `{
|
||||
"racialtypes:human": 6,
|
||||
"racialtypes:elf": 7,
|
||||
"racialtypes:drow": 8
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "racialtypes", "core", "global.json"), `{
|
||||
"defaults": [
|
||||
{
|
||||
"match": "all",
|
||||
"values": {
|
||||
"ECL": 0,
|
||||
"DefaultScale": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.ReferenceBuilder = ""
|
||||
result, err := BuildNativeWithOptions(proj, NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(result.Output2DADir, "racialtypes.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read racialtypes.2da: %v", err)
|
||||
}
|
||||
got := string(raw)
|
||||
for _, want := range []string{
|
||||
"6\tHuman\t0\t1\n",
|
||||
"7\tElf\t0\t1\n",
|
||||
"8\tDrow\t2\t0.95\n",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("expected racialtypes.2da to contain %q, got:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeAppliesRecursiveGlobalJSONPlainDatasetInjections(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "classes", "skills", "baseclasses"))
|
||||
@@ -14089,6 +14478,28 @@ func TestBuildNativeAppliesRecursiveGlobalJSONPlainDatasetInjections(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeRejectsGlobalDefaultsOnPlainDataset(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "classes", "skills"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "classes", "skills", "global.json"), `{
|
||||
"defaults": [
|
||||
{"match": "all", "values": {"ClassSkill": 1}}
|
||||
]
|
||||
}`+"\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "classes", "skills", "fighter.json"), `{
|
||||
"columns": ["SkillLabel", "ClassSkill"],
|
||||
"rows": [
|
||||
{"id": 0, "SkillLabel": "Concentration", "ClassSkill": 1}
|
||||
]
|
||||
}`+"\n")
|
||||
|
||||
_, err := BuildNativeWithOptions(testProject(root), NativeBuildOptions{BuildWiki: false}, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "defaults") || !strings.Contains(err.Error(), "base.json dataset") {
|
||||
t.Fatalf("expected plain dataset defaults build error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeExtendsConfiguredPlainRowsByRepeatingLastLevel(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "classes", "spellsgained"))
|
||||
|
||||
Reference in New Issue
Block a user