Dev #18
@@ -24,8 +24,10 @@ public class ExpenseChangeRequest {
|
||||
@NotBlank(message = "Owner name is required")
|
||||
private String ownerName;
|
||||
|
||||
// Same bounds as ExpenseInput: Quick Add creates stub expenses with amount 0
|
||||
// and no category, and those stubs must remain editable.
|
||||
@NotNull(message = "Amount is required")
|
||||
@DecimalMin(value = "0.01", message = "Amount must be greater than zero")
|
||||
@DecimalMin(value = "0.00", message = "Amount must not be negative")
|
||||
private Double amount;
|
||||
|
||||
private Double personalUseAmount;
|
||||
@@ -34,7 +36,6 @@ public class ExpenseChangeRequest {
|
||||
@NotNull(message = "Date is required")
|
||||
private LocalDate date;
|
||||
|
||||
@NotBlank(message = "Category is required")
|
||||
private String category;
|
||||
|
||||
public Expense convertToExpense(Long userId, ExpenseList expenseList) {
|
||||
@@ -51,7 +52,9 @@ public class ExpenseChangeRequest {
|
||||
expense.setId(id);
|
||||
expense.setOwner(appUser);
|
||||
expense.setTitle(title);
|
||||
expense.setCategory(category);
|
||||
// The edit dialog sends "" for a missing category; store null so the
|
||||
// stub state stays uniform and history diffs don't report null -> "".
|
||||
expense.setCategory(category == null || category.isBlank() ? null : category);
|
||||
|
||||
return expense;
|
||||
}
|
||||
|
||||
+48
@@ -53,6 +53,54 @@ class ExpenseListControllerTest {
|
||||
.andExpect(jsonPath("$.title").exists());
|
||||
}
|
||||
|
||||
// Quick Add creates stub expenses (amount 0, no category); updating such a
|
||||
// stub must be allowed so the user can fill in the details afterwards.
|
||||
@Test
|
||||
void updateExpense_quickAddStub_zeroAmountAndNoCategory_returns200() throws Exception {
|
||||
AppUser owner = new AppUser(); owner.setId(1L); owner.setUsername("alice");
|
||||
ExpenseList list = new ExpenseList(); list.setId(1L); list.setOwner(owner);
|
||||
when(expenseListService.findById(1L)).thenReturn(Optional.of(list));
|
||||
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(owner);
|
||||
when(expenseListService.updateExpense(eq(1L), any(Expense.class), eq(owner)))
|
||||
.thenAnswer(inv -> inv.getArgument(1));
|
||||
|
||||
mockMvc.perform(put("/api/expenselist/1/update")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"id\":42,\"title\":\"Groceries\",\"ownerName\":\"alice\",\"amount\":0.0,"
|
||||
+ "\"personalUseAmount\":0.0,\"otherPersonAmount\":0.0,\"date\":\"2026-07-06\"}"))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateExpense_blankCategory_isStoredAsNull() throws Exception {
|
||||
AppUser owner = new AppUser(); owner.setId(1L); owner.setUsername("alice");
|
||||
ExpenseList list = new ExpenseList(); list.setId(1L); list.setOwner(owner);
|
||||
when(expenseListService.findById(1L)).thenReturn(Optional.of(list));
|
||||
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(owner);
|
||||
when(expenseListService.updateExpense(eq(1L), any(Expense.class), eq(owner)))
|
||||
.thenAnswer(inv -> inv.getArgument(1));
|
||||
|
||||
mockMvc.perform(put("/api/expenselist/1/update")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"id\":42,\"title\":\"Groceries\",\"ownerName\":\"alice\",\"amount\":0.0,"
|
||||
+ "\"personalUseAmount\":0.0,\"otherPersonAmount\":0.0,\"date\":\"2026-07-06\",\"category\":\"\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
org.mockito.ArgumentCaptor<Expense> captor = org.mockito.ArgumentCaptor.forClass(Expense.class);
|
||||
org.mockito.Mockito.verify(expenseListService).updateExpense(eq(1L), captor.capture(), eq(owner));
|
||||
org.assertj.core.api.Assertions.assertThat(captor.getValue().getCategory()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateExpense_negativeAmount_returns400() throws Exception {
|
||||
mockMvc.perform(put("/api/expenselist/1/update")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"id\":42,\"title\":\"Groceries\",\"ownerName\":\"alice\",\"amount\":-5.0,"
|
||||
+ "\"personalUseAmount\":0.0,\"otherPersonAmount\":0.0,\"date\":\"2026-07-06\",\"category\":\"Food\"}"))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.amount").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addExpense_negativeAmount_returns400() throws Exception {
|
||||
mockMvc.perform(post("/api/expenselist/1/add")
|
||||
|
||||
Reference in New Issue
Block a user