15
15
import com .jongsoft .finance .domain .user .Role ;
16
16
import com .jongsoft .finance .domain .user .UserAccount ;
17
17
import com .jongsoft .finance .factory .FilterFactory ;
18
+ import com .jongsoft .finance .messaging .EventBus ;
19
+ import com .jongsoft .finance .messaging .commands .budget .CreateBudgetCommand ;
18
20
import com .jongsoft .finance .messaging .commands .transaction .CreateTransactionCommand ;
19
21
import com .jongsoft .finance .messaging .handlers .TransactionCreationHandler ;
20
22
import com .jongsoft .finance .providers .*;
24
26
import com .jongsoft .lang .Control ;
25
27
import com .jongsoft .lang .control .Optional ;
26
28
import io .micronaut .context .ApplicationContext ;
29
+ import io .micronaut .context .event .ApplicationEventPublisher ;
27
30
import io .micronaut .core .reflect .ReflectionUtils ;
28
31
import lombok .extern .slf4j .Slf4j ;
29
32
import org .apache .commons .lang3 .mutable .MutableLong ;
36
39
import org .mockito .stubbing .OngoingStubbing ;
37
40
38
41
import java .math .BigDecimal ;
39
- import java .util .ArrayList ;
40
- import java .util .List ;
41
- import java .util .Map ;
42
- import java .util .UUID ;
42
+ import java .time .LocalDate ;
43
+ import java .util .*;
43
44
import java .util .function .Consumer ;
44
45
45
46
@ Slf4j
46
47
public class RuntimeContext {
47
48
48
49
private ApplicationContext applicationContext ;
50
+ private ApplicationEventPublisher applicationEventPublisher ;
49
51
50
52
private ProcessEngine processEngine ;
51
53
52
54
private UserAccount userAccount ;
53
55
54
56
private final List <String > storageTokens ;
55
57
private final MutableLong idGenerator ;
58
+ private final List <Budget > registeredBudgets ;
56
59
57
60
public RuntimeContext (ApplicationContext applicationContext ) {
58
61
this .applicationContext = applicationContext ;
@@ -64,14 +67,17 @@ public RuntimeContext(ApplicationContext applicationContext) {
64
67
.roles (Collections .List (new Role ("admin" )))
65
68
.build ());
66
69
this .processEngine = applicationContext .getBean (ProcessEngine .class );
70
+ this .applicationEventPublisher = Mockito .spy (applicationContext .getBean (ApplicationEventPublisher .class ));
67
71
idGenerator = new MutableLong (100 );
72
+ registeredBudgets = new ArrayList <>();
68
73
69
74
setupDefaultMocks ();
70
75
}
71
76
72
77
void clean () {
73
78
processEngine .close ();
74
79
storageTokens .clear ();
80
+ registeredBudgets .clear ();
75
81
}
76
82
77
83
public RuntimeContext withStorage () {
@@ -98,6 +104,34 @@ public RuntimeContext withStorage(String token, String resource) {
98
104
return this ;
99
105
}
100
106
107
+ @ SuppressWarnings ("unchecked" )
108
+ public RuntimeContext withBudgets () {
109
+ var budgetProvider = applicationContext .getBean (BudgetProvider .class );
110
+ Mockito .when (budgetProvider .lookup (Mockito .anyInt (), Mockito .anyInt ()))
111
+ .thenAnswer (invocation -> {
112
+ var date = LocalDate .of (invocation .getArgument (0 ), invocation .getArgument (1 , Integer .class ), 1 );
113
+
114
+ return Control .Option (registeredBudgets .stream ()
115
+ .filter (budget -> budget .getStart ().isBefore (date ) || budget .getStart ().isEqual (date ))
116
+ .max (Comparator .comparing (Budget ::getStart ))
117
+ .orElse (null ));
118
+ });
119
+
120
+ Mockito .doAnswer ((Answer <Void >) invocation -> {
121
+ var createCommand = invocation .getArgument (0 , CreateBudgetCommand .class );
122
+
123
+ var budget = Budget .builder ()
124
+ .start (createCommand .budget ().getStart ())
125
+ .expectedIncome (createCommand .budget ().getExpectedIncome ())
126
+ .id (idGenerator .getAndIncrement ())
127
+ .expenses (Collections .List ())
128
+ .build ();
129
+ registeredBudgets .add (budget );
130
+ return null ;
131
+ }).when (applicationEventPublisher ).publishEvent (Mockito .any (CreateBudgetCommand .class ));
132
+ return this ;
133
+ }
134
+
101
135
public RuntimeContext withBudget (int year , int month , Budget budget ) {
102
136
var budgetProvider = applicationContext .getBean (BudgetProvider .class );
103
137
Mockito .when (budgetProvider .lookup (year , month ))
@@ -232,12 +266,24 @@ public RuntimeContext verifyAccountCreated(String name, String currency, String
232
266
return this ;
233
267
}
234
268
269
+ /**
270
+ * Verifies if a category with the specified name has been created.
271
+ *
272
+ * @param name the name of the category to be verified
273
+ * @return the current RuntimeContext instance
274
+ */
235
275
public RuntimeContext verifyCategoryCreated (String name ) {
236
276
Mockito .verify (userAccount , Mockito .atMostOnce ())
237
277
.createCategory (name );
238
278
return this ;
239
279
}
240
280
281
+ /**
282
+ * Verifies the transactions by performing validations provided by the consumer.
283
+ *
284
+ * @param validations the consumer that accepts a ListAssert<Transaction> for performing validations
285
+ * @return the RuntimeContext instance
286
+ */
241
287
public RuntimeContext verifyTransactions (Consumer <ListAssert <Transaction >> validations ) {
242
288
var createdTransactions = Mockito .mockingDetails (applicationContext .getBean (TransactionCreationHandler .class )).getInvocations ().stream ()
243
289
.filter (invocation -> invocation .getMethod ().getName ().equals ("handleCreatedEvent" ))
@@ -250,12 +296,34 @@ public RuntimeContext verifyTransactions(Consumer<ListAssert<Transaction>> valid
250
296
return this ;
251
297
}
252
298
299
+ /**
300
+ * Verifies that all storage tokens have been cleaned.
301
+ *
302
+ * @return The RuntimeContext object.
303
+ */
253
304
public RuntimeContext verifyStorageCleaned () {
254
305
storageTokens .forEach (token ->
255
306
Mockito .verify (applicationContext .getBean (StorageService .class )).remove (token ));
256
307
return this ;
257
308
}
258
309
310
+ /**
311
+ * Verifies the budget for the specified start date.
312
+ *
313
+ * @param startDate the start date of the budget to verify
314
+ * @param validations the consumer function that performs assertions on the budget
315
+ * @return the current RuntimeContext object
316
+ */
317
+ public RuntimeContext verifyBudget (LocalDate startDate , Consumer <ObjectAssert <Budget >> validations ) {
318
+ validations .accept (
319
+ Assertions .assertThat (registeredBudgets .stream ()
320
+ .filter (budget -> budget .getStart ().equals (startDate ))
321
+ .findFirst ()
322
+ .orElseThrow (() -> new AssertionError ("Budget not found for start date: " + startDate )))
323
+ .as ("Budget created for start date: " + startDate ));
324
+ return this ;
325
+ }
326
+
259
327
public RuntimeContext verifyRuleCreated (String name , Consumer <ObjectAssert <TransactionRule >> validations ) {
260
328
var matchedRule = Mockito .mockingDetails (applicationContext .getBean (TransactionRuleProvider .class ))
261
329
.getInvocations ().stream ()
@@ -282,6 +350,7 @@ public <T> T verifyInteraction(Class<T> type) {
282
350
283
351
void resetMocks () {
284
352
Mockito .reset (
353
+ applicationContext .getBean (BudgetProvider .class ),
285
354
applicationContext .getBean (AuthenticationFacade .class ),
286
355
applicationContext .getBean (CurrentUserProvider .class ),
287
356
applicationContext .getBean (AccountProvider .class ),
@@ -303,6 +372,8 @@ private void setupDefaultMocks() {
303
372
Mockito .when (applicationContext .getBean (CurrentUserProvider .class ).currentUser ())
304
373
.thenReturn (userAccount );
305
374
375
+ new EventBus (applicationEventPublisher );
376
+
306
377
// Prepare the mocks for the filter factory
307
378
var filterFactory = applicationContext .getBean (FilterFactory .class );
308
379
Mockito .when (filterFactory .account ()).thenReturn (Mockito .mock (AccountProvider .FilterCommand .class , Mockito .RETURNS_DEEP_STUBS ));
0 commit comments