diff --git a/src/main/java/idatt2106/systemutvikling/sparesti/controller/ChallengeController.java b/src/main/java/idatt2106/systemutvikling/sparesti/controller/ChallengeController.java index 09e9f58eb1b36eee3c4e6723aace411a40e43626..d7291a29bbf10f4a8d1e9564f843658c1fe6d6a5 100644 --- a/src/main/java/idatt2106/systemutvikling/sparesti/controller/ChallengeController.java +++ b/src/main/java/idatt2106/systemutvikling/sparesti/controller/ChallengeController.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.AllArgsConstructor; +import lombok.NonNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -200,20 +201,16 @@ public class ChallengeController { ) @PostMapping("/activate/{challengeId}") @ResponseBody - public ResponseEntity<ChallengeDTO> activateChallenge(@PathVariable Long challengeId) { + public ResponseEntity<ChallengeDTO> activateChallenge(@PathVariable @NonNull Long challengeId) { - if (challengeId == null) { - return ResponseEntity.badRequest().build(); - } - - if (challengeService.getChallenge(challengeId).isActive()) { + // Verify that the challenge is inactive + if (challengeService.getChallenge(challengeId).isActive()) return ResponseEntity.badRequest().body(challengeService.getChallenge(challengeId)); - } + // if (!challengeService.getChallenge(challengeId).getUsername() - .equals(CurrentUserService.getCurrentUsername())) { + .equals(CurrentUserService.getCurrentUsername())) return ResponseEntity.badRequest().body(challengeService.getChallenge(challengeId)); - } return ResponseEntity.ok() .body(ChallengeMapper.toDTO(challengeService.activateChallenge(challengeId))); @@ -250,40 +247,22 @@ public class ChallengeController { ) @PostMapping("/complete") @ResponseBody - public ResponseEntity<String> completeChallenge(@RequestParam("challengeId") Long challengeId, - @RequestParam("milestoneId") Long milestoneId) { - if (challengeId == null) { - return ResponseEntity.badRequest().build(); - } + public ResponseEntity<String> completeChallenge(@RequestParam("challengeId") @NonNull Long challengeId, + @RequestParam("milestoneId") @NonNull Long milestoneId) { + // Verify ownership of the requested challenge if (!challengeService.getChallenge(challengeId).getUsername() - .equals(CurrentUserService.getCurrentUsername())) { + .equals(CurrentUserService.getCurrentUsername())) return ResponseEntity.badRequest().body("You are not the owner of this challenge"); - } - - if (milestoneId == null) { - return ResponseEntity.badRequest().build(); - } + // Verify ownership of the requested milestone if (!milestoneService.getMilestoneDTOById(milestoneId).getUsername() - .equals(CurrentUserService.getCurrentUsername())) { + .equals(CurrentUserService.getCurrentUsername())) return ResponseEntity.badRequest().body("You are not the owner of this milestone"); - } - - Long achievedSum = challengeService.getChallenge(challengeId).getGoalSum(); - Long milestoneCurrentSum = milestoneService.getMilestoneDTOById(milestoneId) - .getMilestoneCurrentSum(); - long targetSum = achievedSum + milestoneCurrentSum; - - milestoneService.increaseMilestonesCurrentSum(milestoneId, achievedSum); - - if (targetSum > milestoneService.getMilestoneDTOById(milestoneId) - .getMilestoneCurrentSum()) { - return ResponseEntity.badRequest().body("Could not transfer money to milestone"); - } - - challengeService.completeChallenge(challengeId); + // Perform requested operation + challengeService.completeChallengeForCurrentUser(challengeId, milestoneId); + // Return 200 OK return ResponseEntity.ok().body("Challenge completed"); } @@ -315,16 +294,12 @@ public class ChallengeController { )}) @DeleteMapping("/delete/{challengeId}") @ResponseBody - public ResponseEntity<String> moveChallengeToLog(@PathVariable Long challengeId) { - if (challengeId == null) { - return ResponseEntity.badRequest().build(); - } - - if (!challengeService.getChallenge(challengeId).getUsername() - .equals(CurrentUserService.getCurrentUsername())) { + public ResponseEntity<String> moveChallengeToLog(@PathVariable @NonNull Long challengeId) { + // Verify ownership of the challenge + if (!challengeService.getChallenge(challengeId).getUsername().equals(CurrentUserService.getCurrentUsername())) return ResponseEntity.badRequest().body("You are not the owner of this challenge"); - } + // Perform the service layer function challengeService.moveChallengeToLog(challengeId); return ResponseEntity.ok().body("Challenge deleted"); diff --git a/src/main/java/idatt2106/systemutvikling/sparesti/dto/MilestoneDTO.java b/src/main/java/idatt2106/systemutvikling/sparesti/dto/MilestoneDTO.java index b9883c740e03ff27f0c4a7961fe8703fc00c8f91..574cbf32caae027d7122dad6a12dc498af763a74 100644 --- a/src/main/java/idatt2106/systemutvikling/sparesti/dto/MilestoneDTO.java +++ b/src/main/java/idatt2106/systemutvikling/sparesti/dto/MilestoneDTO.java @@ -2,8 +2,8 @@ package idatt2106.systemutvikling.sparesti.dto; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; -import lombok.Getter; -import lombok.Setter; + +import lombok.*; /** * Data transfer object for Milestone @@ -11,6 +11,9 @@ import lombok.Setter; */ @Getter @Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder=true) public class MilestoneDTO { @NotNull private Long milestoneId; diff --git a/src/main/java/idatt2106/systemutvikling/sparesti/repository/ChallengeRepository.java b/src/main/java/idatt2106/systemutvikling/sparesti/repository/ChallengeRepository.java index 772b1e9dc5ad1190fc6550f6f228d79db33e5dd1..4246123350b3b3aed3bb1964ba59b4e51dd3ede3 100644 --- a/src/main/java/idatt2106/systemutvikling/sparesti/repository/ChallengeRepository.java +++ b/src/main/java/idatt2106/systemutvikling/sparesti/repository/ChallengeRepository.java @@ -118,4 +118,8 @@ public interface ChallengeRepository extends JpaRepository<ChallengeDAO, Long> { void deleteAllByUserDAO_Username(String username); + + + + ChallengeDAO findByChallengeIdAndUserDAO_Username(Long id, String username); } diff --git a/src/main/java/idatt2106/systemutvikling/sparesti/service/ChallengeService.java b/src/main/java/idatt2106/systemutvikling/sparesti/service/ChallengeService.java index ecac3fd3c7b566a3ddfe86c914497c5d41afc97e..01275088e55f07d6443153814b139cb49b3ecb17 100644 --- a/src/main/java/idatt2106/systemutvikling/sparesti/service/ChallengeService.java +++ b/src/main/java/idatt2106/systemutvikling/sparesti/service/ChallengeService.java @@ -2,13 +2,18 @@ package idatt2106.systemutvikling.sparesti.service; import idatt2106.systemutvikling.sparesti.dao.ChallengeDAO; import idatt2106.systemutvikling.sparesti.dao.ChallengeLogDAO; +import idatt2106.systemutvikling.sparesti.dao.MilestoneDAO; import idatt2106.systemutvikling.sparesti.dto.ChallengeDTO; +import idatt2106.systemutvikling.sparesti.exceptions.BankConnectionErrorException; +import idatt2106.systemutvikling.sparesti.exceptions.NotFoundInDatabaseException; import idatt2106.systemutvikling.sparesti.mapper.ChallengeMapper; import idatt2106.systemutvikling.sparesti.repository.ChallengeLogRepository; import idatt2106.systemutvikling.sparesti.repository.ChallengeRepository; import java.util.logging.Logger; +import idatt2106.systemutvikling.sparesti.repository.MilestoneRepository; +import jakarta.transaction.Transactional; import lombok.AllArgsConstructor; import org.springframework.data.domain.*; import org.springframework.stereotype.Service; @@ -25,8 +30,11 @@ import java.util.List; public class ChallengeService { private final Logger logger = Logger.getLogger(ChallengeService.class.getName()); - private ChallengeRepository challengeRepository; - private ChallengeLogRepository challengeLogRepository; + private final TransactionService transactionService; + private final ChallengeRepository challengeRepository; + private final ChallengeLogRepository challengeLogRepository; + private final MilestoneService milestoneService; + private final MilestoneRepository dbMilestone; /** * Method to get a challenge by its id from the database and return it as a ChallengeDTO object to @@ -208,20 +216,74 @@ public class ChallengeService { return challengeRepository.save(challengeDAO); } + @Transactional + public void completeChallengeForCurrentUser(long challengeId, long milestoneId) { + // Fetch username from security context + final String username = CurrentUserService.getCurrentUsername(); + + // Fetch data + ChallengeDAO challenge = challengeRepository.findByChallengeIdAndUserDAO_Username(challengeId, username); + MilestoneDAO milestone = dbMilestone.findMilestoneDAOByMilestoneIdAndUserDAO_Username(milestoneId, username); + + // Verify existence of the requested challenge + if (challenge == null) + throw new NotFoundInDatabaseException("No challenge found with the requested ID for the user"); + + // Verify existence of the requested milestone + if (milestone == null) + throw new NotFoundInDatabaseException("No milestone found with the requested ID for the user"); + + + + // Define transfer amount as the difference between the goal and the current sum + long transferAmount = challenge.getGoalSum() - challenge.getCurrentSum(); + + // Perform savings transaction + boolean success = transactionService.createSavingsTransferForCurrentUser(transferAmount); + + // Verify transaction success + if (success) + throw new BankConnectionErrorException("Failed to transfer funds to savings"); + + + // Transfer achieved currency to milestone + MilestoneDAO savedEntry = milestoneService.increaseMilestonesCurrentSum(milestoneId, challenge.getGoalSum()); + + + // Archive challenge + archiveActiveChallenge(challenge.getChallengeId()); + } + /** - * Method to complete a challenge. The method returns a ChallengeLogDAO object. The challenge is - * completed with the current date and time. The challenge is completed with the same information - * as the challenge. The challenge is deleted from the database and saved as a challenge log. + * Performs the changes - local to the challenge repository - needed for a challenge to be considered as 'completed'. + * This function creates a log entry from the selected challenge (specified by the id-parameter) + * and stores it in the database. The challenge is deleted from the table of active challenges, + * but the log entry persists. * * @param challengeId the id of the challenge to complete - * @return the completed challenge + * @return The log entry that is persisted by this function. */ - public ChallengeLogDAO completeChallenge(Long challengeId) { + public ChallengeLogDAO archiveActiveChallenge(Long challengeId) { + // Fetch active challenge from database ChallengeDAO challengeDAO = challengeRepository.findChallengeDAOByChallengeId(challengeId); + + // Verify existence of the active challenge + if (challengeDAO == null) + return null; + + // Create log entry from the active challenge ChallengeLogDAO challengeLogDAO = createChallengeLog(challengeDAO); + + // Set the archived currency equal to the goal of the active challenge challengeLogDAO.setChallengeAchievedSum(challengeLogDAO.getGoalSum()); + + // Save challenge log entry to database + challengeLogDAO = challengeLogRepository.save(challengeLogDAO); + + // Remove active challenge from database challengeRepository.delete(challengeDAO); - challengeLogRepository.save(challengeLogDAO); + + // Return the archived entry return challengeLogDAO; } diff --git a/src/test/java/idatt2106/systemutvikling/sparesti/controller/ChallengeControllerTests.java b/src/test/java/idatt2106/systemutvikling/sparesti/controller/ChallengeControllerTests.java index 8bb216a43d9be2e515e45efd1839b0a71094df9a..dc119e5510eef34c57230c0f08ea673c1f5569c9 100644 --- a/src/test/java/idatt2106/systemutvikling/sparesti/controller/ChallengeControllerTests.java +++ b/src/test/java/idatt2106/systemutvikling/sparesti/controller/ChallengeControllerTests.java @@ -1,11 +1,12 @@ package idatt2106.systemutvikling.sparesti.controller; import idatt2106.systemutvikling.sparesti.dto.ChallengeDTO; +import idatt2106.systemutvikling.sparesti.dto.MilestoneDTO; +import idatt2106.systemutvikling.sparesti.repository.ChallengeLogRepository; +import idatt2106.systemutvikling.sparesti.repository.ChallengeRepository; import idatt2106.systemutvikling.sparesti.service.ChallengeService; import idatt2106.systemutvikling.sparesti.service.CurrentUserService; import idatt2106.systemutvikling.sparesti.service.MilestoneService; -import idatt2106.systemutvikling.sparesti.service.TransactionService; -import org.hibernate.grammars.hql.HqlParser; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -15,15 +16,13 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import java.time.LocalDateTime; -import java.util.Date; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -32,40 +31,178 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @TestPropertySource(locations = "classpath:application-integrationtest.properties") public class ChallengeControllerTests { - private static final ChallengeDTO TEST_CHALLENGE = new ChallengeDTO( - 99L, - "Darth", - "Test", - "This is a test challenge", - 100L, - 0L, - LocalDateTime.now(), - LocalDateTime.now().plusDays(3), - 0, - true - ); - - @Autowired - private MockMvc mvc; - - @MockBean - private ChallengeService challengeService; - - @MockBean - private MilestoneService milestoneService; - - @Test - public void deleteChallenge_ReturnOkWhenAllIsWell() throws Exception { - final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().build(); - - given(challengeService.getChallenge(challenge.getChallengeId())).willReturn(challenge); - doNothing().when(challengeService).moveChallengeToLog(challenge.getChallengeId()); - - try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic( - CurrentUserService.class)) { - utilities.when(CurrentUserService::getCurrentUsername).thenReturn(challenge.getUsername()); - mvc.perform(delete("/user/challenge/delete/" + challenge.getChallengeId())) - .andExpect(status().isOk()); + public static final String TEST_USERNAME = "Test user"; + public static final String TEST_USERNAME_OTHER = "Not " + TEST_USERNAME; + + private static final ChallengeDTO TEST_CHALLENGE = new ChallengeDTO( + 99L, + TEST_USERNAME, + "Test", + "This is a test challenge", + 100L, + 0L, + LocalDateTime.now(), + LocalDateTime.now().plusDays(3), + 0, + true + ); + + private static final MilestoneDTO TEST_MILESTONE = new MilestoneDTO( + 1L, + TEST_USERNAME, + "Test milestone", + "A milestone for testing", + 100L, + 0L, + "image.jpg", + LocalDateTime.now(), + LocalDateTime.now().plusDays(3) + ); + + @Autowired + private MockMvc mvc; + + @MockBean + private ChallengeService challengeService; + + @MockBean + private MilestoneService milestoneService; + + + @Test + public void moveChallengeToLog_okWhenUserOwnsChallenge() throws Exception { + try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic(CurrentUserService.class)) { + // Copy the default values used for testing + final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().build(); + final Long challengeId = challenge.getChallengeId(); + + // Set the currently logged-in user to the owner of the challenge and milestone + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(TEST_USERNAME); + + // Stub the service call + doNothing().when(challengeService).moveChallengeToLog(challengeId); + + // Set return values of service layer functions + given(challengeService.getChallenge(challengeId)).willReturn(challenge); + + // Http request path + final String URI = "/user/challenge/delete/" + challengeId; + + // Perform http request + mvc.perform(delete(URI)).andExpect(status().is2xxSuccessful()); + } + } + + + @Test + public void completeChallenge_okWhenUserOwnsBothMilestoneAndChallenge() throws Exception { + try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic(CurrentUserService.class)) { + // Copy the default values used for testing + final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().build(); + final MilestoneDTO milestone = TEST_MILESTONE.toBuilder().build(); + final Long challengeId = challenge.getChallengeId(); + final Long milestoneId = milestone.getMilestoneId(); + + // Set the currently logged-in user to the owner of the challenge and milestone + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(TEST_USERNAME); + + // Stub the service call + doNothing().when(challengeService).completeChallengeForCurrentUser(challengeId, milestoneId); + + // Set return values of service layer functions + given(challengeService.getChallenge(challengeId)).willReturn(challenge); + given(milestoneService.getMilestoneDTOById(milestoneId)).willReturn(milestone); + + // Http request path + final String URI = String.format("/user/challenge/complete?challengeId=%d&milestoneId=%d", + challengeId, + milestoneId); + + // Perform http request + mvc.perform(post(URI)).andExpect(status().isOk()); + } + } + + @Test + public void completeChallenge_badRequestWhenUserDoesNotOwnChallenge() throws Exception { + try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic(CurrentUserService.class)) { + // Copy the default values used for testing + final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().username("Other user").build(); + final MilestoneDTO milestone = TEST_MILESTONE.toBuilder().build(); + final Long challengeId = challenge.getChallengeId(); + final Long milestoneId = milestone.getMilestoneId(); + + // Set the currently logged-in user to the owner of the challenge and milestone + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(TEST_USERNAME); + + // Stub the service call + doNothing().when(challengeService).completeChallengeForCurrentUser(challengeId, milestoneId); + + // Set return values of service layer functions + given(challengeService.getChallenge(challengeId)).willReturn(challenge); + given(milestoneService.getMilestoneDTOById(milestoneId)).willReturn(milestone); + + // Http request path + final String URI = String.format("/user/challenge/complete?challengeId=%d&milestoneId=%d", + challengeId, + milestoneId); + + // Perform http request + mvc.perform(post(URI)).andExpect(status().isBadRequest()); + } } - } + + @Test + public void completeChallenge_badRequestWhenUserDoesNotOwnMilestone() throws Exception { + try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic(CurrentUserService.class)) { + // Copy the default values used for testing + final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().build(); + final MilestoneDTO milestone = TEST_MILESTONE.toBuilder().username(TEST_USERNAME_OTHER).build(); + final Long challengeId = challenge.getChallengeId(); + final Long milestoneId = milestone.getMilestoneId(); + + // Set the currently logged-in user to the owner of the challenge and milestone + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(TEST_USERNAME); + + // Stub the service call + doNothing().when(challengeService).completeChallengeForCurrentUser(challengeId, milestoneId); + + // Set return values of service layer functions + given(challengeService.getChallenge(challengeId)).willReturn(challenge); + given(milestoneService.getMilestoneDTOById(milestoneId)).willReturn(milestone); + + // Http request path + final String URI = String.format("/user/challenge/complete?challengeId=%d&milestoneId=%d", + challengeId, + milestoneId); + + // Perform http request + mvc.perform(post(URI)).andExpect(status().isBadRequest()); + } + } + + @Test + public void moveChallengeToLog_badRequestWhenUserDoesNotOwnChallenge() throws Exception { + try (MockedStatic<CurrentUserService> utilities = Mockito.mockStatic(CurrentUserService.class)) { + // Copy the default values used for testing + final ChallengeDTO challenge = TEST_CHALLENGE.toBuilder().username(TEST_USERNAME_OTHER).build(); + final Long challengeId = challenge.getChallengeId(); + + // Set the currently logged-in user to the owner of the challenge and milestone + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(TEST_USERNAME); + + // Stub the service call + doNothing().when(challengeService).moveChallengeToLog(challengeId); + + // Set return values of service layer functions + given(challengeService.getChallenge(challengeId)).willReturn(challenge); + + // Http request path + final String URI = "/user/challenge/delete/" + challengeId; + + // Perform http request + mvc.perform(delete(URI)).andExpect(status().is4xxClientError()); + } + } + } diff --git a/src/test/java/idatt2106/systemutvikling/sparesti/service/ChallengeServiceTest.java b/src/test/java/idatt2106/systemutvikling/sparesti/service/ChallengeServiceTest.java index 54f5ea1296680a2997b76ab5504e3fd28aa90e76..982f9b1d63c3c128bd89056fb0e75960975dc711 100644 --- a/src/test/java/idatt2106/systemutvikling/sparesti/service/ChallengeServiceTest.java +++ b/src/test/java/idatt2106/systemutvikling/sparesti/service/ChallengeServiceTest.java @@ -1,7 +1,9 @@ package idatt2106.systemutvikling.sparesti.service; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import idatt2106.systemutvikling.sparesti.dao.ChallengeDAO; import idatt2106.systemutvikling.sparesti.dao.ChallengeLogDAO; @@ -16,23 +18,29 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import org.aspectj.lang.annotation.Before; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; +import org.mockito.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.data.domain.*; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.util.ReflectionTestUtils; +@AutoConfigureMockMvc(addFilters = false) +@TestPropertySource(locations = "classpath:application-integrationtest.properties") +@DataJpaTest public class ChallengeServiceTest { - @Mock + @MockBean private ChallengeRepository challengeRepository; - @Mock + @MockBean private ChallengeLogRepository challengeLogRepository; @InjectMocks @@ -40,10 +48,40 @@ public class ChallengeServiceTest { @BeforeEach public void setup() { - MockitoAnnotations.openMocks(this); - challengeRepository = Mockito.mock(ChallengeRepository.class); - challengeLogRepository = Mockito.mock(ChallengeLogRepository.class); ReflectionTestUtils.setField(challengeService, "challengeRepository", challengeRepository); + ReflectionTestUtils.setField(challengeService, "challengeLogRepository", challengeLogRepository); + } + + @Test + @DisplayName("Verify that ChallengeService::createChallenge cannot register challenges on other users") + public void createChallenge_CannotRegisterChallengesOnOtherUsers() { + String loggedInUsername = "Original user"; + String targetUsername = "Other user"; + + ChallengeDTO dto = new ChallengeDTO( + 451L, + targetUsername, + "Tricked you >:D", + "This is a challenge from \"Other user\"", + 100_000_000L, + 0L, + LocalDateTime.now(), + LocalDateTime.now().plusDays(2), + 0, + true + ); + + try (MockedStatic<CurrentUserService> utilities = mockStatic(CurrentUserService.class)) { + utilities.when(CurrentUserService::getCurrentUsername).thenReturn(loggedInUsername); + challengeService.createChallenge(dto); + } + + ArgumentCaptor<ChallengeDAO> argumentCaptor = ArgumentCaptor.forClass(ChallengeDAO.class); + verify(challengeRepository, times(1)).save(argumentCaptor.capture()); + + ChallengeDAO argument = argumentCaptor.getValue(); + assertNotEquals(targetUsername, argument.getUserDAO().getUsername()); + assertEquals(loggedInUsername, argument.getUserDAO().getUsername()); } @Test @@ -57,7 +95,7 @@ public class ChallengeServiceTest { List<ChallengeDAO> challenges = List.of(challenge, challenge2); when(challengeRepository.findChallengeDAOByActiveAndUserDAO_Username(true, - "username")).thenReturn(challenges); + "username")).thenReturn(challenges); assertEquals(challenges, challengeService.getChallengesByActiveAndUsername("username", true)); } @@ -222,8 +260,8 @@ public class ChallengeServiceTest { } @Test - @DisplayName("Test completeChallenge completes a challenge") - void testCompleteChallenge() { + @DisplayName("Test archiveActiveChallenge completes a challenge") + void testArchiveActiveChallenge() { UserDAO user1 = new UserDAO(); user1.setUsername("JohnSmith12"); @@ -242,11 +280,15 @@ public class ChallengeServiceTest { challengeLogDAO.setCompletionDate(LocalDateTime.now()); challengeLogDAO.setUserDAO(user1); - when(challengeRepository.findChallengeDAOByChallengeId(1L)).thenReturn(challenge1); - when(challengeRepository.save(challenge1)).thenReturn(challenge1); + given(challengeRepository.findChallengeDAOByChallengeId(challenge1.getChallengeId())).willReturn(challenge1); + ArgumentCaptor<ChallengeLogDAO> challengeLogDAOCaptor = ArgumentCaptor.forClass(ChallengeLogDAO.class); - assertEquals(challengeLogDAO.getChallengeId(), - challengeService.completeChallenge(1L).getChallengeId()); + // Act + challengeService.archiveActiveChallenge(challenge1.getChallengeId()); + verify(challengeLogRepository, times(1)).save(challengeLogDAOCaptor.capture()); + + // Assert + assertEquals(challenge1.getChallengeId(), challengeLogDAOCaptor.getValue().getChallengeId()); } @Test