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>
81 lines
2.3 KiB
Go
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)
|
|
}
|
|
}
|