YAML Configuration Refactor

This commit is contained in:
2026-05-07 13:44:46 +02:00
parent 7abcbf1a38
commit 000d31ad24
8 changed files with 860 additions and 87 deletions
+219
View File
@@ -9,6 +9,156 @@ import (
"testing"
)
func TestLoadYAMLConfig(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, ConfigFile), `
module:
name: Test Module
resref: testmod
paths:
source: src
assets: assets
build: output
haks:
- name: core
priority: 1
max_bytes: 1024
split: false
include:
- core/**
`)
proj, err := Load(root)
if err != nil {
t.Fatalf("Load returned error: %v", err)
}
if proj.ConfigSource.Name != ConfigFile || proj.ConfigSource.Format != "yaml" || proj.ConfigSource.Legacy {
t.Fatalf("unexpected config source: %#v", proj.ConfigSource)
}
if got, want := proj.Config.Module.Name, "Test Module"; got != want {
t.Fatalf("expected module name %q, got %q", want, got)
}
if got, want := proj.BuildDir(), filepath.Join(root, "output"); got != want {
t.Fatalf("expected build dir %s, got %s", want, got)
}
}
func TestLoadYMLConfig(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, ConfigFileYML), `
module:
name: Test Module
resref: testmod
paths:
source: src
build: build
`)
proj, err := Load(root)
if err != nil {
t.Fatalf("Load returned error: %v", err)
}
if proj.ConfigSource.Name != ConfigFileYML || proj.ConfigSource.Format != "yaml" || proj.ConfigSource.Legacy {
t.Fatalf("unexpected config source: %#v", proj.ConfigSource)
}
}
func TestLoadLegacyJSONConfig(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, LegacyConfigFile), `{
"module": {
"name": "Legacy Module",
"resref": "legacy"
},
"paths": {
"source": "src",
"build": "build"
}
}`+"\n")
proj, err := Load(root)
if err != nil {
t.Fatalf("Load returned error: %v", err)
}
if proj.ConfigSource.Name != LegacyConfigFile || proj.ConfigSource.Format != "json" || !proj.ConfigSource.Legacy {
t.Fatalf("unexpected config source: %#v", proj.ConfigSource)
}
}
func TestLoadPrefersYAMLOverLegacyJSON(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, LegacyConfigFile), `{
"module": {
"name": "Legacy Module",
"resref": "legacy"
}
}`+"\n")
writeProjectFile(t, filepath.Join(root, ConfigFile), `
module:
name: YAML Module
resref: yamlmod
paths:
source: src
build: build
`)
proj, err := Load(root)
if err != nil {
t.Fatalf("Load returned error: %v", err)
}
if proj.ConfigSource.Name != ConfigFile {
t.Fatalf("expected YAML config to win, got %#v", proj.ConfigSource)
}
if got, want := proj.Config.Module.ResRef, "yamlmod"; got != want {
t.Fatalf("expected resref %q, got %q", want, got)
}
}
func TestLoadRejectsMalformedYAML(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, ConfigFile), "module:\n name: Test\n resref: bad\n")
if _, err := Load(root); err == nil {
t.Fatal("expected malformed YAML error")
}
}
func TestLoadRejectsUnknownYAMLFields(t *testing.T) {
root := t.TempDir()
writeProjectFile(t, filepath.Join(root, ConfigFile), `
module:
name: Test Module
resref: testmod
paths:
source: src
build: build
unexpected: true
`)
err := loadAndValidate(root)
if err == nil {
t.Fatal("expected unknown field error")
}
if !strings.Contains(err.Error(), "field unexpected not found") {
t.Fatalf("expected unknown field error, got %v", err)
}
}
func TestFindRootUsesYAMLConfig(t *testing.T) {
root := t.TempDir()
child := filepath.Join(root, "nested", "dir")
mkdirAll(t, child)
writeProjectFile(t, filepath.Join(root, ConfigFile), "module:\n name: Test\n resref: test\n")
got, err := FindRoot(child)
if err != nil {
t.Fatalf("FindRoot returned error: %v", err)
}
if got != root {
t.Fatalf("expected root %s, got %s", root, got)
}
}
func TestTopDataAssetsDirPrefersExplicitConfig(t *testing.T) {
root := t.TempDir()
mkdirAll(t, filepath.Join(root, "src"))
@@ -242,6 +392,60 @@ func TestValidateLayoutRejectsInvalidAutogenConsumerConfig(t *testing.T) {
}
}
func TestValidateLayoutRejectsDuplicateHAKNames(t *testing.T) {
root := t.TempDir()
mkdirAll(t, filepath.Join(root, "src"))
mkdirAll(t, filepath.Join(root, "build"))
proj := &Project{
Root: root,
Config: Config{
Module: ModuleConfig{Name: "Test", ResRef: "test"},
Paths: PathConfig{Source: "src", Build: "build"},
HAKs: []HAKConfig{
{Name: "core", Priority: 1, Include: []string{"core/**"}},
{Name: "CORE", Priority: 2, Include: []string{"other/**"}},
},
},
}
err := proj.ValidateLayout()
if err == nil {
t.Fatal("expected duplicate hak validation error")
}
if !strings.Contains(err.Error(), "duplicated") {
t.Fatalf("expected duplicate validation error, got %v", err)
}
}
func TestValidateLayoutRejectsAmbiguousMusicPrefixes(t *testing.T) {
root := t.TempDir()
mkdirAll(t, filepath.Join(root, "assets"))
mkdirAll(t, filepath.Join(root, "build"))
proj := &Project{
Root: root,
Config: Config{
Module: ModuleConfig{Name: "Test", ResRef: "test"},
Paths: PathConfig{Assets: "assets", Build: "build"},
Music: MusicConfig{
Prefixes: map[string]string{
"envi/music": "mus_",
"/envi/music": "mus2_",
},
},
},
}
err := proj.ValidateLayout()
if err == nil {
t.Fatal("expected music prefix validation error")
}
if !strings.Contains(err.Error(), "normalize to the same path") {
t.Fatalf("expected ambiguous prefix validation error, got %v", err)
}
}
func TestScanAllowsMissingAssetsDir(t *testing.T) {
root := t.TempDir()
mkdirAll(t, filepath.Join(root, "src"))
@@ -320,3 +524,18 @@ func TestCloneWithHAKNamesRejectsUnknownHAKs(t *testing.T) {
t.Fatal("expected error for unknown hak name")
}
}
func loadAndValidate(root string) error {
proj, err := Load(root)
if err != nil {
return err
}
return proj.ValidateLayout()
}
func writeProjectFile(t *testing.T, path, content string) {
t.Helper()
if err := os.WriteFile(path, []byte(strings.TrimPrefix(content, "\n")), 0o644); err != nil {
t.Fatalf("write %s: %v", path, err)
}
}