|
|
@@ -11,6 +11,7 @@ import (
|
|
|
"net/http/httptest"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
+ "reflect"
|
|
|
"strings"
|
|
|
"testing"
|
|
|
|
|
|
@@ -35,9 +36,13 @@ func (f *fakeDialogs) SaveZip(name string) (string, error) {
|
|
|
|
|
|
func newService() (*Service, *fakeDialogs) {
|
|
|
d := &fakeDialogs{}
|
|
|
- return NewService(d), d
|
|
|
+ s, _ := NewService(d)
|
|
|
+ return s, d
|
|
|
}
|
|
|
|
|
|
+// hostOf returns the Host that shares s, as NewService does.
|
|
|
+func hostOf(s *Service) *Host { return &Host{s: s} }
|
|
|
+
|
|
|
func must(t *testing.T, err error) {
|
|
|
t.Helper()
|
|
|
if err != nil {
|
|
|
@@ -110,7 +115,7 @@ func TestPadEdits(t *testing.T) {
|
|
|
t.Errorf("after assign: %+v", p)
|
|
|
}
|
|
|
|
|
|
- st, err = s.AssignSamplePath(16, kick)
|
|
|
+ st, err = hostOf(s).AssignSamplePath(16, kick)
|
|
|
must(t, err)
|
|
|
if st.Pads[16].File != "Linn 9000 kick.wav" || st.SampleCount != 1 {
|
|
|
t.Error("drop of the same file did not share the pool entry")
|
|
|
@@ -141,7 +146,7 @@ func TestPadEdits(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
// Errors still return the current state.
|
|
|
- st, err = s.AssignSamplePath(1, filepath.Join(testdata, "nope.wav"))
|
|
|
+ st, err = hostOf(s).AssignSamplePath(1, filepath.Join(testdata, "nope.wav"))
|
|
|
if err == nil || st.Pads[16].File == "" {
|
|
|
t.Errorf("bad path: %v", err)
|
|
|
}
|
|
|
@@ -178,7 +183,7 @@ func TestExport(t *testing.T) {
|
|
|
s, d := newService()
|
|
|
_, err := s.SetName("Kit")
|
|
|
must(t, err)
|
|
|
- _, err = s.AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
+ _, err = hostOf(s).AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
must(t, err)
|
|
|
|
|
|
d.folder = t.TempDir()
|
|
|
@@ -278,7 +283,7 @@ func TestExportTarget(t *testing.T) {
|
|
|
t.Error("New kept the export targets")
|
|
|
}
|
|
|
choose()
|
|
|
- _, err = s.LoadPath(filepath.Join(testdata, "device", "DemoBlank.xpj"))
|
|
|
+ _, err = hostOf(s).LoadPath(filepath.Join(testdata, "device", "DemoBlank.xpj"))
|
|
|
must(t, err)
|
|
|
if s.exportDir != "" || s.zipPath != "" {
|
|
|
t.Error("Load kept the export targets")
|
|
|
@@ -299,9 +304,9 @@ func TestExportMatchesCLIRecipe(t *testing.T) {
|
|
|
s, _ := newService()
|
|
|
_, err := s.SetName("MpckitT1")
|
|
|
must(t, err)
|
|
|
- _, err = s.AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
+ _, err = hostOf(s).AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
must(t, err)
|
|
|
- _, err = s.AssignSamplePath(16, filepath.Join(kickDir, "Linn 9000 kick001.wav"))
|
|
|
+ _, err = hostOf(s).AssignSamplePath(16, filepath.Join(kickDir, "Linn 9000 kick001.wav"))
|
|
|
must(t, err)
|
|
|
_, err = s.SetTune(16, 5, 0)
|
|
|
must(t, err)
|
|
|
@@ -324,11 +329,11 @@ func TestExportMatchesCLIRecipe(t *testing.T) {
|
|
|
func TestAudio(t *testing.T) {
|
|
|
s, _ := newService()
|
|
|
kick := filepath.Join(kickDir, "Linn 9000 kick.wav")
|
|
|
- st, err := s.AssignSamplePath(3, kick)
|
|
|
+ st, err := hostOf(s).AssignSamplePath(3, kick)
|
|
|
must(t, err)
|
|
|
|
|
|
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("asset")) })
|
|
|
- h := s.AudioMiddleware(next)
|
|
|
+ h := hostOf(s).AudioMiddleware(next)
|
|
|
get := func(url string) *httptest.ResponseRecorder {
|
|
|
rec := httptest.NewRecorder()
|
|
|
h.ServeHTTP(rec, httptest.NewRequest("GET", url, nil))
|
|
|
@@ -373,11 +378,11 @@ func TestMoveCopySwap(t *testing.T) {
|
|
|
s, _ := newService()
|
|
|
kick := filepath.Join(kickDir, "Linn 9000 kick.wav")
|
|
|
kick2 := filepath.Join(kickDir, "Linn 9000 kick001.wav")
|
|
|
- _, err := s.AssignSamplePath(0, kick)
|
|
|
+ _, err := hostOf(s).AssignSamplePath(0, kick)
|
|
|
must(t, err)
|
|
|
_, err = s.SetTune(0, 3, 0)
|
|
|
must(t, err)
|
|
|
- _, err = s.AssignSamplePath(1, kick2)
|
|
|
+ _, err = hostOf(s).AssignSamplePath(1, kick2)
|
|
|
must(t, err)
|
|
|
|
|
|
// Copy across banks keeps the tuning and shares the sample.
|
|
|
@@ -434,7 +439,7 @@ func TestLoad(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
// A bad file keeps the current project.
|
|
|
- _, err = s.LoadPath(filepath.Join(testdata, "device", "DemoFile_[ProjectData]", "Bass-Pure C.wav"))
|
|
|
+ _, err = hostOf(s).LoadPath(filepath.Join(testdata, "device", "DemoFile_[ProjectData]", "Bass-Pure C.wav"))
|
|
|
if err == nil || s.State().Name != "DemoFile" {
|
|
|
t.Errorf("bad load: %v", err)
|
|
|
}
|
|
|
@@ -482,8 +487,12 @@ func TestGoldenT1ThroughService(t *testing.T) {
|
|
|
s, _ := newService()
|
|
|
calls := []func() (State, error){
|
|
|
func() (State, error) { return s.SetName("MpckitT1") },
|
|
|
- func() (State, error) { return s.AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav")) },
|
|
|
- func() (State, error) { return s.AssignSamplePath(16, filepath.Join(kickDir, "Linn 9000 kick001.wav")) },
|
|
|
+ func() (State, error) {
|
|
|
+ return hostOf(s).AssignSamplePath(0, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
+ },
|
|
|
+ func() (State, error) {
|
|
|
+ return hostOf(s).AssignSamplePath(16, filepath.Join(kickDir, "Linn 9000 kick001.wav"))
|
|
|
+ },
|
|
|
func() (State, error) { return s.SetTune(16, 5, 0) },
|
|
|
func() (State, error) { return s.SetSequence(0, "Verse", 96, 8) },
|
|
|
func() (State, error) { return s.AddSequence(1) },
|
|
|
@@ -524,7 +533,7 @@ func TestMissingFiles(t *testing.T) {
|
|
|
must(t, os.Remove(filepath.Join(dir, "DemoFile"+project.DataSuffix, "80s-Snr-Dreamer SA.wav")))
|
|
|
|
|
|
s, _ := newService()
|
|
|
- res, err := s.LoadPath(path)
|
|
|
+ res, err := hostOf(s).LoadPath(path)
|
|
|
must(t, err)
|
|
|
st := res.State
|
|
|
if st.MissingCount != 1 {
|
|
|
@@ -548,7 +557,7 @@ func TestMissingFiles(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
// Replacing the pad's sample fixes it.
|
|
|
- st, err = s.AssignSamplePath(1, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
+ st, err = hostOf(s).AssignSamplePath(1, filepath.Join(kickDir, "Linn 9000 kick.wav"))
|
|
|
must(t, err)
|
|
|
if st.MissingCount != 0 || st.Pads[1].Missing {
|
|
|
t.Error("still missing after replace")
|
|
|
@@ -562,12 +571,12 @@ func TestCloseWindow(t *testing.T) {
|
|
|
s, _ := newService()
|
|
|
s.CloseWindow() // no closer set: does nothing
|
|
|
closed := false
|
|
|
- s.SetCloser(func() { closed = true })
|
|
|
- if s.Dirty() {
|
|
|
+ hostOf(s).SetCloser(func() { closed = true })
|
|
|
+ if hostOf(s).Dirty() {
|
|
|
t.Error("new project dirty")
|
|
|
}
|
|
|
_, _ = s.SetName("Other")
|
|
|
- if !s.Dirty() {
|
|
|
+ if !hostOf(s).Dirty() {
|
|
|
t.Error("not dirty after rename")
|
|
|
}
|
|
|
s.CloseWindow()
|
|
|
@@ -587,9 +596,53 @@ func TestLinkedFileIsMissing(t *testing.T) {
|
|
|
t.Skipf("cannot create a symlink: %v", err)
|
|
|
}
|
|
|
s, _ := newService()
|
|
|
- res, err := s.LoadPath(path)
|
|
|
+ res, err := hostOf(s).LoadPath(path)
|
|
|
must(t, err)
|
|
|
if st := res.State; st.MissingCount != 1 || !st.Pads[1].Missing {
|
|
|
t.Errorf("missing count %d, A2 missing %v; want 1, true", st.MissingCount, st.Pads[1].Missing)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// TestBoundMethods pins the methods the window can call. Wails binds every
|
|
|
+// exported method of Service by reflection, so each one is reachable from
|
|
|
+// any script in the window by name.
|
|
|
+func TestBoundMethods(t *testing.T) {
|
|
|
+ want := []string{
|
|
|
+ "About", "AddSequence", "AssignSampleDialog", "CancelExport",
|
|
|
+ "ChooseExportFolder", "ChooseZipPath", "ClearPad", "CloseWindow",
|
|
|
+ "CopyPad", "ExportFolder", "ExportZip", "Load", "MovePad", "New",
|
|
|
+ "RemoveSequence", "SetMuteGroup", "SetName", "SetSequence", "SetTune",
|
|
|
+ "State", "SwapPads",
|
|
|
+ }
|
|
|
+ typ := reflect.TypeOf(&Service{})
|
|
|
+ var got []string
|
|
|
+ for i := range typ.NumMethod() {
|
|
|
+ got = append(got, typ.Method(i).Name)
|
|
|
+ }
|
|
|
+ if strings.Join(got, ",") != strings.Join(want, ",") {
|
|
|
+ t.Errorf("Service's exported methods are\n %v\nwant\n %v\n"+
|
|
|
+ "Every exported method of Service can be called by any script in the window. "+
|
|
|
+ "A new one must not take a file path (Go-only methods belong on Host), "+
|
|
|
+ "and must be added to this list on purpose.", got, want)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestCancelExport(t *testing.T) {
|
|
|
+ // Declining "Replace existing files?" forgets the target, so a later
|
|
|
+ // overwrite cannot reach it without the dialog.
|
|
|
+ s, d := newService()
|
|
|
+ d.folder, d.zip = t.TempDir(), filepath.Join(t.TempDir(), "kit.zip")
|
|
|
+ _, err := s.ChooseExportFolder()
|
|
|
+ must(t, err)
|
|
|
+ _, err = s.ChooseZipPath()
|
|
|
+ must(t, err)
|
|
|
+ s.CancelExport()
|
|
|
+ for _, export := range []func(bool) (ExportResult, error){s.ExportFolder, s.ExportZip} {
|
|
|
+ if _, err := export(true); err == nil || err.Error() != "choose where to export first" {
|
|
|
+ t.Errorf("overwrite after cancel: %v", err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ents, _ := os.ReadDir(d.folder); len(ents) != 0 {
|
|
|
+ t.Errorf("export after cancel wrote %d entries", len(ents))
|
|
|
+ }
|
|
|
+}
|