Parts-Based Manifest Publishing
This commit is contained in:
@@ -2,7 +2,10 @@ package topdata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -7966,6 +7969,91 @@ func TestAugmentWithAutogeneratedPartsSortsRows(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAugmentWithAutogeneratedRobePartsDefaultsHideColumns(t *testing.T) {
|
||||
collected := []nativeCollectedDataset{
|
||||
{
|
||||
Dataset: nativeDataset{
|
||||
Name: "parts/robe",
|
||||
OutputName: "parts_robe.2da",
|
||||
},
|
||||
Columns: []string{
|
||||
"COSTMODIFIER", "ACBONUS", "HIDEFOOTR", "HIDEFOOTL", "HIDECHEST",
|
||||
},
|
||||
Rows: []map[string]any{},
|
||||
LockData: map[string]int{},
|
||||
},
|
||||
}
|
||||
|
||||
autogenerated := map[string]map[int]struct{}{
|
||||
"robe": {95: {}},
|
||||
}
|
||||
|
||||
result := augmentWithAutogeneratedParts(collected, autogenerated)
|
||||
robeDataset := result[0]
|
||||
if len(robeDataset.Rows) != 1 {
|
||||
t.Fatalf("expected 1 autogenerated robe row, got %d", len(robeDataset.Rows))
|
||||
}
|
||||
|
||||
row := robeDataset.Rows[0]
|
||||
if got := row["id"]; got != 95 {
|
||||
t.Fatalf("expected autogenerated robe row id 95, got %v", got)
|
||||
}
|
||||
if got := row["COSTMODIFIER"]; got != "0" {
|
||||
t.Fatalf("expected COSTMODIFIER=0, got %v", got)
|
||||
}
|
||||
if got := row["ACBONUS"]; got != "0.00" {
|
||||
t.Fatalf("expected ACBONUS=0.00, got %v", got)
|
||||
}
|
||||
for _, column := range []string{"HIDEFOOTR", "HIDEFOOTL", "HIDECHEST"} {
|
||||
if got := row[column]; got != "0" {
|
||||
t.Fatalf("expected %s=0, got %v", column, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAugmentWithAutogeneratedRobePartsActivatesUnsetHideColumns(t *testing.T) {
|
||||
collected := []nativeCollectedDataset{
|
||||
{
|
||||
Dataset: nativeDataset{
|
||||
Name: "parts/robe",
|
||||
OutputName: "parts_robe.2da",
|
||||
},
|
||||
Columns: []string{
|
||||
"COSTMODIFIER", "ACBONUS", "HIDEFOOTR", "HIDEFOOTL", "HIDECHEST",
|
||||
},
|
||||
Rows: []map[string]any{
|
||||
{
|
||||
"id": 95,
|
||||
"COSTMODIFIER": "****",
|
||||
"ACBONUS": "****",
|
||||
"HIDEFOOTR": "****",
|
||||
"HIDEFOOTL": "****",
|
||||
"HIDECHEST": "****",
|
||||
},
|
||||
},
|
||||
LockData: map[string]int{},
|
||||
},
|
||||
}
|
||||
|
||||
autogenerated := map[string]map[int]struct{}{
|
||||
"robe": {95: {}},
|
||||
}
|
||||
|
||||
result := augmentWithAutogeneratedParts(collected, autogenerated)
|
||||
row := result[0].Rows[0]
|
||||
if got := row["COSTMODIFIER"]; got != "0" {
|
||||
t.Fatalf("expected COSTMODIFIER=0, got %v", got)
|
||||
}
|
||||
if got := row["ACBONUS"]; got != "0.00" {
|
||||
t.Fatalf("expected ACBONUS=0.00, got %v", got)
|
||||
}
|
||||
for _, column := range []string{"HIDEFOOTR", "HIDEFOOTL", "HIDECHEST"} {
|
||||
if got := row[column]; got != "0" {
|
||||
t.Fatalf("expected %s=0, got %v", column, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeWithAutogeneratedParts(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "parts"))
|
||||
@@ -8007,7 +8095,41 @@ func TestBuildNativeWithAutogeneratedParts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeWithSiblingAssetsRepo(t *testing.T) {
|
||||
func TestBuildNativeWithAutogeneratedRobeParts(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "parts"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "parts", "robe.json"), `{
|
||||
"output": "parts_robe.2da",
|
||||
"columns": ["COSTMODIFIER", "ACBONUS", "HIDEFOOTR", "HIDEFOOTL", "HIDECHEST"],
|
||||
"rows": [{"id": 0, "COSTMODIFIER": "1", "ACBONUS": "0.25", "HIDEFOOTR": "1", "HIDEFOOTL": "1", "HIDECHEST": "1"}]
|
||||
}`+"\n")
|
||||
mkdirAll(t, filepath.Join(root, "reference"))
|
||||
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
mkdirAll(t, filepath.Join(root, "assets", "part", "robe"))
|
||||
writeFile(t, filepath.Join(root, "assets", "part", "robe", "pfa0_robe095.mdl"), "")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.Assets = filepath.Join(root, "assets")
|
||||
|
||||
result, err := BuildNative(proj, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildNative failed: %v", err)
|
||||
}
|
||||
|
||||
partsBytes, err := os.ReadFile(filepath.Join(result.Output2DADir, "parts_robe.2da"))
|
||||
if err != nil {
|
||||
t.Fatalf("read parts_robe.2da: %v", err)
|
||||
}
|
||||
partsText := string(partsBytes)
|
||||
|
||||
if !strings.Contains(partsText, "95\t0\t0.00\t0\t0\t0") {
|
||||
t.Fatalf("expected autogenerated robe row 95 with zeroed hide defaults, got:\n%s", partsText)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeWithReleasedPartsManifest(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
projRoot := filepath.Join(root, "project")
|
||||
mkdirAll(t, filepath.Join(projRoot, "src"))
|
||||
@@ -8023,10 +8145,31 @@ func TestBuildNativeWithSiblingAssetsRepo(t *testing.T) {
|
||||
mkdirAll(t, filepath.Join(projRoot, "reference"))
|
||||
writeFile(t, filepath.Join(projRoot, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
siblingAssets := filepath.Join(root, "sow-assets")
|
||||
mkdirAll(t, filepath.Join(siblingAssets, "assets", "part", "belt"))
|
||||
writeFile(t, filepath.Join(siblingAssets, "assets", "part", "belt", "pfa0_belt018.mdl"), "")
|
||||
writeFile(t, filepath.Join(siblingAssets, "assets", "part", "belt", "pfa0_belt171.mdl"), "")
|
||||
manifestJSON := `{
|
||||
"repo": "ShadowsOverWestgate/sow-assets",
|
||||
"ref": "test-manifest",
|
||||
"generated_at": "2026-04-09T00:00:00Z",
|
||||
"categories": {
|
||||
"belt": [18, 171]
|
||||
}
|
||||
}` + "\n"
|
||||
var server *httptest.Server
|
||||
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api/v1/repos/ShadowsOverWestgate/sow-assets/releases/tags/parts-manifest-current":
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"assets":[{"name":"sow-parts-manifest.json","browser_download_url":"` + server.URL + `/downloads/sow-parts-manifest.json"}]}`))
|
||||
case "/downloads/sow-parts-manifest.json":
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(manifestJSON))
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
runGitTest(t, "", "init", "-b", "main", projRoot)
|
||||
runGitTest(t, projRoot, "remote", "add", "origin", server.URL+"/ShadowsOverWestgate/sow-module.git")
|
||||
|
||||
proj := &project.Project{
|
||||
Root: projRoot,
|
||||
@@ -8036,7 +8179,6 @@ func TestBuildNativeWithSiblingAssetsRepo(t *testing.T) {
|
||||
TopData: project.TopDataConfig{
|
||||
Source: "topdata",
|
||||
Build: "build/topdata",
|
||||
Assets: "sow-assets",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -8056,10 +8198,71 @@ func TestBuildNativeWithSiblingAssetsRepo(t *testing.T) {
|
||||
t.Errorf("expected existing row 0 to be preserved, got:\n%s", partsText)
|
||||
}
|
||||
if !strings.Contains(partsText, "18\t0\t0.00") {
|
||||
t.Errorf("expected autogenerated row 18 from sibling repo, got:\n%s", partsText)
|
||||
t.Errorf("expected autogenerated row 18 from released manifest, got:\n%s", partsText)
|
||||
}
|
||||
if !strings.Contains(partsText, "171\t0\t0.00") {
|
||||
t.Errorf("expected autogenerated row 171 from sibling repo, got:\n%s", partsText)
|
||||
t.Errorf("expected autogenerated row 171 from released manifest, got:\n%s", partsText)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeRejectsGitRepoTopDataAssetsOverride(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
mkdirAll(t, filepath.Join(root, "topdata", "data", "parts"))
|
||||
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(root, "topdata", "data", "parts", "belt.json"), `{
|
||||
"output": "parts_belt.2da",
|
||||
"columns": ["COSTMODIFIER", "ACBONUS"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
mkdirAll(t, filepath.Join(root, "reference"))
|
||||
writeFile(t, filepath.Join(root, "reference", "build.py"), "print('ok')\n")
|
||||
|
||||
proj := testProject(root)
|
||||
proj.Config.TopData.Assets = "ssh://git@gitea.westgate.pw:2222/ShadowsOverWestgate/sow-assets.git"
|
||||
|
||||
_, err := BuildNative(proj, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "no longer supports git repo specs") {
|
||||
t.Fatalf("expected git repo topdata.assets override to be rejected, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildNativeFailsWhenReleasedPartsManifestUnavailable(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
projRoot := filepath.Join(root, "project")
|
||||
mkdirAll(t, filepath.Join(projRoot, "src"))
|
||||
mkdirAll(t, filepath.Join(projRoot, "assets"))
|
||||
mkdirAll(t, filepath.Join(projRoot, "build"))
|
||||
mkdirAll(t, filepath.Join(projRoot, "topdata", "data", "parts"))
|
||||
writeFile(t, filepath.Join(projRoot, "topdata", "base_dialog.json"), "{}\n")
|
||||
writeFile(t, filepath.Join(projRoot, "topdata", "data", "parts", "belt.json"), `{
|
||||
"output": "parts_belt.2da",
|
||||
"columns": ["COSTMODIFIER", "ACBONUS"],
|
||||
"rows": []
|
||||
}`+"\n")
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
runGitTest(t, "", "init", "-b", "main", projRoot)
|
||||
runGitTest(t, projRoot, "remote", "add", "origin", server.URL+"/ShadowsOverWestgate/sow-module.git")
|
||||
|
||||
proj := &project.Project{
|
||||
Root: projRoot,
|
||||
Config: project.Config{
|
||||
Module: project.ModuleConfig{Name: "Test", ResRef: "test"},
|
||||
Paths: project.PathConfig{Source: "src", Assets: "assets", Build: "build"},
|
||||
TopData: project.TopDataConfig{
|
||||
Source: "topdata",
|
||||
Build: "build/topdata",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := BuildNative(proj, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "fetch parts manifest release metadata") {
|
||||
t.Fatalf("expected missing released parts manifest to fail, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8214,6 +8417,18 @@ func diagnosticsText(diags []Diagnostic) string {
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func runGitTest(t *testing.T, dir string, args ...string) {
|
||||
t.Helper()
|
||||
cmd := exec.Command("git", args...)
|
||||
if dir != "" {
|
||||
cmd.Dir = dir
|
||||
}
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("git %v failed: %v\n%s", args, err, string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func testProjectRoot(t *testing.T) string {
|
||||
t.Helper()
|
||||
root := t.TempDir()
|
||||
@@ -8233,6 +8448,7 @@ func testProject(root string) *project.Project {
|
||||
Source: "topdata",
|
||||
Build: "build/topdata",
|
||||
ReferenceBuilder: "reference",
|
||||
Assets: ".",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user