Files
arnefandCopilot ae46e8f5c0 Replace config file with folder-based mapping
Mappings between local playlist folders and Kreativ-Tonies are now
expressed purely through the filesystem instead of a YAML config:

  <root>/<household_id>/<freier_name> [id=<tonie_id>]/*.mp3

- internal/library: discovers tonie folders from this structure
  (Discover/Filter), and scaffolds it automatically from the
  TonieCloud account (Scaffold), leaving already-existing folders
  (matched by tonie id) untouched
- internal/syncer: decoupled from the removed config package via a
  plain Target{TonieID, Folder, Prune} struct
- cmd/toni-sync: new `init --root PATH` command to scaffold the
  library; `sync [FILTER] --root PATH` now discovers targets from the
  folder tree instead of a config file; removed the `config` command
  group entirely
- Unit tests for folder discovery, filtering, and scaffolding

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-14 12:02:54 +02:00

81 lines
2.3 KiB
Go

package library
import (
"os"
"path/filepath"
"testing"
"github.com/arnef/toni-sync/internal/tonieapi"
)
type fakeScaffoldClient struct {
households []tonieapi.Household
toniesByHouse map[string][]tonieapi.CreativeTonie
}
func (f *fakeScaffoldClient) GetHouseholds() ([]tonieapi.Household, error) {
return f.households, nil
}
func (f *fakeScaffoldClient) GetCreativeTonies(householdID string) ([]tonieapi.CreativeTonie, error) {
return f.toniesByHouse[householdID], nil
}
func TestScaffoldCreatesFolders(t *testing.T) {
root := t.TempDir()
client := &fakeScaffoldClient{
households: []tonieapi.Household{{ID: "h1", Name: "Family"}},
toniesByHouse: map[string][]tonieapi.CreativeTonie{
"h1": {{ID: "t1", HouseholdID: "h1", Name: "Peppa Wutz"}},
},
}
results, err := Scaffold(client, root)
if err != nil {
t.Fatal(err)
}
if len(results) != 1 || !results[0].Created {
t.Fatalf("expected 1 created result, got %+v", results)
}
expected := filepath.Join(root, "h1", "Peppa Wutz [id=t1]")
if info, err := os.Stat(expected); err != nil || !info.IsDir() {
t.Fatalf("expected folder %s to exist: %v", expected, err)
}
}
func TestScaffoldLeavesExistingFolderUntouched(t *testing.T) {
root := t.TempDir()
// Simulate an existing folder that was renamed locally but keeps the id suffix.
existing := filepath.Join(root, "h1", "My Custom Name [id=t1]")
if err := os.MkdirAll(existing, 0o755); err != nil {
t.Fatal(err)
}
// Put a marker file inside to make sure Scaffold doesn't touch it.
marker := filepath.Join(existing, "song.mp3")
if err := os.WriteFile(marker, []byte("data"), 0o644); err != nil {
t.Fatal(err)
}
client := &fakeScaffoldClient{
households: []tonieapi.Household{{ID: "h1", Name: "Family"}},
toniesByHouse: map[string][]tonieapi.CreativeTonie{
"h1": {{ID: "t1", HouseholdID: "h1", Name: "Peppa Wutz (renamed in cloud)"}},
},
}
results, err := Scaffold(client, root)
if err != nil {
t.Fatal(err)
}
if len(results) != 1 || results[0].Created {
t.Fatalf("expected existing folder to be reported as not created, got %+v", results)
}
if results[0].Folder != existing {
t.Fatalf("expected folder %s, got %s", existing, results[0].Folder)
}
if _, err := os.Stat(marker); err != nil {
t.Fatalf("expected local file to remain untouched: %v", err)
}
}