package repo import ( "context" "encoding/json" "testing" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/stretchr/testify/assert" ) func locationFactory() LocationCreate { return LocationCreate{ Name: fk.Str(10), Description: fk.Str(100), } } func useLocations(t *testing.T, len int) []LocationOut { t.Helper() out := make([]LocationOut, len) for i := 0; i < len; i++ { loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) assert.NoError(t, err) out[i] = loc } t.Cleanup(func() { for _, loc := range out { err := tRepos.Locations.delete(context.Background(), loc.ID) if err != nil { assert.True(t, ent.IsNotFound(err)) } } }) return out } func TestLocationRepository_Get(t *testing.T) { loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) assert.NoError(t, err) // Get by ID foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) assert.NoError(t, err) assert.Equal(t, loc.ID, foundLoc.ID) err = tRepos.Locations.delete(context.Background(), loc.ID) assert.NoError(t, err) } func TestLocationRepositoryGetAllWithCount(t *testing.T) { ctx := context.Background() result := useLocations(t, 1)[0] _, err := tRepos.Items.Create(ctx, tGroup.ID, ItemCreate{ Name: fk.Str(10), Description: fk.Str(100), LocationID: result.ID, }) assert.NoError(t, err) results, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID, LocationQuery{}) assert.NoError(t, err) for _, loc := range results { if loc.ID == result.ID { assert.Equal(t, 1, loc.ItemCount) } } } func TestLocationRepository_Create(t *testing.T) { loc := useLocations(t, 1)[0] // Get by ID foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) assert.NoError(t, err) assert.Equal(t, loc.ID, foundLoc.ID) err = tRepos.Locations.delete(context.Background(), loc.ID) assert.NoError(t, err) } func TestLocationRepository_Update(t *testing.T) { loc := useLocations(t, 1)[0] updateData := LocationUpdate{ ID: loc.ID, Name: fk.Str(10), Description: fk.Str(100), } update, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, updateData.ID, updateData) assert.NoError(t, err) foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) assert.NoError(t, err) assert.Equal(t, update.ID, foundLoc.ID) assert.Equal(t, update.Name, foundLoc.Name) assert.Equal(t, update.Description, foundLoc.Description) err = tRepos.Locations.delete(context.Background(), loc.ID) assert.NoError(t, err) } func TestLocationRepository_Delete(t *testing.T) { loc := useLocations(t, 1)[0] err := tRepos.Locations.delete(context.Background(), loc.ID) assert.NoError(t, err) _, err = tRepos.Locations.Get(context.Background(), loc.ID) assert.Error(t, err) } func TestItemRepository_TreeQuery(t *testing.T) { locs := useLocations(t, 3) // Set relations _, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, locs[0].ID, LocationUpdate{ ID: locs[0].ID, ParentID: locs[1].ID, Name: locs[0].Name, Description: locs[0].Description, }) assert.NoError(t, err) locations, err := tRepos.Locations.Tree(context.Background(), tGroup.ID, TreeQuery{WithItems: true}) assert.NoError(t, err) assert.Equal(t, 2, len(locations)) // Check roots for _, loc := range locations { if loc.ID == locs[1].ID { assert.Equal(t, 1, len(loc.Children)) } } } func TestLocationRepository_PathForLoc(t *testing.T) { locs := useLocations(t, 3) // Set relations 3 -> 2 -> 1 for i := 0; i < 2; i++ { _, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, locs[i].ID, LocationUpdate{ ID: locs[i].ID, ParentID: locs[i+1].ID, Name: locs[i].Name, Description: locs[i].Description, }) assert.NoError(t, err) } last := locs[0] path, err := tRepos.Locations.PathForLoc(context.Background(), tGroup.ID, last.ID) assert.NoError(t, err) assert.Equal(t, 3, len(path)) // Check path and order for i, loc := range path { assert.Equal(t, locs[2-i].ID, loc.ID) assert.Equal(t, locs[2-i].Name, loc.Name) } } func TestConvertLocationsToTree(t *testing.T) { uuid1, uuid2, uuid3, uuid4 := uuid.New(), uuid.New(), uuid.New(), uuid.New() testCases := []struct { name string locations []FlatTreeItem expected []TreeItem }{ { name: "Convert locations to tree", locations: []FlatTreeItem{ { ID: uuid1, Name: "Root1", ParentID: uuid.Nil, Level: 0, }, { ID: uuid2, Name: "Child1", ParentID: uuid1, Level: 1, }, { ID: uuid3, Name: "Child2", ParentID: uuid1, Level: 1, }, }, expected: []TreeItem{ { ID: uuid1, Name: "Root1", Children: []*TreeItem{ { ID: uuid2, Name: "Child1", Children: []*TreeItem{}, }, { ID: uuid3, Name: "Child2", Children: []*TreeItem{}, }, }, }, }, }, { name: "Convert locations to tree with deeply nested children", locations: []FlatTreeItem{ { ID: uuid1, Name: "Root1", ParentID: uuid.Nil, Level: 0, }, { ID: uuid2, Name: "Child1", ParentID: uuid1, Level: 1, }, { ID: uuid3, Name: "Child2", ParentID: uuid2, Level: 2, }, { ID: uuid4, Name: "Child3", ParentID: uuid3, Level: 3, }, }, expected: []TreeItem{ { ID: uuid1, Name: "Root1", Children: []*TreeItem{ { ID: uuid2, Name: "Child1", Children: []*TreeItem{ { ID: uuid3, Name: "Child2", Children: []*TreeItem{ { ID: uuid4, Name: "Child3", Children: []*TreeItem{}, }, }, }, }, }, }, }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := ConvertLocationsToTree(tc.locations) // Compare JSON strings expected, _ := json.Marshal(tc.expected) got, _ := json.Marshal(result) assert.Equal(t, string(expected), string(got)) }) } }