1
1
package org .jabref .gui .groups ;
2
2
3
3
import java .util .EnumSet ;
4
+ import java .util .List ;
4
5
import java .util .Optional ;
5
6
6
7
import org .jabref .gui .DialogService ;
7
8
import org .jabref .gui .StateManager ;
8
9
import org .jabref .gui .preferences .GuiPreferences ;
9
10
import org .jabref .gui .util .CustomLocalDragboard ;
10
11
import org .jabref .logic .ai .AiService ;
12
+ import org .jabref .logic .l10n .Localization ;
11
13
import org .jabref .logic .util .CurrentThreadTaskExecutor ;
12
14
import org .jabref .logic .util .TaskExecutor ;
13
15
import org .jabref .model .database .BibDatabaseContext ;
17
19
import org .jabref .model .groups .AllEntriesGroup ;
18
20
import org .jabref .model .groups .ExplicitGroup ;
19
21
import org .jabref .model .groups .GroupHierarchyType ;
22
+ import org .jabref .model .groups .SearchGroup ;
20
23
import org .jabref .model .groups .WordKeywordGroup ;
24
+ import org .jabref .model .search .SearchFlags ;
21
25
22
26
import org .junit .jupiter .api .BeforeEach ;
23
27
import org .junit .jupiter .api .Test ;
24
28
import org .mockito .Answers ;
29
+ import org .mockito .ArgumentCaptor ;
30
+ import org .mockito .Mockito ;
25
31
26
32
import static org .junit .jupiter .api .Assertions .assertEquals ;
27
33
import static org .junit .jupiter .api .Assertions .assertFalse ;
28
34
import static org .junit .jupiter .api .Assertions .assertTrue ;
35
+ import static org .mockito .ArgumentMatchers .anyString ;
29
36
import static org .mockito .Mockito .mock ;
37
+ import static org .mockito .Mockito .times ;
38
+ import static org .mockito .Mockito .verify ;
30
39
import static org .mockito .Mockito .when ;
31
40
32
41
class GroupTreeViewModelTest {
33
42
34
43
private StateManager stateManager ;
35
44
private GroupTreeViewModel groupTree ;
36
45
private BibDatabaseContext databaseContext ;
46
+ private GroupNodeViewModel rootGroupViewModel ;
37
47
private TaskExecutor taskExecutor ;
38
48
private GuiPreferences preferences ;
39
49
private DialogService dialogService ;
@@ -53,6 +63,8 @@ void setUp() {
53
63
true ,
54
64
GroupHierarchyType .INDEPENDENT ));
55
65
groupTree = new GroupTreeViewModel (stateManager , mock (DialogService .class ), mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
66
+
67
+ rootGroupViewModel = groupTree .rootGroupProperty ().get ();
56
68
}
57
69
58
70
@ Test
@@ -139,4 +151,137 @@ void shouldShowDialogWhenCaseSensitivyDiffers() {
139
151
GroupTreeViewModel model = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
140
152
assertFalse (model .onlyMinorChanges (oldGroup , newGroup ));
141
153
}
154
+
155
+ @ Test
156
+ void addSuggestedSubGroupCreatesCorrectGroups () {
157
+ Mockito .reset (dialogService );
158
+
159
+ GroupTreeViewModel testGroupTree = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
160
+ GroupNodeViewModel testRootGroup = testGroupTree .rootGroupProperty ().get ();
161
+
162
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
163
+
164
+ verify (dialogService , times (2 )).notify (anyString ());
165
+
166
+ List <GroupNodeViewModel > children = testRootGroup .getChildren ();
167
+
168
+ assertEquals (2 , children .size ());
169
+
170
+ GroupNodeViewModel firstGroup = children .get (0 );
171
+ assertEquals (Localization .lang ("Entries without linked files" ), firstGroup .getDisplayName ());
172
+
173
+ GroupNodeViewModel secondGroup = children .get (1 );
174
+ assertEquals (Localization .lang ("Entries without groups" ), secondGroup .getDisplayName ());
175
+
176
+ AbstractGroup firstGroupObj = firstGroup .getGroupNode ().getGroup ();
177
+ assertTrue (firstGroupObj instanceof SearchGroup );
178
+ SearchGroup firstSearchGroup = (SearchGroup ) firstGroupObj ;
179
+ assertEquals ("file !=~.*" , firstSearchGroup .getSearchExpression ());
180
+ assertTrue (firstSearchGroup .getSearchFlags ().contains (SearchFlags .CASE_INSENSITIVE ));
181
+
182
+ AbstractGroup secondGroupObj = secondGroup .getGroupNode ().getGroup ();
183
+ assertTrue (secondGroupObj instanceof SearchGroup );
184
+ SearchGroup secondSearchGroup = (SearchGroup ) secondGroupObj ;
185
+ assertEquals ("groups !=~.*" , secondSearchGroup .getSearchExpression ());
186
+ assertTrue (secondSearchGroup .getSearchFlags ().contains (SearchFlags .CASE_INSENSITIVE ));
187
+ }
188
+
189
+ @ Test
190
+ void addSuggestedSubGroupDoesNotCreateDuplicateGroups () {
191
+ Mockito .reset (dialogService );
192
+
193
+ GroupTreeViewModel testGroupTree = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
194
+ GroupNodeViewModel testRootGroup = testGroupTree .rootGroupProperty ().get ();
195
+
196
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
197
+
198
+ Mockito .reset (dialogService );
199
+
200
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
201
+
202
+ ArgumentCaptor <String > messageCaptor = ArgumentCaptor .forClass (String .class );
203
+ verify (dialogService , times (1 )).notify (messageCaptor .capture ());
204
+ assertEquals (Localization .lang ("All suggested groups already exist." ), messageCaptor .getValue ());
205
+
206
+ List <GroupNodeViewModel > children = testRootGroup .getChildren ();
207
+ assertEquals (2 , children .size ());
208
+ }
209
+
210
+ @ Test
211
+ void addSuggestedSubGroupWritesChangesToMetaData () {
212
+ GroupTreeViewModel spyGroupTree = Mockito .spy (groupTree );
213
+
214
+ spyGroupTree .addSuggestedSubGroup (rootGroupViewModel );
215
+
216
+ verify (spyGroupTree ).writeGroupChangesToMetaData ();
217
+ }
218
+
219
+ @ Test
220
+ void addSuggestedSubGroupAddsOnlyMissingFilesGroup () {
221
+ Mockito .reset (dialogService );
222
+
223
+ GroupTreeViewModel testGroupTree = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
224
+ GroupNodeViewModel testRootGroup = testGroupTree .rootGroupProperty ().get ();
225
+
226
+ SearchGroup withoutGroupsGroup = new SearchGroup (
227
+ Localization .lang ("Entries without groups" ),
228
+ GroupHierarchyType .INDEPENDENT ,
229
+ "groups !=~.*" ,
230
+ EnumSet .of (SearchFlags .CASE_INSENSITIVE )
231
+ );
232
+ testRootGroup .addSubgroup (withoutGroupsGroup );
233
+
234
+ assertEquals (1 , testRootGroup .getChildren ().size ());
235
+
236
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
237
+
238
+ verify (dialogService , times (1 )).notify (anyString ());
239
+
240
+ List <GroupNodeViewModel > children = testRootGroup .getChildren ();
241
+ assertEquals (2 , children .size ());
242
+
243
+ boolean hasWithoutFilesGroup = children .stream ()
244
+ .anyMatch (group -> group .getDisplayName ().equals (Localization .lang ("Entries without linked files" )));
245
+ assertTrue (hasWithoutFilesGroup );
246
+ }
247
+
248
+ @ Test
249
+ void addSuggestedSubGroupAddsOnlyMissingGroupsGroup () {
250
+ Mockito .reset (dialogService );
251
+
252
+ GroupTreeViewModel testGroupTree = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
253
+ GroupNodeViewModel testRootGroup = testGroupTree .rootGroupProperty ().get ();
254
+
255
+ SearchGroup withoutFilesGroup = new SearchGroup (
256
+ Localization .lang ("Entries without linked files" ),
257
+ GroupHierarchyType .INDEPENDENT ,
258
+ "file !=~.*" ,
259
+ EnumSet .of (SearchFlags .CASE_INSENSITIVE )
260
+ );
261
+ testRootGroup .addSubgroup (withoutFilesGroup );
262
+
263
+ assertEquals (1 , testRootGroup .getChildren ().size ());
264
+
265
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
266
+
267
+ verify (dialogService , times (1 )).notify (anyString ());
268
+
269
+ List <GroupNodeViewModel > children = testRootGroup .getChildren ();
270
+ assertEquals (2 , children .size ());
271
+
272
+ boolean hasWithoutGroupsGroup = children .stream ()
273
+ .anyMatch (group -> group .getDisplayName ().equals (Localization .lang ("Entries without groups" )));
274
+ assertTrue (hasWithoutGroupsGroup );
275
+ }
276
+
277
+ @ Test
278
+ void addSuggestedSubGroupUpdatesSelectedGroups () {
279
+ GroupTreeViewModel testGroupTree = new GroupTreeViewModel (stateManager , dialogService , mock (AiService .class ), preferences , taskExecutor , new CustomLocalDragboard ());
280
+ GroupNodeViewModel testRootGroup = testGroupTree .rootGroupProperty ().get ();
281
+
282
+ testGroupTree .addSuggestedSubGroup (testRootGroup );
283
+
284
+ assertFalse (testGroupTree .selectedGroupsProperty ().isEmpty ());
285
+ assertEquals (2 , testGroupTree .selectedGroupsProperty ().size ());
286
+ }
142
287
}
0 commit comments