package pack import ( "archive/zip" "bytes" "fmt" "os" "path/filepath" "strings" "testing" "git.t5de.dev/t5de/t5de-api/cfl" ) // Synthetic test files: not IMVU's. const ( testManifest = `{"format": 1, "id": "blue-coat", "revision": 2, "name": " Blue Coat ", "creator": "Tester", "description": "

A coat

", "rating": "general"}` testIndex = `` ) var testPNG = []byte("\x89PNG\r\n\x1a\nfake") func testFiles() map[string][]byte { return map[string][]byte{"index.xml": []byte(testIndex), "coat.png": testPNG, "coat.xmf": []byte("mesh")} } func writeFile(t *testing.T, path string, data []byte) { t.Helper() if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, data, 0o644); err != nil { t.Fatal(err) } } // dirPack makes a pack with its files in files/. func dirPack(t *testing.T, manifest string, files map[string][]byte) string { dir := t.TempDir() writeFile(t, filepath.Join(dir, ManifestName), []byte(manifest)) if err := os.Mkdir(filepath.Join(dir, FilesDir), 0o755); err != nil { t.Fatal(err) } for name, data := range files { writeFile(t, filepath.Join(dir, FilesDir, name), data) } return dir } type zipEntry struct { name string data []byte method uint16 } func makeZip(t *testing.T, entries []zipEntry) []byte { t.Helper() var b bytes.Buffer z := zip.NewWriter(&b) for _, e := range entries { w, err := z.CreateHeader(&zip.FileHeader{Name: e.name, Method: e.method}) if err != nil { t.Fatal(err) } w.Write(e.data) } if err := z.Close(); err != nil { t.Fatal(err) } return b.Bytes() } // chknPack makes a pack with its files in product.chkn. func chknPack(t *testing.T, manifest string, entries []zipEntry) string { dir := t.TempDir() writeFile(t, filepath.Join(dir, ManifestName), []byte(manifest)) writeFile(t, filepath.Join(dir, ChknName), makeZip(t, entries)) return dir } func zipEntries(method uint16) []zipEntry { var entries []zipEntry for name, data := range testFiles() { entries = append(entries, zipEntry{name, data, method}) } return entries } func TestLoad(t *testing.T) { fromDir, err := Load(dirPack(t, testManifest, testFiles())) if err != nil { t.Fatal(err) } m := fromDir.Manifest if m.ID != "blue-coat" || m.Revision != 2 || m.Name != "Blue Coat" || m.Creator != "Tester" || m.Rating != General { t.Errorf("manifest: %+v", m) } want := Index{Rating: "GA", Name: "Test Coat", Gender: "female", TypeID: 106, BodyPattern: 80, Parent: 12345} if fromDir.Index != want { t.Errorf("index: got %+v, want %+v", fromDir.Index, want) } var names []string for _, f := range fromDir.Files { names = append(names, f.Name) } if got := strings.Join(names, " "); got != "coat.png coat.xmf index.xml" { t.Errorf("files: %s", got) } // The same files zipped, stored or deflated, have the same checksum. Folder entries are ignored. for _, method := range []uint16{zip.Store, zip.Deflate} { entries := append(zipEntries(method), zipEntry{name: "folder/", method: method}) fromZip, err := Load(chknPack(t, testManifest, entries)) if err != nil { t.Fatal(err) } if fromZip.Checksum() != fromDir.Checksum() { t.Errorf("method %d: checksum differs", method) } } changed := testFiles() changed["coat.png"] = append(testPNG, 0) other, err := Load(dirPack(t, testManifest, changed)) if err != nil { t.Fatal(err) } if other.Checksum() == fromDir.Checksum() { t.Error("checksum didn't change") } data, err := fromDir.CFL() if err != nil { t.Fatal(err) } entries, err := cfl.Read(data) if err != nil || len(entries) != 3 || entries[2].Name != "index.xml" { t.Errorf("CFL: %q, %v", entries, err) } } func TestLoadErrors(t *testing.T) { adult := strings.Replace(testManifest, `"general"`, `"adult"`, 1) with := func(name string, data []byte) map[string][]byte { f := testFiles() f[name] = data return f } without := func(name string) map[string][]byte { f := testFiles() delete(f, name) return f } extra := func(e ...zipEntry) []zipEntry { return append(zipEntries(zip.Store), e...) } for _, c := range []struct { name, want string dir func(t *testing.T) string }{ {"rating mismatch", "ProductRating", func(t *testing.T) string { return dirPack(t, adult, testFiles()) }}, {"no index", "no index.xml", func(t *testing.T) string { return dirPack(t, testManifest, without("index.xml")) }}, {"contents json", "_contents.json", func(t *testing.T) string { return dirPack(t, testManifest, with("_contents.json", []byte("{}"))) }}, {"bad index", "index.xml: ProductRating", func(t *testing.T) string { return dirPack(t, testManifest, with("index.xml", []byte("