v0.23.2 bfd5eb4

manage_favorites_test.go RawHistoryFolder

1package usecase_test
2
3import (
4	"errors"
5	"testing"
6
7	"github.com/bnema/dumber/internal/application/usecase"
8	"github.com/bnema/dumber/internal/domain/entity"
9	repomocks "github.com/bnema/dumber/internal/domain/repository/mocks"
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/mock"
12	"github.com/stretchr/testify/require"
13)
14
15func TestManageFavoritesUseCase_GetAllURLs_ReturnsURLSet(t *testing.T) {
16	ctx := testContext()
17
18	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
19	folderRepo := repomocks.NewMockFolderRepository(t)
20	tagRepo := repomocks.NewMockTagRepository(t)
21
22	favorites := []*entity.Favorite{
23		{ID: 1, URL: "https://example.com"},
24		{ID: 2, URL: "https://github.com"},
25		{ID: 3, URL: "https://google.com"},
26	}
27
28	favoriteRepo.EXPECT().GetAll(mock.Anything).Return(favorites, nil)
29
30	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
31
32	urls, err := uc.GetAllURLs(ctx)
33	require.NoError(t, err)
34	require.NotNil(t, urls)
35
36	assert.Len(t, urls, 3)
37	_, hasExample := urls["https://example.com"]
38	_, hasGithub := urls["https://github.com"]
39	_, hasGoogle := urls["https://google.com"]
40	assert.True(t, hasExample)
41	assert.True(t, hasGithub)
42	assert.True(t, hasGoogle)
43}
44
45func TestManageFavoritesUseCase_GetAllURLs_ReturnsEmptySetWhenNoFavorites(t *testing.T) {
46	ctx := testContext()
47
48	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
49	folderRepo := repomocks.NewMockFolderRepository(t)
50	tagRepo := repomocks.NewMockTagRepository(t)
51
52	favoriteRepo.EXPECT().GetAll(mock.Anything).Return([]*entity.Favorite{}, nil)
53
54	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
55
56	urls, err := uc.GetAllURLs(ctx)
57	require.NoError(t, err)
58	require.NotNil(t, urls)
59	assert.Empty(t, urls)
60}
61
62func TestManageFavoritesUseCase_GetAllURLs_ReturnsErrorOnRepoFailure(t *testing.T) {
63	ctx := testContext()
64
65	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
66	folderRepo := repomocks.NewMockFolderRepository(t)
67	tagRepo := repomocks.NewMockTagRepository(t)
68
69	favoriteRepo.EXPECT().GetAll(mock.Anything).Return(nil, errors.New("db connection failed"))
70
71	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
72
73	urls, err := uc.GetAllURLs(ctx)
74	require.Error(t, err)
75	assert.Nil(t, urls)
76	assert.Contains(t, err.Error(), "failed to get favorites")
77}
78
79func TestManageFavoritesUseCase_Toggle_AddsWhenNotFavorite(t *testing.T) {
80	ctx := testContext()
81
82	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
83	folderRepo := repomocks.NewMockFolderRepository(t)
84	tagRepo := repomocks.NewMockTagRepository(t)
85
86	// URL is not a favorite
87	favoriteRepo.EXPECT().FindByURL(mock.Anything, "https://example.com").Return(nil, nil)
88	favoriteRepo.EXPECT().Save(mock.Anything, mock.MatchedBy(func(f *entity.Favorite) bool {
89		return f.URL == "https://example.com" && f.Title == "Example"
90	})).Return(nil)
91
92	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
93
94	result, err := uc.Toggle(ctx, "https://example.com", "Example")
95	require.NoError(t, err)
96	require.NotNil(t, result)
97
98	assert.True(t, result.Added)
99	assert.Equal(t, "https://example.com", result.URL)
100	assert.Equal(t, "Example", result.Title)
101	assert.Equal(t, "Favorite added", result.Message)
102}
103
104func TestManageFavoritesUseCase_Toggle_RemovesWhenAlreadyFavorite(t *testing.T) {
105	ctx := testContext()
106
107	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
108	folderRepo := repomocks.NewMockFolderRepository(t)
109	tagRepo := repomocks.NewMockTagRepository(t)
110
111	existingFav := &entity.Favorite{
112		ID:    42,
113		URL:   "https://example.com",
114		Title: "Example Site",
115	}
116
117	// URL is already a favorite
118	favoriteRepo.EXPECT().FindByURL(mock.Anything, "https://example.com").Return(existingFav, nil)
119	favoriteRepo.EXPECT().Delete(mock.Anything, entity.FavoriteID(42)).Return(nil)
120
121	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
122
123	result, err := uc.Toggle(ctx, "https://example.com", "Example")
124	require.NoError(t, err)
125	require.NotNil(t, result)
126
127	assert.False(t, result.Added)
128	assert.Equal(t, "https://example.com", result.URL)
129	assert.Equal(t, "Example Site", result.Title) // Uses existing title
130	assert.Equal(t, "Favorite removed", result.Message)
131}
132
133func TestManageFavoritesUseCase_Toggle_EmptyURLReturnsError(t *testing.T) {
134	ctx := testContext()
135
136	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
137	folderRepo := repomocks.NewMockFolderRepository(t)
138	tagRepo := repomocks.NewMockTagRepository(t)
139
140	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
141
142	result, err := uc.Toggle(ctx, "", "Title")
143	require.Error(t, err)
144	assert.Nil(t, result)
145	assert.Contains(t, err.Error(), "URL cannot be empty")
146}
147
148func TestManageFavoritesUseCase_Toggle_FindByURLErrorReturnsError(t *testing.T) {
149	ctx := testContext()
150
151	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
152	folderRepo := repomocks.NewMockFolderRepository(t)
153	tagRepo := repomocks.NewMockTagRepository(t)
154
155	favoriteRepo.EXPECT().FindByURL(mock.Anything, "https://example.com").Return(nil, errors.New("db error"))
156
157	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
158
159	result, err := uc.Toggle(ctx, "https://example.com", "Example")
160	require.Error(t, err)
161	assert.Nil(t, result)
162	assert.Contains(t, err.Error(), "failed to check existing favorite")
163}
164
165func TestManageFavoritesUseCase_Toggle_SaveErrorReturnsError(t *testing.T) {
166	ctx := testContext()
167
168	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
169	folderRepo := repomocks.NewMockFolderRepository(t)
170	tagRepo := repomocks.NewMockTagRepository(t)
171
172	favoriteRepo.EXPECT().FindByURL(mock.Anything, "https://example.com").Return(nil, nil)
173	favoriteRepo.EXPECT().Save(mock.Anything, mock.Anything).Return(errors.New("db error"))
174
175	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
176
177	result, err := uc.Toggle(ctx, "https://example.com", "Example")
178	require.Error(t, err)
179	assert.Nil(t, result)
180	assert.Contains(t, err.Error(), "failed to add favorite")
181}
182
183func TestManageFavoritesUseCase_Toggle_DeleteErrorReturnsError(t *testing.T) {
184	ctx := testContext()
185
186	favoriteRepo := repomocks.NewMockFavoriteRepository(t)
187	folderRepo := repomocks.NewMockFolderRepository(t)
188	tagRepo := repomocks.NewMockTagRepository(t)
189
190	existingFav := &entity.Favorite{ID: 42, URL: "https://example.com", Title: "Example"}
191	favoriteRepo.EXPECT().FindByURL(mock.Anything, "https://example.com").Return(existingFav, nil)
192	favoriteRepo.EXPECT().Delete(mock.Anything, entity.FavoriteID(42)).Return(errors.New("db error"))
193
194	uc := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
195
196	result, err := uc.Toggle(ctx, "https://example.com", "Example")
197	require.Error(t, err)
198	assert.Nil(t, result)
199	assert.Contains(t, err.Error(), "failed to remove favorite")
200}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close