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")
}
}