package cli import ( "bytes" "context" "intake/internal/audio" "intake/internal/plan" "intake/internal/scan" "os" "path/filepath" "strings" "testing" "intake/internal/artist" "intake/internal/config" ) func TestDryRunDoesNotWriteAliases(t *testing.T) { root := t.TempDir() var errBuf bytes.Buffer a := &App{ Cfg: config.Config{Root: root}, DryRun: true, Err: &errBuf, Out: &bytes.Buffer{}, } ix := artist.NewIndex() a.rememberAlias(ix, "Some Credit", "some-folder") path := artist.AliasPath(root) if _, err := os.Stat(path); !os.IsNotExist(err) { t.Fatalf("a dry run wrote %s", path) } if got := ix.Alias["Some Credit"]; got != "some-folder" { t.Errorf("in-memory alias = %q, want %q", got, "some-folder") } } func TestAliasesAreWrittenNormally(t *testing.T) { root := t.TempDir() a := &App{ Cfg: config.Config{Root: root}, Err: &bytes.Buffer{}, Out: &bytes.Buffer{}, } ix := artist.NewIndex() a.rememberAlias(ix, "Some Credit", "some-folder") if _, err := os.Stat(artist.AliasPath(root)); err != nil { t.Fatalf("aliases were not saved: %v", err) } reloaded := artist.NewIndex() if err := reloaded.LoadAliases(artist.AliasPath(root)); err != nil { t.Fatal(err) } if got := reloaded.Alias["Some Credit"]; got != "some-folder" { t.Errorf("reloaded alias = %q, want %q", got, "some-folder") } _ = filepath.Join } // An album that files and then cannot be recorded is worse than one that never // files: it lands in the archive untracked, so verify and audit skip it and a // later run offers to file it again. The journal is proved writable before the // first byte is copied, and that has to happen before anything is created. func TestFilingRefusesWhenTheJournalCannotBeWritten(t *testing.T) { root := t.TempDir() // A file where the state directory needs to be, so creating it fails. blocker := filepath.Join(root, "blocked") if err := os.WriteFile(blocker, []byte("not a directory"), 0o600); err != nil { t.Fatal(err) } a := &App{ Cfg: config.Config{Root: root, StateDir: filepath.Join(blocker, "state")}, Out: &bytes.Buffer{}, Err: &bytes.Buffer{}, } archive := filepath.Join(root, "archive", "an-artist", "an-album") _, err := a.FilePlan(context.Background(), plan.Plan{ArchiveDir: archive}, coverChoice{}, "") if err == nil { t.Fatal("filing should have been refused") } if !strings.Contains(err.Error(), "journal") { t.Errorf("the refusal should name the journal: %v", err) } if _, statErr := os.Stat(filepath.Join(root, "archive")); !os.IsNotExist(statErr) { t.Error("the archive was created even though the journal could not be written") } } // --yes is for unattended runs. A name that cannot be worked out used to send it // into the editor anyway, which waits for somebody who is not there and hangs // the whole batch on that album forever. func TestYesRefusesRatherThanOpeningTheEditor(t *testing.T) { root := t.TempDir() marker := filepath.Join(root, "editor-ran") script := filepath.Join(root, "editor.sh") if err := os.WriteFile(script, []byte("#!/bin/sh\ntouch "+marker+"\n"), 0o755); err != nil { t.Fatal(err) } cfg := config.Defaults() cfg.Root = root cfg.StagingDir = "staging" cfg.ArchiveDir = "archive" cfg.LibraryDir = "library" cfg.StateDir = filepath.Join(root, "state") cfg.Editor = script var out, errBuf bytes.Buffer a := &App{Cfg: cfg, Yes: true, Out: &out, Err: &errBuf} album := scan.Album{ Name: "nameless", Dir: filepath.Join(root, "staging", "nameless"), Status: scan.StatusReady, // no tags at all, and a folder name with no separator to infer from Tracks: []audio.Track{{ Path: filepath.Join(root, "staging", "nameless", "01 untitled.flac"), Ext: ".flac", }}, } if err := a.process(context.Background(), album); err == nil { t.Fatal("--yes should have refused an album whose names cannot be worked out") } if _, statErr := os.Stat(marker); !os.IsNotExist(statErr) { t.Error("the editor was opened under --yes, which is what hangs an unattended run") } }