Phase 5: scaffold Crucible (sow-tools) — dispatcher + builder shims, container, PR-first CI, fail-closed (D11, D19).
This commit is contained in:
@@ -1,611 +0,0 @@
|
||||
package topdata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRunConvertCommandInfersTemplateNamespaceAndOutput(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "appearance", "modules"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
tables:
|
||||
template_appearance:
|
||||
namespace: appearance
|
||||
key_fields:
|
||||
- LABEL
|
||||
`)
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "template_appearance.2da"), "2DA V2.0\n\nLABEL STRING_REF NAME\n960 \"Zombie, Ash, Hot\" **** Zombie_Ash_Hot\n961 \"Zombie, Ash, Done\" **** Zombie_Ash_Done\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
var stdout bytes.Buffer
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-module",
|
||||
"--name", "ashzombies",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
}, &stdout); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "topdata", "data", "appearance", "modules", "add_appearance_ashzombies.json")
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
text := string(raw)
|
||||
if !strings.Contains(text, `"appearance:zombie_ash_hot"`) || !strings.Contains(text, `"appearance:zombie_ash_done"`) {
|
||||
t.Fatalf("unexpected output:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(stdout.String(), "converted entries: 2") {
|
||||
t.Fatalf("unexpected stdout: %s", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommandInfersOverrideOutputPrefixFromTemplateConfig(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
module_output:
|
||||
filename_prefixes:
|
||||
entries: add
|
||||
override: ovr
|
||||
tables:
|
||||
template_appearance:
|
||||
namespace: appearance
|
||||
key_fields:
|
||||
- LABEL
|
||||
`)
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "template_appearance.2da"), "2DA V2.0\n\nLABEL STRING_REF NAME\n960 \"Zombie, Ash, Hot\" **** Zombie_Ash_Hot\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
var stdout bytes.Buffer
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-module",
|
||||
"--type", "override",
|
||||
"--name", "ashzombies",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
}, &stdout); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "topdata", "data", "appearance", "modules", "ovr_appearance_ashzombies.json")
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(raw), `"overrides"`) {
|
||||
t.Fatalf("expected override payload, got:\n%s", string(raw))
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(root, "topdata", "data", "appearance", "modules", "add_appearance_ashzombies.json")); !os.IsNotExist(err) {
|
||||
t.Fatalf("expected add-prefixed output to be absent, stat err: %v", err)
|
||||
}
|
||||
if !strings.Contains(stdout.String(), "converted overrides: 1") {
|
||||
t.Fatalf("unexpected stdout: %s", stdout.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommand2DAToJSONInfersTemplateKeys(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
tables:
|
||||
template_appearance:
|
||||
namespace: appearance
|
||||
key_fields:
|
||||
- LABEL
|
||||
`)
|
||||
inputPath := filepath.Join(root, "topdata", "templates", "template_appearance.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nLABEL STRING_REF NAME\n960 \"Zombie, Ash, Hot\" **** Zombie_Ash_Hot\n961 \"Zombie, Ash, Done\" **** Zombie_Ash_Done\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "out", "appearance.json")
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-json",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
outputPath,
|
||||
}, &bytes.Buffer{}); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
var payload struct {
|
||||
Rows []map[string]any `json:"rows"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
t.Fatalf("unmarshal output: %v", err)
|
||||
}
|
||||
if got := payload.Rows[0]["key"]; got != "appearance:zombie_ash_hot" {
|
||||
t.Fatalf("expected first key to be inferred from template config, got %#v", got)
|
||||
}
|
||||
if got := payload.Rows[1]["key"]; got != "appearance:zombie_ash_done" {
|
||||
t.Fatalf("expected second key to be inferred from template config, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommand2DAToJSONInfersOutputDatasetKeysFromConfig(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "soundset"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
tables:
|
||||
template_soundset:
|
||||
namespace: soundset
|
||||
key_fields:
|
||||
- RESREF
|
||||
- LABEL
|
||||
`)
|
||||
inputPath := filepath.Join(root, "scratch_soundset.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nLABEL RESREF STRREF GENDER TYPE\n0 \"Bandit Male\" nw_bandit 100 1 4\n1 \"Bandit Female\" nw_bandit 101 2 4\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "topdata", "data", "soundset", "base.json")
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-json",
|
||||
"scratch_soundset.2da",
|
||||
outputPath,
|
||||
}, &bytes.Buffer{}); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
var payload struct {
|
||||
Rows []map[string]any `json:"rows"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
t.Fatalf("unmarshal output: %v", err)
|
||||
}
|
||||
if got := payload.Rows[0]["key"]; got != "soundset:nw_bandit" {
|
||||
t.Fatalf("expected first soundset key, got %#v", got)
|
||||
}
|
||||
if got := payload.Rows[1]["key"]; got != "soundset:nw_bandit_bandit_female" {
|
||||
t.Fatalf("expected second soundset key to use config disambiguation, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommand2DAToJSONInfersAmbientTemplateKeysFromResource(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
tables:
|
||||
template_ambientmusic:
|
||||
namespace: ambientmusic
|
||||
key_fields:
|
||||
- Resource
|
||||
`)
|
||||
inputPath := filepath.Join(root, "topdata", "templates", "template_ambientmusic.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nDescription DisplayName Resource Stinger1 Stinger2 Stinger3\n0 61901 **** **** **** **** ****\n1 61842 **** mus_ruralday1 **** **** ****\n2 61843 **** mus_ruralday2 **** **** ****\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "out", "ambientmusic.json")
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-json",
|
||||
"topdata/templates/template_ambientmusic.2da",
|
||||
outputPath,
|
||||
}, &bytes.Buffer{}); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
var payload struct {
|
||||
Rows []map[string]any `json:"rows"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
t.Fatalf("unmarshal output: %v", err)
|
||||
}
|
||||
if _, ok := payload.Rows[0]["key"]; ok {
|
||||
t.Fatalf("expected null Resource row to remain unkeyed, got %#v", payload.Rows[0]["key"])
|
||||
}
|
||||
if got := payload.Rows[1]["key"]; got != "ambientmusic:mus_ruralday1" {
|
||||
t.Fatalf("expected first populated resource row key, got %#v", got)
|
||||
}
|
||||
if got := payload.Rows[2]["key"]; got != "ambientmusic:mus_ruralday2" {
|
||||
t.Fatalf("expected second populated resource row key, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommand2DAToJSONSuffixesDuplicateGeneratedKeys(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
inputPath := filepath.Join(root, "dup.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nResource\n1 cmp_reserved\n2 cmp_reserved\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "out", "ambientmusic.json")
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-json",
|
||||
"--namespace", "ambientmusic",
|
||||
"--key-field", "Resource",
|
||||
inputPath,
|
||||
outputPath,
|
||||
}, &bytes.Buffer{}); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
var payload struct {
|
||||
Rows []map[string]any `json:"rows"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &payload); err != nil {
|
||||
t.Fatalf("unmarshal output: %v", err)
|
||||
}
|
||||
if got := payload.Rows[0]["key"]; got != "ambientmusic:cmp_reserved" {
|
||||
t.Fatalf("expected first duplicate key to remain unsuffixed, got %#v", got)
|
||||
}
|
||||
if got := payload.Rows[1]["key"]; got != "ambientmusic:cmp_reserved_2" {
|
||||
t.Fatalf("expected second duplicate key to gain row-id suffix, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseConvertArgsSupportsEqualsSyntax(t *testing.T) {
|
||||
opts, input, output, err := parseConvertArgs([]string{
|
||||
"--namespace=environment",
|
||||
"--name=projectq",
|
||||
"--type=entries",
|
||||
"--collision=suffix",
|
||||
"--key-field=Label",
|
||||
"input.2da",
|
||||
"output.json",
|
||||
}, true, "error")
|
||||
if err != nil {
|
||||
t.Fatalf("parseConvertArgs failed: %v", err)
|
||||
}
|
||||
if opts.Namespace != "environment" {
|
||||
t.Fatalf("expected namespace from equals syntax, got %q", opts.Namespace)
|
||||
}
|
||||
if opts.Name != "projectq" {
|
||||
t.Fatalf("expected name from equals syntax, got %q", opts.Name)
|
||||
}
|
||||
if opts.Type != "entries" {
|
||||
t.Fatalf("expected type from equals syntax, got %q", opts.Type)
|
||||
}
|
||||
if opts.CollisionMode != "suffix" {
|
||||
t.Fatalf("expected collision from equals syntax, got %q", opts.CollisionMode)
|
||||
}
|
||||
if len(opts.KeyFields) != 1 || opts.KeyFields[0] != "Label" {
|
||||
t.Fatalf("expected key field from equals syntax, got %#v", opts.KeyFields)
|
||||
}
|
||||
if input != "input.2da" || output != "output.json" {
|
||||
t.Fatalf("unexpected positional parse result: input=%q output=%q", input, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert2DAToJSONSkipsConfiguredKeysWhenAnyKeyFieldIsNull(t *testing.T) {
|
||||
result, err := convert2DAToJSON(parsed2DA{
|
||||
Columns: []string{"LABEL", "RESREF", "STRREF"},
|
||||
Rows: []map[string]any{
|
||||
{"id": 309, "LABEL": "Unused", "RESREF": "unused", "STRREF": 1},
|
||||
{"id": 310, "LABEL": nullValue, "RESREF": "unused", "STRREF": 2},
|
||||
},
|
||||
}, "topdata/data/soundset/base.json", convertOptions{
|
||||
Namespace: "soundset",
|
||||
KeyFields: []string{"RESREF", "LABEL"},
|
||||
CollisionMode: "error",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("convert2DAToJSON failed: %v", err)
|
||||
}
|
||||
|
||||
rows := result["rows"].([]map[string]any)
|
||||
if got := rows[0]["key"]; got != "soundset:unused" {
|
||||
t.Fatalf("expected first row key to use the primary configured key field, got %#v", got)
|
||||
}
|
||||
if _, ok := rows[1]["key"]; ok {
|
||||
t.Fatalf("expected second row to remain unkeyed when one configured key field is null, got %#v", rows[1]["key"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommandFailsOnUnkeyedRows(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.json"), `{
|
||||
"module": {"name": "Test", "resref": "test"},
|
||||
"paths": {"source": "src", "assets": "assets", "build": "build"},
|
||||
"topdata": {"source": "topdata", "build": "build/topdata"}
|
||||
}`+"\n")
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
tables:
|
||||
template_appearance:
|
||||
namespace: appearance
|
||||
key_fields:
|
||||
- STRING_REF
|
||||
`)
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "template_appearance.2da"), "2DA V2.0\n\nLABEL STRING_REF NAME\n960 \"Zombie, Ash, Hot\" **** Zombie_Ash_Hot\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
err = RunConvertCommand([]string{
|
||||
"2da-to-module",
|
||||
"--name", "ashzombies",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
}, &bytes.Buffer{})
|
||||
if err == nil || !strings.Contains(err.Error(), "unable to generate keys for row ids 960") {
|
||||
t.Fatalf("expected unkeyed row failure, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommandFallsBackToLegacyTemplateJSONConfig(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.json"), `{
|
||||
"tables": {
|
||||
"template_appearance": {
|
||||
"namespace": "appearance",
|
||||
"key_fields": ["LABEL"]
|
||||
}
|
||||
}
|
||||
}`+"\n")
|
||||
inputPath := filepath.Join(root, "topdata", "templates", "template_appearance.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nLABEL\n960 Zombie_Ash_Hot\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(root, "out", "appearance.json")
|
||||
if err := RunConvertCommand([]string{
|
||||
"2da-to-json",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
outputPath,
|
||||
}, &bytes.Buffer{}); err != nil {
|
||||
t.Fatalf("RunConvertCommand failed: %v", err)
|
||||
}
|
||||
|
||||
raw, err := os.ReadFile(outputPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read output: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(raw), `"appearance:zombie_ash_hot"`) {
|
||||
t.Fatalf("expected legacy JSON template config fallback to be honored, got %s", string(raw))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConvertCommandRejectsUnknownTemplateFilenamePrefixType(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
writeFile(t, filepath.Join(root, "nwn-tool.yaml"), `
|
||||
module:
|
||||
name: Test
|
||||
resref: test
|
||||
paths:
|
||||
source: src
|
||||
assets: assets
|
||||
build: build
|
||||
topdata:
|
||||
source: topdata
|
||||
build: build/topdata
|
||||
`)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "templates"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "config.yaml"), `
|
||||
module_output:
|
||||
filename_prefixes:
|
||||
additions: add
|
||||
tables:
|
||||
template_appearance:
|
||||
namespace: appearance
|
||||
key_fields:
|
||||
- LABEL
|
||||
`)
|
||||
writeFile(t, filepath.Join(root, "topdata", "templates", "template_appearance.2da"), "2DA V2.0\n\nLABEL\n960 Zombie_Ash_Hot\n")
|
||||
|
||||
oldCwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("getwd: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = os.Chdir(oldCwd)
|
||||
})
|
||||
if err := os.Chdir(root); err != nil {
|
||||
t.Fatalf("chdir: %v", err)
|
||||
}
|
||||
|
||||
err = RunConvertCommand([]string{
|
||||
"2da-to-module",
|
||||
"--name", "ashzombies",
|
||||
"topdata/templates/template_appearance.2da",
|
||||
}, &bytes.Buffer{})
|
||||
if err == nil || !strings.Contains(err.Error(), `unsupported module_output.filename_prefixes key "additions"`) {
|
||||
t.Fatalf("expected invalid filename prefix type error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert2DAToModuleFailsOnDuplicateGeneratedKeysByDefault(t *testing.T) {
|
||||
_, err := convert2DAToModule(parsed2DA{
|
||||
Columns: []string{"LABEL"},
|
||||
Rows: []map[string]any{
|
||||
{"id": 1, "LABEL": "Zombie"},
|
||||
{"id": 2, "LABEL": "Zombie"},
|
||||
},
|
||||
}, "topdata/data/appearance/modules/add_appearance_ashzombies.json", convertOptions{
|
||||
Namespace: "appearance",
|
||||
CollisionMode: "error",
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), `duplicate generated key "appearance:zombie"`) {
|
||||
t.Fatalf("expected duplicate generated key error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse2DAFileRejectsRowsWithTooManyFields(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
inputPath := filepath.Join(root, "bad.2da")
|
||||
writeFile(t, inputPath, "2DA V2.0\n\nLABEL NAME\n0 one two three\n")
|
||||
|
||||
_, err := parse2DAFile(inputPath)
|
||||
if err == nil || !strings.Contains(err.Error(), "has 3 values but only 2 columns are declared") {
|
||||
t.Fatalf("expected row width error, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user