Files
sow-tools/internal/topdata/autogen_manifest_file_test.go
T
archvillainette 945204ce50 feat(topdata): anchor autogen lock identity on model path with cutover remap
Lock identity for accessory VFX rows is now the model source path
(dataset:group/subgroup/file.mdl) rather than the config-derived
presentation key. Config-only edits (key_format, delimiter, case,
strip_prefixes) no longer reshuffle row IDs.

Adds: accessoryVisualeffectLockKey, hasKey helper, stale pruning loop
(managed keys with no live entry are freed), and one-time cutover remap
(old config-derived key in historical lock → new model-path key, with
the old key pruned). autogenConsumerManagedLockKeyMatcher is now
config-independent (dataset prefix + first path segment ∈ policy groups).

Updates autogen_manifest_file_test.go and topdata_test.go lock-key
assertions to match the new model-path scheme.
2026-06-21 14:43:38 +02:00

104 lines
3.4 KiB
Go

package topdata
import (
"path/filepath"
"testing"
"git.westgate.pw/ShadowsOverWestgate/sow-tools/internal/project"
)
// The manifest_file branch reads a local autogenManifest JSON, augments the
// visualeffects dataset from its entries, and assigns lock IDs — no network.
func TestApplyAutogenConsumersReadsManifestFile(t *testing.T) {
root := testProjectRoot(t)
manifestPath := filepath.Join(root, ".cache", "sow-accessory-vfx-manifest.json")
mkdirAll(t, filepath.Join(root, ".cache"))
writeFile(t, manifestPath, `{
"id": "accessory_visualeffects",
"repo": "ShadowsOverWestgate/sow-assets-manifest",
"ref": "v1.2.3",
"generated_at": "2026-06-21T00:00:00Z",
"entries": [
{"source": "head_accessories/hat/hfx_bandana.mdl", "model_stem": "hfx_bandana", "group": "head_accessories", "subgroup": "hat"}
]
}`+"\n")
p := testProject(root)
p.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "accessory_visualeffects",
Optional: true,
ManifestFile: ".cache/sow-accessory-vfx-manifest.json",
},
}
collected := []nativeCollectedDataset{
{
Dataset: nativeDataset{Name: "visualeffects", Kind: nativeDatasetBase},
Columns: []string{"Label", "Type_FD", "OrientWithGround", "Imp_HeadCon_Node", "OrientWithObject"},
Rows: nil,
LockData: map[string]int{
"visualeffects:existing": 17,
},
},
}
got, err := applyAutogenConsumers(p, collected, nil)
if err != nil {
t.Fatalf("applyAutogenConsumers failed: %v", err)
}
if len(got) != 1 || len(got[0].Rows) != 1 {
t.Fatalf("expected one autogenerated row, got %#v", got)
}
row := got[0].Rows[0]
if row["key"] != "visualeffects:head_accessories/hat/bandana" || row["Imp_HeadCon_Node"] != "hfx_bandana" {
t.Fatalf("unexpected generated row: %#v", row)
}
if _, ok := got[0].LockData["visualeffects:head_accessories/hat/hfx_bandana.mdl"]; !ok {
t.Fatalf("expected lock id for generated accessory, got %#v", got[0].LockData)
}
// Authored key untouched.
if got[0].LockData["visualeffects:existing"] != 17 {
t.Fatalf("expected authored lock id retained at 17, got %#v", got[0].LockData)
}
}
// A missing manifest_file is an ignorable-optional condition: the optional
// consumer fails open (no rows) and preserves existing lock IDs.
func TestApplyAutogenConsumersMissingManifestFileFailsOpen(t *testing.T) {
root := testProjectRoot(t)
lockPath := filepath.Join(root, "visualeffects-lock.json")
writeFile(t, lockPath, `{"visualeffects:head_accessories/hat/bandana":10101}`+"\n")
p := testProject(root)
p.Config.Autogen.Consumers = []project.AutogenConsumerConfig{
{
ID: "accessory_visualeffects",
Producer: "accessory_visualeffects",
Dataset: "visualeffects",
Mode: "accessory_visualeffects",
Optional: true,
ManifestFile: ".cache/does-not-exist.json",
},
}
collected := []nativeCollectedDataset{
{
Dataset: nativeDataset{Name: "visualeffects", Kind: nativeDatasetBase, LockPath: lockPath},
Columns: []string{"Label"},
Rows: nil,
LockData: map[string]int{},
},
}
got, err := applyAutogenConsumers(p, collected, nil)
if err != nil {
t.Fatalf("expected fail-open, got error: %v", err)
}
if id, ok := got[0].LockData["visualeffects:head_accessories/hat/bandana"]; !ok || id != 10101 {
t.Fatalf("expected preserved lock id 10101, got %v (present=%v)", id, ok)
}
}