| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- package export
- import (
- "archive/zip"
- "bytes"
- "compress/gzip"
- "errors"
- "io"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "testing"
- "git.monoexp.com/bajdev/mpckit/internal/project"
- )
- const testdata = "../../testdata"
- func must(t *testing.T, err error) {
- t.Helper()
- if err != nil {
- t.Fatal(err)
- }
- }
- func gunzip(t *testing.T, b []byte) []byte {
- t.Helper()
- zr, err := gzip.NewReader(bytes.NewReader(b))
- must(t, err)
- out, err := io.ReadAll(zr)
- must(t, err)
- return out
- }
- func readFile(t *testing.T, path string) []byte {
- t.Helper()
- b, err := os.ReadFile(path)
- must(t, err)
- return b
- }
- // buildT1 makes MpckitT1 through the model (as in the M2 golden test).
- func buildT1(t *testing.T) *project.Project {
- t.Helper()
- p, err := project.New("MpckitT1")
- must(t, err)
- dir := filepath.Join(testdata, "accepted", "MpckitT1"+project.DataSuffix)
- must(t, p.AssignSample(0, filepath.Join(dir, "Linn 9000 kick.wav")))
- must(t, p.AssignSample(16, filepath.Join(dir, "Linn 9000 kick001.wav")))
- must(t, p.SetTune(16, 5, 0))
- must(t, p.SetSequence(0, "Verse", 96, 8))
- must(t, p.AddSequence(1))
- must(t, p.SetSequence(1, "Chorus", 96, 4))
- return p
- }
- func listDir(t *testing.T, dir string) []string {
- t.Helper()
- ents, err := os.ReadDir(dir)
- must(t, err)
- var names []string
- for _, e := range ents {
- names = append(names, e.Name())
- }
- sort.Strings(names)
- return names
- }
- func TestFolder(t *testing.T) {
- dest := t.TempDir()
- p := buildT1(t)
- path, err := Folder(p, dest, false)
- must(t, err)
- if path != filepath.Join(dest, "MpckitT1.xpj") {
- t.Errorf("path = %s", path)
- }
- if got := listDir(t, dest); strings.Join(got, "|") != "MpckitT1.xpj|MpckitT1_[ProjectData]" {
- t.Errorf("dest holds %v", got)
- }
- want := gunzip(t, readFile(t, filepath.Join(testdata, "accepted", "MpckitT1.xpj")))
- if !bytes.Equal(gunzip(t, readFile(t, path)), want) {
- t.Error("exported .xpj differs from MpckitT1.xpj")
- }
- src := filepath.Join(testdata, "accepted", "MpckitT1"+project.DataSuffix)
- data := filepath.Join(dest, "MpckitT1"+project.DataSuffix)
- if got := listDir(t, data); strings.Join(got, "|") != "Linn 9000 kick.wav|Linn 9000 kick001.wav" {
- t.Errorf("data folder holds %v", got)
- }
- for _, f := range listDir(t, data) {
- if !bytes.Equal(readFile(t, filepath.Join(data, f)), readFile(t, filepath.Join(src, f))) {
- t.Errorf("%s differs from its source", f)
- }
- }
- // Again without overwrite: refused, nothing touched.
- marker := filepath.Join(data, "keep.txt")
- must(t, os.WriteFile(marker, []byte("x"), 0o644))
- _, err = Folder(p, dest, false)
- var exists *ExistsError
- if !errors.As(err, &exists) || len(exists.Paths) != 2 {
- t.Fatalf("second export: %v", err)
- }
- if _, err := os.Stat(marker); err != nil {
- t.Error("refused export changed the folder")
- }
- // With overwrite: the old data folder is replaced, not merged.
- _, err = Folder(p, dest, true)
- must(t, err)
- if _, err := os.Stat(marker); err == nil {
- t.Error("overwrite kept a stale file in the data folder")
- }
- if got := listDir(t, dest); len(got) != 2 {
- t.Errorf("temporary files left behind: %v", got)
- }
- }
- func TestFolderEmptyProject(t *testing.T) {
- dest := t.TempDir()
- p, err := project.New("Empty")
- must(t, err)
- _, err = Folder(p, dest, false)
- must(t, err)
- // The device creates the data folder even with no samples; so do we.
- if got := listDir(t, filepath.Join(dest, "Empty"+project.DataSuffix)); len(got) != 0 {
- t.Errorf("data folder holds %v", got)
- }
- }
- func TestRenamedLoadedProject(t *testing.T) {
- p, _, err := project.Load(filepath.Join(testdata, "device", "DemoFile.xpj"))
- must(t, err)
- must(t, p.SetName("Renamed"))
- dest := t.TempDir()
- _, err = Folder(p, dest, false)
- must(t, err)
- got := listDir(t, filepath.Join(dest, "Renamed"+project.DataSuffix))
- if len(got) != 6 {
- t.Errorf("data folder holds %v", got)
- }
- want := gunzip(t, readFile(t, filepath.Join(testdata, "device", "DemoFile.xpj")))
- if !bytes.Equal(gunzip(t, readFile(t, filepath.Join(dest, "Renamed.xpj"))), want) {
- t.Error("renaming changed the file contents")
- }
- }
- func TestMissingSources(t *testing.T) {
- tmp := t.TempDir()
- p, err := project.New("Missing")
- must(t, err)
- for i, name := range []string{"a.wav", "b.wav", "c.wav"} {
- src := filepath.Join(tmp, name)
- must(t, os.WriteFile(src, readFile(t, filepath.Join(testdata, "accepted", "MpckitT2"+project.DataSuffix, "Linn 9000 kick.wav")), 0o644))
- must(t, p.AssignSample(i, src))
- }
- must(t, os.Remove(filepath.Join(tmp, "a.wav")))
- must(t, os.Remove(filepath.Join(tmp, "c.wav")))
- dest := t.TempDir()
- _, err = Folder(p, dest, false)
- var missing *MissingError
- if !errors.As(err, &missing) || strings.Join(missing.Files, ",") != "a.wav,c.wav" {
- t.Fatalf("Folder: %v", err)
- }
- if !strings.Contains(err.Error(), "2 sample file(s)") {
- t.Errorf("message: %v", err)
- }
- if err := Zip(p, filepath.Join(dest, "m.zip"), false); !errors.As(err, &missing) {
- t.Fatalf("Zip: %v", err)
- }
- if got := listDir(t, dest); len(got) != 0 {
- t.Errorf("failed export wrote %v", got)
- }
- }
- func TestZip(t *testing.T) {
- dest := t.TempDir()
- zpath := filepath.Join(dest, "kit.zip")
- p := buildT1(t)
- must(t, Zip(p, zpath, false))
- zr, err := zip.OpenReader(zpath)
- must(t, err)
- defer zr.Close()
- var names []string
- files := map[string][]byte{}
- for _, f := range zr.File {
- names = append(names, f.Name)
- rc, err := f.Open()
- must(t, err)
- b, err := io.ReadAll(rc)
- rc.Close()
- must(t, err)
- files[f.Name] = b
- }
- want := "MpckitT1.xpj|MpckitT1_[ProjectData]/|MpckitT1_[ProjectData]/Linn 9000 kick.wav|MpckitT1_[ProjectData]/Linn 9000 kick001.wav"
- if strings.Join(names, "|") != want {
- t.Errorf("entries %v", names)
- }
- if !bytes.Equal(gunzip(t, files["MpckitT1.xpj"]), gunzip(t, readFile(t, filepath.Join(testdata, "accepted", "MpckitT1.xpj")))) {
- t.Error("zipped .xpj differs from MpckitT1.xpj")
- }
- src := filepath.Join(testdata, "accepted", "MpckitT1"+project.DataSuffix, "Linn 9000 kick001.wav")
- if !bytes.Equal(files["MpckitT1_[ProjectData]/Linn 9000 kick001.wav"], readFile(t, src)) {
- t.Error("zipped WAV differs from its source")
- }
- var exists *ExistsError
- if err := Zip(p, zpath, false); !errors.As(err, &exists) {
- t.Errorf("existing zip: %v", err)
- }
- must(t, Zip(p, zpath, true))
- if got := listDir(t, dest); strings.Join(got, "|") != "kit.zip" {
- t.Errorf("temporary files left behind: %v", got)
- }
- }
|