package kc import ( "archive/zip" "bytes" "encoding/json" "testing" ) // buildZip creates a ZIP archive in memory from a map of filename → content. func buildZip(t *testing.T, files map[string][]byte) []byte { t.Helper() var buf bytes.Buffer w := zip.NewWriter(&buf) for name, content := range files { f, err := w.Create(name) if err != nil { t.Fatalf("creating zip entry %s: %v", name, err) } if _, err := f.Write(content); err != nil { t.Fatalf("writing zip entry %s: %v", name, err) } } if err := w.Close(); err != nil { t.Fatalf("closing zip: %v", err) } return buf.Bytes() } func mustJSON(t *testing.T, v any) []byte { t.Helper() data, err := json.Marshal(v) if err != nil { t.Fatalf("marshaling JSON: %v", err) } return data } func TestExtract_PlainFCStd(t *testing.T) { data := buildZip(t, map[string][]byte{ "Document.xml": []byte(""), "thumbnails/a.png": []byte("png"), }) result, err := Extract(data) if err != nil { t.Fatalf("unexpected error: %v", err) } if result != nil { t.Fatalf("expected nil result for plain .fcstd, got %+v", result) } } func TestExtract_ValidKC(t *testing.T) { manifest := Manifest{ UUID: "550e8400-e29b-41d4-a716-446655440000", KCVersion: "1.0", RevisionHash: "abc123", SiloInstance: "https://silo.example.com", } metadata := Metadata{ SchemaName: "mechanical-part-v2", Tags: []string{"structural", "aluminum"}, LifecycleState: "draft", Fields: map[string]any{ "material": "6061-T6", "weight_kg": 0.34, }, } data := buildZip(t, map[string][]byte{ "Document.xml": []byte(""), "silo/manifest.json": mustJSON(t, manifest), "silo/metadata.json": mustJSON(t, metadata), }) result, err := Extract(data) if err != nil { t.Fatalf("unexpected error: %v", err) } if result == nil { t.Fatal("expected non-nil result") } if result.Manifest == nil { t.Fatal("expected manifest") } if result.Manifest.UUID != manifest.UUID { t.Errorf("manifest UUID = %q, want %q", result.Manifest.UUID, manifest.UUID) } if result.Manifest.KCVersion != manifest.KCVersion { t.Errorf("manifest KCVersion = %q, want %q", result.Manifest.KCVersion, manifest.KCVersion) } if result.Manifest.RevisionHash != manifest.RevisionHash { t.Errorf("manifest RevisionHash = %q, want %q", result.Manifest.RevisionHash, manifest.RevisionHash) } if result.Manifest.SiloInstance != manifest.SiloInstance { t.Errorf("manifest SiloInstance = %q, want %q", result.Manifest.SiloInstance, manifest.SiloInstance) } if result.Metadata == nil { t.Fatal("expected metadata") } if result.Metadata.SchemaName != metadata.SchemaName { t.Errorf("metadata SchemaName = %q, want %q", result.Metadata.SchemaName, metadata.SchemaName) } if result.Metadata.LifecycleState != metadata.LifecycleState { t.Errorf("metadata LifecycleState = %q, want %q", result.Metadata.LifecycleState, metadata.LifecycleState) } if len(result.Metadata.Tags) != 2 { t.Errorf("metadata Tags len = %d, want 2", len(result.Metadata.Tags)) } if result.Metadata.Fields["material"] != "6061-T6" { t.Errorf("metadata Fields[material] = %v, want 6061-T6", result.Metadata.Fields["material"]) } } func TestExtract_ManifestOnly(t *testing.T) { manifest := Manifest{ UUID: "550e8400-e29b-41d4-a716-446655440000", KCVersion: "1.0", } data := buildZip(t, map[string][]byte{ "Document.xml": []byte(""), "silo/manifest.json": mustJSON(t, manifest), }) result, err := Extract(data) if err != nil { t.Fatalf("unexpected error: %v", err) } if result == nil { t.Fatal("expected non-nil result") } if result.Manifest == nil { t.Fatal("expected manifest") } if result.Metadata != nil { t.Errorf("expected nil metadata, got %+v", result.Metadata) } } func TestExtract_InvalidJSON(t *testing.T) { data := buildZip(t, map[string][]byte{ "silo/manifest.json": []byte("{not valid json"), }) result, err := Extract(data) if err == nil { t.Fatal("expected error for invalid JSON") } if result != nil { t.Errorf("expected nil result on error, got %+v", result) } } func TestExtract_NotAZip(t *testing.T) { result, err := Extract([]byte("this is not a zip file")) if err == nil { t.Fatal("expected error for non-ZIP data") } if result != nil { t.Errorf("expected nil result on error, got %+v", result) } } func TestExtract_EmptySiloDir(t *testing.T) { // silo/ directory entry exists but no manifest or metadata files data := buildZip(t, map[string][]byte{ "Document.xml": []byte(""), "silo/": {}, }) result, err := Extract(data) if err != nil { t.Fatalf("unexpected error: %v", err) } if result == nil { t.Fatal("expected non-nil result for silo/ dir") } if result.Manifest != nil { t.Errorf("expected nil manifest, got %+v", result.Manifest) } if result.Metadata != nil { t.Errorf("expected nil metadata, got %+v", result.Metadata) } }