From 30c941948130d00a2cbc87c87b9ee59adc3b1deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=89=D0=B8=D0=BB=D0=BA=D0=BE=20=D0=90=D0=BB?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Thu, 16 Oct 2025 20:02:51 +0300 Subject: [PATCH] add task 2 --- README.md | 2 +- pom.xml | 5 + .../java/task/repository/TaskRepository.java | 1 + .../repository/impl/TaskRepositoryImpl.java | 5 + .../NotificationControllerTest.java | 96 ++++++++++++ .../task/controller/TaskControllerTest.java | 96 ++++++++++++ .../task/controller/UserControllerTest.java | 93 ++++++++++++ .../impl/NotificationRepositoryImplTest.java | 137 ++++++++++++++++++ .../impl/TaskRepositoryImplTest.java | 95 ++++++++++++ .../impl/UserRepositoryImplTest.java | 118 +++++++++++++++ .../impl/NotificationServiceImplTest.java | 91 ++++++++++++ .../service/impl/TaskServiceImplTest.java | 88 +++++++++++ .../service/impl/UserServiceImplTest.java | 102 +++++++++++++ .../task/repository/TaskRepository.class | Bin 630 -> 785 bytes .../repository/impl/TaskRepositoryImpl.class | Bin 4510 -> 4850 bytes .../NotificationControllerTest.class | Bin 0 -> 6120 bytes .../task/controller/TaskControllerTest.class | Bin 0 -> 5892 bytes .../task/controller/UserControllerTest.class | Bin 0 -> 5497 bytes .../impl/NotificationRepositoryImplTest.class | Bin 0 -> 5028 bytes .../impl/TaskRepositoryImplTest.class | Bin 0 -> 4271 bytes .../impl/UserRepositoryImplTest.class | Bin 0 -> 4202 bytes .../impl/NotificationServiceImplTest.class | Bin 0 -> 4239 bytes .../service/impl/TaskServiceImplTest.class | Bin 0 -> 3916 bytes .../service/impl/UserServiceImplTest.class | Bin 0 -> 4282 bytes 24 files changed, 928 insertions(+), 1 deletion(-) create mode 100644 src/test/java/task/controller/NotificationControllerTest.java create mode 100644 src/test/java/task/controller/TaskControllerTest.java create mode 100644 src/test/java/task/controller/UserControllerTest.java create mode 100644 src/test/java/task/repository/impl/NotificationRepositoryImplTest.java create mode 100644 src/test/java/task/repository/impl/TaskRepositoryImplTest.java create mode 100644 src/test/java/task/repository/impl/UserRepositoryImplTest.java create mode 100644 src/test/java/task/service/impl/NotificationServiceImplTest.java create mode 100644 src/test/java/task/service/impl/TaskServiceImplTest.java create mode 100644 src/test/java/task/service/impl/UserServiceImplTest.java create mode 100644 target/test-classes/task/controller/NotificationControllerTest.class create mode 100644 target/test-classes/task/controller/TaskControllerTest.class create mode 100644 target/test-classes/task/controller/UserControllerTest.class create mode 100644 target/test-classes/task/repository/impl/NotificationRepositoryImplTest.class create mode 100644 target/test-classes/task/repository/impl/TaskRepositoryImplTest.class create mode 100644 target/test-classes/task/repository/impl/UserRepositoryImplTest.class create mode 100644 target/test-classes/task/service/impl/NotificationServiceImplTest.class create mode 100644 target/test-classes/task/service/impl/TaskServiceImplTest.class create mode 100644 target/test-classes/task/service/impl/UserServiceImplTest.class diff --git a/README.md b/README.md index 745d97a..86abe0d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # REST API using Spring Boot - ## task 1 + ## task 2 diff --git a/pom.xml b/pom.xml index 4270842..8575695 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,11 @@ spring-boot-starter-test test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + diff --git a/src/main/java/task/repository/TaskRepository.java b/src/main/java/task/repository/TaskRepository.java index 086dc26..26c18ac 100644 --- a/src/main/java/task/repository/TaskRepository.java +++ b/src/main/java/task/repository/TaskRepository.java @@ -11,6 +11,7 @@ public interface TaskRepository { public List findByUserIdAndIsDeleteFalse(Long userId); public List findByUserIdAndIsCompleteFalseAndIsDeleteFalse(Long userId) ; public Task save(Task task) ; + public Optional findByIdAndIsDeleteFalse(Long taskId); public void markAsDeleted(Long taskId); } diff --git a/src/main/java/task/repository/impl/TaskRepositoryImpl.java b/src/main/java/task/repository/impl/TaskRepositoryImpl.java index 406e53a..2a08f1c 100644 --- a/src/main/java/task/repository/impl/TaskRepositoryImpl.java +++ b/src/main/java/task/repository/impl/TaskRepositoryImpl.java @@ -47,6 +47,11 @@ public Task save(Task task) { return task; } @Override + public Optional findByIdAndIsDeleteFalse(Long taskId) { + Task task = tasks.get(taskId); + return (task != null && !task.getIsDelete()) ? Optional.of(task) : Optional.empty(); + } + @Override public void markAsDeleted(Long taskId) { Optional.ofNullable(tasks.get(taskId)) .ifPresent(task -> task.setIsDelete(true)); diff --git a/src/test/java/task/controller/NotificationControllerTest.java b/src/test/java/task/controller/NotificationControllerTest.java new file mode 100644 index 0000000..a004079 --- /dev/null +++ b/src/test/java/task/controller/NotificationControllerTest.java @@ -0,0 +1,96 @@ +package task.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import task.model.Notification; +import task.service.NotificationService; + +import java.util.List; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class NotificationControllerTest { + + private MockMvc mockMvc; + private ObjectMapper objectMapper; + + @Mock + private NotificationService notificationService; + + @InjectMocks + private NotificationController notificationController; + + private Notification notification; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(notificationController).build(); + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + + notification = Notification.builder() + .notificationId(1L) + .text("New task available") + .userId(1L) + .taskId(2L) + .isRead(false) + .build(); + } + + @Test + void getAllNotifications_WhenExist_ReturnsOkAndList() throws Exception { + when(notificationService.getAllNotifications()).thenReturn(List.of(notification)); + + mockMvc.perform(get("/api/notifications")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].text").value("New task available")); + + verify(notificationService).getAllNotifications(); + } + + @Test + void getUserNotifications_ValidUserId_ReturnsOkAndList() throws Exception { + when(notificationService.getUserNotifications(1L)).thenReturn(List.of(notification)); + + mockMvc.perform(get("/api/notifications/user/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].userId").value(1)); + + verify(notificationService).getUserNotifications(1L); + } + + @Test + void getUserNotificationsUnread_UnreadExist_ReturnsOkAndUnreadList() throws Exception { + when(notificationService.getUserNotificationsUnread(1L)).thenReturn(List.of(notification)); + + mockMvc.perform(get("/api/notifications/user/1/unread")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].isRead").value(false)); + + verify(notificationService).getUserNotificationsUnread(1L); + } + + @Test + void createNotification_ValidData_ReturnsCreated() throws Exception { + when(notificationService.createNotification(any(Notification.class))).thenReturn(notification); + + mockMvc.perform(post("/api/notifications") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(notification))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.text").value("New task available")); + + verify(notificationService).createNotification(any(Notification.class)); + } +} diff --git a/src/test/java/task/controller/TaskControllerTest.java b/src/test/java/task/controller/TaskControllerTest.java new file mode 100644 index 0000000..75e27f8 --- /dev/null +++ b/src/test/java/task/controller/TaskControllerTest.java @@ -0,0 +1,96 @@ +package task.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import task.model.Task; +import task.service.TaskService; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +class TaskControllerTest { + + private MockMvc mockMvc; + private ObjectMapper objectMapper; + + @Mock + private TaskService taskService; + + @InjectMocks + private TaskController taskController; + + private Task task; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(taskController).build(); + objectMapper = new ObjectMapper(); + + objectMapper.registerModule(new JavaTimeModule()); + + task = Task.builder() + .taskId(1L) + .taskText("Sample Task") + .userId(1L) + .createDate(LocalDateTime.now()) + .build(); + } + + @Test + void getAllTasks_WhenTasksExist_ReturnsOkAndList() throws Exception { + when(taskService.getAllTasks()).thenReturn(List.of(task)); + + mockMvc.perform(get("/api/tasks")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].taskText").value("Sample Task")); + + verify(taskService).getAllTasks(); + } + + @Test + void getUserTasks_ValidUserId_ReturnsOk() throws Exception { + when(taskService.getUserTasks(1L)).thenReturn(List.of(task)); + + mockMvc.perform(get("/api/tasks/user/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].userId").value(1)); + + verify(taskService).getUserTasks(1L); + } + + @Test + void createTask_ValidTask_ReturnsCreated() throws Exception { + when(taskService.createTask(any(Task.class))).thenReturn(task); + + mockMvc.perform(post("/api/tasks") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(task))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.taskText").value("Sample Task")); + + verify(taskService).createTask(any(Task.class)); + } + + @Test + void deleteTask_ValidId_ReturnsNoContent() throws Exception { + doNothing().when(taskService).deleteTask(1L); + + mockMvc.perform(delete("/api/tasks/1")) + .andExpect(status().isNoContent()); + + verify(taskService).deleteTask(1L); + } +} diff --git a/src/test/java/task/controller/UserControllerTest.java b/src/test/java/task/controller/UserControllerTest.java new file mode 100644 index 0000000..3421299 --- /dev/null +++ b/src/test/java/task/controller/UserControllerTest.java @@ -0,0 +1,93 @@ +package task.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.InjectMocks; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import task.model.User; +import task.service.UserService; + +import java.util.List; +import java.util.Optional; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +class UserControllerTest { + + private MockMvc mockMvc; + + @Mock + private UserService userService; + + @InjectMocks + private UserController userController; + + private ObjectMapper objectMapper; + private User user; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); + objectMapper = new ObjectMapper(); + + user = User.builder() + .userId(1L) + .login("testLogin") + .userName("testUser") + .email("test@mail.com") + .build(); + } + + @Test + void getAllUsers_WhenUsersExist_ReturnsOkAndUserList() throws Exception { + when(userService.getAllUsers()).thenReturn(List.of(user)); + + mockMvc.perform(get("/api/users")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].userName").value("testUser")); + + verify(userService).getAllUsers(); + } + + @Test + void register_ValidUser_ReturnsCreated() throws Exception { + when(userService.register(any(User.class))).thenReturn(user); + + mockMvc.perform(post("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(user))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.login").value("testLogin")); + + verify(userService).register(any(User.class)); + } + + @Test + void getUserById_ExistingId_ReturnsOkAndUser() throws Exception { + when(userService.getUserById(1L)).thenReturn(Optional.of(user)); + + mockMvc.perform(get("/api/users/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.userName").value("testUser")); + + verify(userService).getUserById(1L); + } + + @Test + void getUserById_NonExistingId_ReturnsNotFound() throws Exception { + when(userService.getUserById(99L)).thenReturn(Optional.empty()); + + mockMvc.perform(get("/api/users/99")) + .andExpect(status().isNotFound()); + + verify(userService).getUserById(99L); + } +} diff --git a/src/test/java/task/repository/impl/NotificationRepositoryImplTest.java b/src/test/java/task/repository/impl/NotificationRepositoryImplTest.java new file mode 100644 index 0000000..9aedc68 --- /dev/null +++ b/src/test/java/task/repository/impl/NotificationRepositoryImplTest.java @@ -0,0 +1,137 @@ +package task.repository.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import task.model.Notification; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class NotificationRepositoryImplTest { + + private NotificationRepositoryImpl repository; + private Notification notification; + + @BeforeEach + void setUp() { + repository = new NotificationRepositoryImpl(); + + notification = Notification.builder() + .text("Reminder about task") + .taskId(1L) + .userId(10L) + .isRead(false) + .build(); + } + + @Test + void save_NewNotification_AssignsIdAndStoresNotification() { + // Act + Notification saved = repository.save(notification); + + // Assert + assertNotNull(saved.getNotificationId(), "Id должен быть присвоен"); + assertEquals(1, repository.findAll().size(), "Ожидаем 1 уведомление в репозитории"); + } + + @Test + void findByUserId_UserHasNotifications_ReturnsCorrectList() { + // Arrange + repository.save(notification); + repository.save(Notification.builder() + .text("Another one") + .taskId(2L) + .userId(20L) + .isRead(false) + .build()); + + // Act + List list = repository.findByUserId(10L); + + // Assert + assertEquals(1, list.size(), "Ожидаем 1 уведомление для userId=10"); + assertEquals("Reminder about task", list.get(0).getText()); + } + + @Test + void findByUserId_UserHasNoNotifications_ReturnsEmptyList() { + // Arrange + repository.save(notification); + + // Act + List list = repository.findByUserId(999L); + + // Assert + assertTrue(list.isEmpty(), "Список должен быть пуст для неизвестного пользователя"); + } + + @Test + void findByUserIdAndIsReadFalse_HasUnread_ReturnsOnlyUnread() { + // Arrange + repository.save(notification); // unread + repository.save(Notification.builder() + .text("Read message") + .taskId(2L) + .userId(10L) + .isRead(true) + .build()); + + // Act + List unread = repository.findByUserIdAndIsReadFalse(10L); + + // Assert + assertEquals(1, unread.size(), "Ожидаем только одно непрочитанное уведомление"); + assertFalse(unread.get(0).getIsRead(), "Уведомление должно быть непрочитанным"); + } + + @Test + void findByUserIdAndIsReadFalse_NoUnread_ReturnsEmptyList() { + // Arrange + repository.save(Notification.builder() + .text("Read message") + .taskId(3L) + .userId(15L) + .isRead(true) + .build()); + + // Act + List unread = repository.findByUserIdAndIsReadFalse(15L); + + // Assert + assertTrue(unread.isEmpty(), "Ожидаем пустой список при отсутствии непрочитанных"); + } + + @Test + void save_ExistingNotificationId_UpdatesStoredNotification() { + // Arrange + Notification saved = repository.save(notification); + saved.setText("Updated text"); + + // Act + repository.save(saved); + + // Assert + List all = repository.findAll(); + assertEquals(1, all.size()); + assertEquals("Updated text", all.get(0).getText(), "Текст должен быть обновлён"); + } + + @Test + void findAll_MultipleNotifications_ReturnsAll() { + // Arrange + repository.save(notification); + repository.save(Notification.builder() + .text("Second note") + .taskId(2L) + .userId(10L) + .isRead(false) + .build()); + + // Act + List all = repository.findAll(); + + // Assert + assertEquals(2, all.size(), "Ожидаем 2 уведомления"); + } +} diff --git a/src/test/java/task/repository/impl/TaskRepositoryImplTest.java b/src/test/java/task/repository/impl/TaskRepositoryImplTest.java new file mode 100644 index 0000000..33ead9d --- /dev/null +++ b/src/test/java/task/repository/impl/TaskRepositoryImplTest.java @@ -0,0 +1,95 @@ +package task.repository.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import task.model.Task; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +class TaskRepositoryImplTest { + + private TaskRepositoryImpl repository; + private Task task; + private static final LocalDateTime DATE_NOW = LocalDateTime.now(); + + @BeforeEach + void setUp() { + repository = new TaskRepositoryImpl(); + + task = Task.builder() + .taskText("Test task 1") + .userId(1L) + .actionDate(DATE_NOW.plusDays(2)) + .build(); + } + + @Test + void save_NewTask_AssignsIdAndStoresTask() { + Task saved = repository.save(task); + + assertNotNull(saved.getTaskId(), "Id должен быть назначен"); + assertEquals(1, repository.findAllIsDeleteFalse().size(), "В репозитории должен быть 1 элемент"); + } + + @Test + void findByUserIdAndIsDeleteFalse_ExistingTasks_ReturnsCorrectTasks() { + repository.save(task); + repository.save(Task.builder() + .taskText("Test task 2") + .userId(2L) + .actionDate(DATE_NOW.plusDays(3)) + .build() + ); + + List tasks = repository.findByUserIdAndIsDeleteFalse(1L); + + assertEquals(1, tasks.size()); + assertEquals("Test task 1", tasks.get(0).getTaskText()); + } + + @Test + void findByUserIdAndIsDeleteFalse_NoTasksForUser_ReturnsEmptyList() { + // не сохраняем задачи для userId=99 + List tasks = repository.findByUserIdAndIsDeleteFalse(99L); + assertTrue(tasks.isEmpty(), "Ожидаем пустой список если задач нет для заданного пользователя"); + } + + @Test + void findByUserIdAndIsCompleteFalseAndIsDeleteFalse_OnlyIncomplete_ReturnsPending() { + Task completedTask = Task.builder() + .taskText("Completed task") + .userId(1L) + .actionDate(DATE_NOW.plusDays(3)) + .isComplete(true) // помечена как выполненная + .build(); + + repository.save(task); // incomplete + repository.save(completedTask); // complete + + List pending = repository.findByUserIdAndIsCompleteFalseAndIsDeleteFalse(1L); + + assertEquals(1, pending.size()); + assertEquals("Test task 1", pending.get(0).getTaskText()); + } + + @Test + void markAsDeleted_TaskExists_SetsIsDeleteTrue() { + Task saved = repository.save(task); + repository.markAsDeleted(saved.getTaskId()); + + // findById должен вернуть empty, т.к. task помечен как удаленный + assertTrue(repository.findByIdAndIsDeleteFalse(saved.getTaskId()).isEmpty()); + } + + @Test + void markAsDeleted_NonExistingTask_NoExceptionAndStateUnchanged() { + // не должно кидать исключения при пометке несуществующего id + repository.markAsDeleted(999L); + // репозиторий по-прежнему пуст + assertTrue(repository.findAllIsDeleteFalse().isEmpty()); + } +} diff --git a/src/test/java/task/repository/impl/UserRepositoryImplTest.java b/src/test/java/task/repository/impl/UserRepositoryImplTest.java new file mode 100644 index 0000000..baf909a --- /dev/null +++ b/src/test/java/task/repository/impl/UserRepositoryImplTest.java @@ -0,0 +1,118 @@ +package task.repository.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import task.model.User; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +class UserRepositoryImplTest { + + private UserRepositoryImpl repository; + private User user; + + @BeforeEach + void setUp() { + repository = new UserRepositoryImpl(); + + user = User.builder() + .login("login1") + .password("pass123") + .email("user1@mail.com") + .userName("user1Name") + .build(); + } + + @Test + void save_NewUser_AssignsIdAndStoresUser() { + // Act + User saved = repository.save(user); + + // Assert + assertNotNull(saved.getUserId(), "Id должен быть назначен"); + assertEquals(1, repository.findAll().size(), "В репозитории должен быть 1 пользователь"); + } + + @Test + void findByUserName_UserExists_ReturnsUser() { + // Arrange + repository.save(user); + + // Act + Optional result = repository.findByUserName("user1Name"); + + // Assert + assertTrue(result.isPresent(), "Пользователь должен быть найден"); + assertEquals("login1", result.get().getLogin()); + } + + @Test + void findByUserName_UserNotExists_ReturnsEmpty() { + // Arrange + repository.save(user); + + // Act + Optional result = repository.findByUserName("unknown"); + + // Assert + assertTrue(result.isEmpty(), "Ожидаем пустой Optional"); + } + + @Test + void findById_ExistingId_ReturnsUser() { + // Arrange + User saved = repository.save(user); + + // Act + Optional found = repository.findById(saved.getUserId()); + + // Assert + assertTrue(found.isPresent(), "Пользователь должен быть найден"); + assertEquals(saved.getUserName(), found.get().getUserName()); + } + + @Test + void findById_NonExistingId_ReturnsEmpty() { + // Act + Optional found = repository.findById(999L); + + // Assert + assertTrue(found.isEmpty(), "Ожидаем Optional.empty для несуществующего id"); + } + + @Test + void findAll_WhenMultipleUsersExist_ReturnsAllUsers() { + // Arrange + repository.save(user); + repository.save(User.builder() + .login("login2") + .password("pass456") + .email("user2@mail.com") + .userName("user2Name") + .build()); + + // Act + List all = repository.findAll(); + + // Assert + assertEquals(2, all.size(), "Ожидаем 2 пользователя"); + } + + @Test + void save_UserWithExistingId_OverwritesExistingUser() { + // Arrange + User saved = repository.save(user); + saved.setEmail("updated@mail.com"); + + // Act + repository.save(saved); + + // Assert + Optional found = repository.findById(saved.getUserId()); + assertTrue(found.isPresent()); + assertEquals("updated@mail.com", found.get().getEmail(), "Email должен быть обновлён"); + } +} diff --git a/src/test/java/task/service/impl/NotificationServiceImplTest.java b/src/test/java/task/service/impl/NotificationServiceImplTest.java new file mode 100644 index 0000000..6ad9108 --- /dev/null +++ b/src/test/java/task/service/impl/NotificationServiceImplTest.java @@ -0,0 +1,91 @@ +package task.service.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import task.model.Notification; +import task.repository.NotificationRepository; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class NotificationServiceImplTest { + + @Mock + private NotificationRepository notificationRepository; + + @InjectMocks + private NotificationServiceImpl notificationService; + + private Notification notification; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + notification = Notification.builder() + .notificationId(1L) + .text("Task reminder") + .taskId(1L) + .userId(10L) + .isRead(false) + .build(); + } + + @Test + void getAllNotifications_WhenExist_ReturnsList() { + when(notificationRepository.findAll()).thenReturn(List.of(notification)); + + List result = notificationService.getAllNotifications(); + + assertEquals(1, result.size()); + assertEquals("Task reminder", result.get(0).getText()); + verify(notificationRepository).findAll(); + } + + @Test + void getUserNotifications_ValidUserId_ReturnsNotifications() { + when(notificationRepository.findByUserId(10L)).thenReturn(List.of(notification)); + + List result = notificationService.getUserNotifications(10L); + + assertEquals(1, result.size()); + verify(notificationRepository).findByUserId(10L); + } + + @Test + void getUserNotifications_NoNotifications_ReturnsEmptyList() { + when(notificationRepository.findByUserId(99L)).thenReturn(List.of()); + + List result = notificationService.getUserNotifications(99L); + + assertTrue(result.isEmpty()); + verify(notificationRepository).findByUserId(99L); + } + + @Test + void getUserNotificationsUnread_HasUnread_ReturnsOnlyUnread() { + when(notificationRepository.findByUserIdAndIsReadFalse(10L)).thenReturn(List.of(notification)); + + List unread = notificationService.getUserNotificationsUnread(10L); + + assertEquals(1, unread.size()); + assertFalse(unread.get(0).getIsRead()); + verify(notificationRepository).findByUserIdAndIsReadFalse(10L); + } + + @Test + void createNotification_ValidNotification_SavesAndReturns() { + when(notificationRepository.save(notification)).thenReturn(notification); + + Notification created = notificationService.createNotification(notification); + + assertNotNull(created); + assertEquals("Task reminder", created.getText()); + verify(notificationRepository).save(notification); + } +} diff --git a/src/test/java/task/service/impl/TaskServiceImplTest.java b/src/test/java/task/service/impl/TaskServiceImplTest.java new file mode 100644 index 0000000..26cfaf0 --- /dev/null +++ b/src/test/java/task/service/impl/TaskServiceImplTest.java @@ -0,0 +1,88 @@ +package task.service.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import task.model.Task; +import task.repository.TaskRepository; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class TaskServiceImplTest { + + @Mock + private TaskRepository taskRepository; + + @InjectMocks + private TaskServiceImpl taskService; + + private Task task; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + task = Task.builder() + .taskId(1L) + .taskText("Test task") + .userId(1L) + .createDate(LocalDateTime.now()) + .build(); + } + + @Test + void getAllTasks_WhenTasksExist_ReturnsTaskList() { + when(taskRepository.findAllIsDeleteFalse()).thenReturn(List.of(task)); + + List result = taskService.getAllTasks(); + + assertEquals(1, result.size()); + assertEquals("Test task", result.get(0).getTaskText()); + verify(taskRepository).findAllIsDeleteFalse(); + } + + @Test + void getUserTasks_ValidUserId_ReturnsTasks() { + when(taskRepository.findByUserIdAndIsDeleteFalse(1L)).thenReturn(List.of(task)); + + List result = taskService.getUserTasks(1L); + + assertEquals(1, result.size()); + verify(taskRepository).findByUserIdAndIsDeleteFalse(1L); + } + + @Test + void getUserTasksPending_OnlyIncompleteTasks_ReturnsPending() { + when(taskRepository.findByUserIdAndIsCompleteFalseAndIsDeleteFalse(1L)).thenReturn(List.of(task)); + + List result = taskService.getUserTasksPending(1L); + + assertEquals(1, result.size()); + assertFalse(result.get(0).getIsComplete()); + verify(taskRepository).findByUserIdAndIsCompleteFalseAndIsDeleteFalse(1L); + } + + @Test + void createTask_ValidTask_SavesTask() { + when(taskRepository.save(task)).thenReturn(task); + + Task created = taskService.createTask(task); + + assertNotNull(created); + assertEquals("Test task", created.getTaskText()); + verify(taskRepository).save(task); + } + + @Test + void deleteTask_ValidId_CallsRepositoryMarkAsDeleted() { + taskService.deleteTask(1L); + + verify(taskRepository).markAsDeleted(1L); + } +} diff --git a/src/test/java/task/service/impl/UserServiceImplTest.java b/src/test/java/task/service/impl/UserServiceImplTest.java new file mode 100644 index 0000000..c72fccf --- /dev/null +++ b/src/test/java/task/service/impl/UserServiceImplTest.java @@ -0,0 +1,102 @@ +package task.service.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import task.model.User; +import task.repository.UserRepository; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class UserServiceImplTest { + + @Mock + private UserRepository userRepository; + + @InjectMocks + private UserServiceImpl userService; + + private User user; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + + user = User.builder() + .userId(1L) + .login("userLogin") + .password("12345") + .userName("userName") + .email("user@mail.com") + .build(); + } + + @Test + void getAllUsers_WhenUsersExist_ReturnsUserList() { + when(userRepository.findAll()).thenReturn(List.of(user)); + + List result = userService.getAllUsers(); + + assertEquals(1, result.size()); + assertEquals("userName", result.get(0).getUserName()); + verify(userRepository).findAll(); + } + + @Test + void register_ValidUser_SavesUser() { + when(userRepository.save(any(User.class))).thenReturn(user); + + User saved = userService.register(user); + + assertNotNull(saved); + assertEquals("userLogin", saved.getLogin()); + verify(userRepository).save(user); + } + + @Test + void login_ValidCredentials_ReturnsUser() { + when(userRepository.findByUserName("userName")).thenReturn(Optional.of(user)); + + Optional result = userService.login("userName", "12345"); + + assertTrue(result.isPresent()); + assertEquals("userLogin", result.get().getLogin()); + verify(userRepository).findByUserName("userName"); + } + + @Test + void login_InvalidPassword_ReturnsEmpty() { + when(userRepository.findByUserName("userName")).thenReturn(Optional.of(user)); + + Optional result = userService.login("userName", "wrongPass"); + + assertTrue(result.isEmpty()); + verify(userRepository).findByUserName("userName"); + } + + @Test + void getUserById_ExistingId_ReturnsUser() { + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); + + Optional result = userService.getUserById(1L); + + assertTrue(result.isPresent()); + assertEquals("userLogin", result.get().getLogin()); + verify(userRepository).findById(1L); + } + + @Test + void getUserById_NonExistingId_ReturnsEmpty() { + when(userRepository.findById(99L)).thenReturn(Optional.empty()); + + Optional result = userService.getUserById(99L); + + assertTrue(result.isEmpty()); + } +} diff --git a/target/classes/task/repository/TaskRepository.class b/target/classes/task/repository/TaskRepository.class index 3bd45266f6e9b7715a1e494e50c80481c815a9c6..fdb9c7f073a2f170b68886775fb3bc4b4d225bfe 100644 GIT binary patch delta 137 zcmeyyGLenz)W2Q(7#J9A8KgFH&0=JiNXyJiajKlSQG`)#GCQNJsDD98W`15`jx{3# zTS;PZwr2_>gC$6Y112+Zg4pCGK-HHSbr{(uF(nu>F>nJ-WMyO!0aENh%)}td!pI=T QAkM&uEXBwm0hW{m008)W2Q(7#J9A8N@eo&0?Ia%cRE6R+3np?U^z;kV%h`b#en!f*2zMH&6{L QBZCN#Vq_2nl1vO@06=dH)Bpeg diff --git a/target/classes/task/repository/impl/TaskRepositoryImpl.class b/target/classes/task/repository/impl/TaskRepositoryImpl.class index 15cf135c98bc7bbdd6c229138183196540285cd0..397df043ce6eddded9bc90dfb787022f4351ebe5 100644 GIT binary patch delta 1639 zcmb7ETXz#x6#h;wGjwvArWHD^O;8$xG%04W%7e9#1w~zC8MSMv%e8!w(M(I}WF{sl zQc>dt?{d)*3aEIuRY9o1Sc?MQQ0ra1`{ZBn+2wMd$&mCxAAHEnK6}pozHfhLpB#$* z8B^x}o;wL(EqQUfL|8F`M|P_R>e)$6f_?M?nfMuCYE$2hh!`1M@AG{Mlmq9@~^jF(1@ zt7#hxzOUdUPRTgU@c}-pEDreCs@*LT zK2Z?B8IHG64WUYj&qZRM<2Wj``ckaE;&=;{5WcZ@N~*ny`=Z~8^!FUcFcZQI15cZ# zUf5u0#iCx6@e@PLJ{5=riWg-pYiv9(;}`oV@4MKB2W<$V1q^#>Bs|zhYZV<72Po%< zM9)dPsd;5`KjngSDnKiIw5tW@;Q*~T?Eu0!h^Ohz@C=?MoJm`6?i&y_ZL}L`rz(}6 z9au)sMqRgCS7Sd!_0QpXVwtqhHm@FP)Q1TtLI_LIOBZirsOLw=#9aJpxp!-CD7#r+Wr4QU&WNu>F>ccWudg4`~u>Tk-!r4lFm!egX99> zL|ttH(|C=9y-pQgu<$wA)3j!I1BZnN6i*O?@H`ej4kb~=&8LyNy7vqg_f~Oh6(a|s z^v)tzo`N)s;xPwJXi*$@`sj34JNy^cQ0n|K9C6&@=ya5L93>o{zpzY3YEY(Y={k9Y z;A+S7CP_PrA<;DDuA{d&0+poM+gp_K?Q^&TsN(J!%6cGV)CT5K8kK&s=duM>sC6l- zE2TjfQp6+^nV{(-C^2D8ao;TNtKxwMx)@Fna&4S4&Mv1L5CUBh7a{Kojgfzk#H)Dx z0Jx?DH8T!O&m z`VR)es_Bm`aHXrx(}n4BeL{$+(;=e21()awdW(ib)X=}^ucNE3JI>ykInGfNWN;m$ zyZH`n^Kd~?n*%>zF8GP7sT?BBO%@0lmb;|cA~)9D!i zui()It;OHk1tW-Vi5~O{MEms}dfRZJ&un{RsL+?q=%#>{?S6gOH1(~fVa@o{S`=RN zOANrYRs>pK=t4#!iy^B&u&gSFd=LeR4H&jE{@8+8b7#v&8*1vAp0>5wtZC?(l^RxI zr^GJowr&N|^?N1uVXeTN9;2{1Z{#|$grbW-g$GfDQ4N7Z?4$>uab1fSX>0WP5#Tst-3+yg!`9=_-1z6*k@Nxe zuPF*3fP*Dtt$dy#MHJYEL3S3sKxO%S?>(5C+n{SM#T zw>?t*@@AE3j8y_s2qKO7Si(G)q6KXg;B-0LG)~|LCiWvEyb$&OrhS5IfuFF+CSQxx z6}L^J4=7>q0=GO+LScpg%P|-26kSmvP+JzL#mUNYoCG48dJm+J*ufrJz?_ut3bvQ9 zW0tNO4U(Nk741`Ywu->F<`RaOjOsu#UBaGJ32z=noaWmlyg!N>S|8h1&^HF3cajIa zcJ9uTNbu<_WbR3hiHiJ_b`yD+J5GU$szQEv5~~H}`S4x&PFG%Oy7K=m>RhRzLMUDq zidS@kI(4=Vf1ImRe2s>xL4imjn{NY+NWvk)3YyOE_xQ#muQ2+5R?&Bfqo&m@T0g(Uz diff --git a/target/test-classes/task/controller/NotificationControllerTest.class b/target/test-classes/task/controller/NotificationControllerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..26ef8d03df7648c5cc90749d85191eb1b5e18277 GIT binary patch literal 6120 zcmb_gd0Z9O75?r69C%K%pf%N`Y84HlGHPrV(I_BR2#W!PpfO~4Z-9Zv%*)I?K)WQ} z_a)uZy-oMMO&Xt%*rc{iw{+k4ec$)>kN*1InSnPC9`Vti{K34rbMHCdch0%zoO>Vs z@BI$~*oXhb5kr}RaupR=CUD7^KB;Rd-5SxlhQ^G9C$MaMur`I!kDt1am}MHZORzZT*H}686KZrCheP{V=~c{ zF;hvyA@7S_Pq&hK%C?LiIYZ!B?ePfjz|b_s5|s4JiIm38t0V9=xLm;%Djtiq0?ijd zra;AzBqOk+wnUI2DBp?eRXh$G1eA#YsX%>cOlO5Cs1ewjuqU)(-SrG-dLpHb=?p2` z(vrHT51CdnjMff4oi>~}Hlj?%&y^}_u|+_&{a6mZG7#IBAgn>bR)O7%ukcQ$4Qi%hGDZnZG1sp48(r(lnY2J9uX{LXH- ztr1F|)KeLwYgk}KZCiAg%gajd5g&6LbR66GNkPrzY;a?hA%W@(J7>hWYkpl_A{->2TD;s(ikS%#^jHCe$_ zEdOFsVV8;{{x>PKH5o@YdKC0ZJ0BIeG;il7+fEs}#cWr5ENb9z+*j1E;wB7Gk?D3D zI!)CS#Xmc9=>(3;^m4Pn<%>s+zxQuZF^F5a0i!MxSiP9V{6#}55+K$U(M3JXv1Y;$ z*buChIhXGR@f^-+SdL+gC>T{?VobpIs-L76SwK}IhS!)%MFX9QyPE8LduKc|rL}YC z(x@p+D6mx6U?N{pr2a8hrbZ3=Wlz-B1xa3JLRm3gFEhm5%UWxV*nIYc?_}V>Rp6<} zU~+bM&7ly8+1yw)Mdi-}yd2Xwso<1~CrZFIQNW9-7l?ag(9L4ySe1A(EuraYQ;Yh; zjpKIQq2Q@1o`$EFT4)^Owv4QrVQTLVUh}20jD8Ssqr}2Z_Wu{msLsQlmzGh&YF((C zj(sMcrQq2ro`dHKY%8g5hBTP%SapVNXF_1SwzT3lPko7XwcBtrDX%f%cUQ#xe7r!x z3st-bFJ^8k3A5vi$a_Ev?9jc$sNbtBW3S?682blHE%l*1HY8jZ;F}dkfOq1h3SOq- z<#>g_fu#T}CXidpbi2j{t}Yc_0U&OxyYMOnuU7FIyjEaWNq7Pgq0QORvX^U_PW!F# zSjo_juRw1@C0s>inrq(tSluN(+Q%lxJWjde%ByyIGOg2Q1+Wr!x1 zM_j}50)$TS1Tzm$iN&KN1SGc+-%{~ye24y;a!k+Ylbw8{8>Ex-@18L2NF#ku#rN?8 zmdB8kz^&1k31?nl_;=z*Dt;{MO_k|3`vJ$8|0(x>jh{NX8@n@>$5UFL>6&cw3ob0G z{Q#J4&}4ycko~H3@$6u$B`-$gCzs#Kn|ZF{A-~r?_;#FOq#xN{C(VHu=y}r^u#D9*B9w! z2m9I2wM?^v9SpiUR?$W)DO*}Ldo9xmBki{o3jWNdHou4Gz6e~gh;Dh~LajTCC7eNq zj+vBsvo%>n@xEeff+RHCDRSm7`KIwH_^hZq191<3#PBPBk{n!xU-Q2jOu%pOTfPCm=q^4bqXB}|XF&JmFwWm6a=2{< zQ!(`OWnJ}?%1AYbr)2Sr9G;iOOJ?xO7^+_v48KA0d9yzxr|UVq^BjhKY5jR3Yp4{w zHCc^o=*MfZhZGL865oWq5x@f>;6HM1IidY&&d-102=LcA=y!+E6H=u#<_z8&D-QpI z#o^x@!Y|L^z9IzXWG*0afJgKu+P#^V3I}QZLm1*!Mm}~D=OOX8M51xHIh;F(T{C!Sj>y7D z`t-f{Y!+YU0=Z32Wbw@`zB?OTKMbPlCn2+<(N&-(!fi9E7$tpJ%ebn?0AuVJ_VafW pH%AX{=JvP+CwX&{ch;##bXE-ipu8CViGT4KXGC7l8^C{~>VJ;7adQ9w literal 0 HcmV?d00001 diff --git a/target/test-classes/task/controller/TaskControllerTest.class b/target/test-classes/task/controller/TaskControllerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..76a156929d97a5116fc7c6d839fff153ee5611aa GIT binary patch literal 5892 zcmb_g30M^88Gio-8CWM5wq8lqDjGy(#8{h%njn$_;V^(8v4#x0BMdGxo0(Zq(=)w~ z^lsC;P4A{>(zq_MNo|{6>3!e#ecyMR_Wfsu-2oO{TOXc>+4<-DzwiC-@Bbfs=-&GQ z>=tEl#89T7T*V?(2wXg-Pv}}ow??$?;V~oO2~_MdEz{d0P*%IKKaNUNDTu3B3{_y2 z?Tl#ScH*e%*;;4tY_crd(>>F+T!AV(ZCLUHe{ZSnn9aR$V`Ql*q#L>r%N!vN9dE~848pE1vI1?$uadDrq>>?;_XJ zt)!l^Eu&Xb2;5M6D576rP^x?mLVEKor4b9_2z(_jRdAV#M_`pe^LgMYuxMB+Be1o$ zM35mU-&t!^JQ8aKl<@$mKz(VNPBT$ZBd{r9k84MC*E5`B<0)-SXXx0Lmef6c*tC*i zRCem=wBf|D4rMY}^DjRLCe$87MG0oQR3%o-JJ64*Zf4)1u{(8gTniiWLPJF}$E z95*`cWF}?AQ3oc{I@GJsu$6J>7$c@sA^0xPUwbwv0VRWDegJdyXAo?|6$-YicocRp z0R3Pex06Q7PY?RScc|eAtfot6eXi+awuIqJR#)OG1v^zVViz?iWNL?PjgZrXp2`^A zM+BDCwnwv8e&+5yxLUzADw?oY;L-&ov7pGWZ45IlS`d6b3uCOrK7qx(`gl5JtdZcQ z*lSfh2CV{>l53xFjAfu9%D2~(*-XPOfXT<-uHrfgz9PdsZ%f9}i7o}*D)!@gfn~ly zJo;SguoHS}pY9nl0$3I;dy*>CzVndy+^$$va z%+bxy#~V}}!ea%>rQ!mY%r<~ebfbzP+(fHNqF&ZFGeKM{16o<{`0mG2_^oj+h7*lZ+De6(Amk|Brs9~`% zM_oFjkjiQ!yN~N-hM6JkTh@rpXK(mU#1?D?X%#nvi4a6~9)&>6rXDp#`TGvdlaiB% zjDiUjlM--E6!3iF>2Z%5^spf~Rwa(}UDMO1Chg|NaSI-&;PEP+fG3t(#2w@2jO<8Z z+3X2k3vH;3b{BA?3WYiFzc-_(%vR4!%V=OHoGF_QeKKxU@DvqK#nS{fm(-I&HCSO- z(T~{9xWLic(i+Ds@g?@G9>dL~yrzUdp%C*k@Jt2IQt@m&N1&-B%#P2Z-~q|7Q}+_1 z{v1%jIl#*>=Jzq?&xIeGJ@*Cprr8nTZFru7=c{-DUMO(Q|I3gmWxCxg2s=teHvfPA=iPuUl5dDdgD9b&HCvkHTtB>8{IwD=>`cb+3xkcz?dFOSSxF zBIAn(qv=U(Zab&cTX4UM56Hq_p0-`D3LnIW6nt341NaCJJjLQ*l(kpuG?J#?$7z(u zwWj_1JKCC?`r5j?hT40(yC}S9$(gy4!as(OEBJ(p2k}XP_F}T;9D7P?0(6Qzq#2eM zAashS_bfam*U3WbTc{1K!>3hz2A}2FG3l6|(JyD$CO1grv&U_i@X|=1SMddWkcnRNYp#4>Y#pyG%45oI%$4bHrNgfEF2A;{bQO8kWR z9ZA#%8R9=v@pBpC6~T7d&3>ukS5mpfrrTx9(>jAiU`0>Hl5=ps>6$$M&$vaX_G5Y) zrJNWVxnag)nu5meG|NAC?7&Oc@XU@ZPUGrhE?<%V|5d>zZKd zm7bpWj)A-v@%Vp$hx@g@{ILu#N3^j_nqlVn%I`He#TYGmVwA+2B17=d00%+8@UK7Zq{@k%JN_FI3AhaI0r za*>q3%`t!Ton$2G4%X$M4Ahn1 zhuC0Q-95OVH-{xztT>6)b*Hgz@D$dc#0GxYa2j=d+nmLg0q$vt=kVw(c2_rN(GvV_ z%b_ESo-F!LVz7Xxp0{bh2Fkmf*E+RW&kKd^*o>>Ng$L?-v`~@juoc&%0Rueq7jPd8 zaZj7)FH!~kl{%F9I^52u)M1eD4o`t@$YF%P2Xh#of*ZpCUshKiE2DBboXFxyIXpd! z=T6~8F;u@iSbn9{;I;meBtM+Po6ca^=QdDKVkLzFJFtQ`2^$H0C;wWp3kR_~0(dY4 z{5R5;6WZVNp8Y3RfPdwo-w{GjNRiTfQ+QjfIQ(}OhyU&net8b>Euui4=Nu)Pc(QJ$ z?f3D1p#@#MU>K$<1*<2{qQt-RN<82z37n8hRBy}ST2eAPH>z{TR5oy86cf?4M3+^NZOrl_xKR)ly~!;}^?$ ln^DUY-;NvUkD&<4)&)_<@E`7vu@1;Qh%@B&V4H}c>c7cv4etN| literal 0 HcmV?d00001 diff --git a/target/test-classes/task/controller/UserControllerTest.class b/target/test-classes/task/controller/UserControllerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..20a2a361c996d7a6e9c5c374a8f3c9dc692b2e27 GIT binary patch literal 5497 zcmb_g340UQ6+KV38Cy&e;-n-%3Iq%o10Em^6igCiV+Rx2rr1Cnl9;hPw#OdLh?$XD zx}0gD8dOzAVaX6g2XHZVG6qmi zt5^(GV5Q?uXlW-kZTgPZS9m6D+wpbZbZk$c$;lYDoZ$B@t;xC4J2pm!5?SBrvK-IQ zM=hhH376vv1xr+1iDrQ{zV1zHDaZC*$FdApJM0;5SLt=g@CfztY{j6!>g2-PI^wt* z&rq;b#WlEAV7KJsWn9yq7)=>k%L_S%>hg(zqd*pzb8+PLodhI=Y)X;V5~$Fa3B-PcD= zdo1+IK0T8$+&I>vPWs6P6|LAPpgMui7G~*i$%_z1i*CYZ1zS|KL*r=%o|AUQ3@h+8 z5(}(jxB{zapE=Vl(jP-#pr~!wuHXh0&%%v#%d*=i9eaY3W^^lS42%n0)p{Tr0&<$W zcjDO!cB$Bn4uKU5Xkv6qm+$47Y0>BkoIK~wLJnz|xU$Y_$;)$_BXi~#0kd&1#!FnlNCF&GNQRZL*A=xikv0x^ev z)>2je9Kee)g=qzrinIjW5(WHp>ILFH860B5bL~breAo1hsY!c#ah!mwz*FHPTWgYX zjT2d!al^E5sPI}&vvst)fEOhc`sV+iY@<5&`+i1x12cW4ZXW1KoKkRF#Th(TU~^45 zH>AO!XT}Ae7r!xJt|&^7YQV4!t4ej$|oQN z_UV3VGH~@pyyyHZeSTl9*F-3fml^jJ@D;@o;JtW>f|sgz8D1{1_hJB66UdMFUE>MB}Q63d(^MXZO1xkXv8}Cr@PP~g(>Wtx<11#}#}+#V7G8mdn+wJju+a^%-NPK6E<6Yj8>8;K5{XS7NAl zpnv4R-~cb%ma3VlawC<01`jECSjA`Yh`@nry5<$lHKkbIsuvy;T6K`7C5w5(%@bASF zDn2iBX_M)7xrXi=V~zL%QM9xNg`M=fFR6GEUoI3evV!S6Eo;aMhYxGWa*Z&Mkynat z(L`Ux*A#qRRvb^!O7oWpv_^@RB6I#qCarI>a4**k+O|e~n^i=nx1~AeYpP{z2qV6g|Y{ZY43L{c??UEPGPgML=S|)CK{f^(`WNorub|`E6X4*Jn zdL}#1ivG1Zh=*bgChu}q98M>$&Fzqy0Ul`qbYLbh! zNO?MPlqFhFsCJ)XmKiBjYrG{B_Lv-&w z?e)b(Ho~wm1L;L|p)U$-Ahe>>jRc5T&-RWL*Og!iY>ck#ckKC#%f}cWbh2*B=rN_W zuaWXAe;#O;bm(fmw#_M-lnt7GaR8*y!(%mj$rwGYfuHPU`7I{f2MGL(-xu-u^I(j> zNJPed5sa|`4W8^tg0)hL-0@4kX?zMk8`{o6JQOVZRj^17F2%3;sTLOCH~1~zfZuU* zEZBTM1<7?iZFwk1+v*=jY`CuN5nMKy$5lBjJBw9qk74cbIjlR2^<2~z&tq#2JDT_8 zaC38K4*QyK&7n7k2WN3qAdkEFeISq2EX){=@?}-CT}K*uWOA6v<9Ru} zcoz4?(EQrM@arY&`-365oJ8M#9=8Y5j+O~5r&8bsEW?e2zJuNJPVC1nX1CoDz{4Tn zKXPq7q5Y|JmVe<0@YfRbCxdz5j8xgYDUWxb$EI1lFIJ>5AOD9Q#z%AbG&ij0|A8FN z<}h32^mu{O`64GC$2?9IY9id$qlwsV#!7bN?MRSSCl6yUKf5r9ee5WEa2mHpc%Hcc z&%c#;J{TU6E_q5{nZ*}N9P{`}gyuJ@AJeyrl&T$5Nn(Uf;izt7L*GZQ>L;-QB-y?n zXRwrgOTPexzn3W77gFe#6t2d1A|&$oZiK)O=MebuT&Id`j^JI&r~m_h1)XUVhUr+x fi2Tk7*8T;t#_$jBkKv#A7oTyu-A>B+H=6zjuIPfF literal 0 HcmV?d00001 diff --git a/target/test-classes/task/repository/impl/NotificationRepositoryImplTest.class b/target/test-classes/task/repository/impl/NotificationRepositoryImplTest.class new file mode 100644 index 0000000000000000000000000000000000000000..3da8c4467c07c079efa576339f2ee2174f6329b0 GIT binary patch literal 5028 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 F`X4~Yo16du literal 0 HcmV?d00001 diff --git a/target/test-classes/task/repository/impl/UserRepositoryImplTest.class b/target/test-classes/task/repository/impl/UserRepositoryImplTest.class new file mode 100644 index 0000000000000000000000000000000000000000..395f821ac534e326126f6adfc76a37f5866d7cd7 GIT binary patch literal 4202 zcma)A`F9iN6}{sH2{8~Xz?hH*g(Y49D>j5QF%T~`t%$HG22-5Hm94QoAdi%pkqJrL zlbEJy8X6kXeM!1E-GP8C;^5@x{xte4`d{?)zL}9Uw(Jw&Ak93z?|t{(ci;QI!+-ww z$r6BL_&kC-)Q8ZZq7my9Y`&P9OT{xOV>&)OaZ#JJ6|6g|8@hd5L48~MXb52it#-<~ z6gRb8*3#{)c_psT<}&efmS&!**b+2F5JLTWY=9cVMirazkb?aWxc01OaqmcV69w(b z2VC0|K@*}OY*Dcl+Y~(HuA9xKH4mkN&_rI(q%~8)t~Nhx_2<2kNx$dN6UKH@kjYN# zMppzo@Nft_RXl<(DcHFpY;c`|Mt6;ZuC`>A(-GU$jp?2*+Hw~W=2Di`)qP0zd`!h| z*)S}&%ULrW#$E-R@`TydJDbuoos-#FaeQ1wt2j1lVhy8R!FtzgC^f5z!+sS9+(=?A z8#`6R@dQ`7q$t=@OG%GZv0KF<99GaEixo6^<*4#T+Cw;^;wgNYPF8A8Q?R$K#;YcI zw_MMt=)qCqo!0DgjGss=h!RMZyJVKkg+U>}?YpmUrZlwEUbtQwmt!Ls%-LiW&;3S?4A*tdN zhFC>6!OG7gR7a$vpe@KvnF%k7 zo6vAhNKIu};4wTO!V4;1#7ktQnseEOh1adqre=z2jkKR5S#>-St-ne9BFB?LfrNS20Lb^3Lo3pQkF~`1gKA`rC%=9L6 z{gfpyT`j#K+Hmg0%A|@WUr})duM(;72m zmUO~+j}v7Dj_$R3=z19M^OVfz(kWX@S7M4Nexl;1_!*hDG<#6yuYzqsrppb&QPGQE zh%kT2Zf_fFr=bbIR`Hv%q}?{Tc6cNbxUW^KEue`DSsC4POd($`?aa8sSTzkXBcRY95mxY+GUwb<9(K; zPa9Su-DjjncsJ23G0S%JqV^wIBczXN-|`VRE{g|W;n=pu&uDhuH2iSu7&xDi5wY61 zoo)>! z)_L8Y3BVej)6B~z4{C2?CMHgt=Ofv?IjNn{MV33ow*2NP6~WRQ$>P zbRF<#{Dp78NBp(UU7SO`>(|k-h|q-vtiOv$M-iK&%>}eXA1xpj-BZB6Xj=gt1suGK zuIdiE5oW9{gt?6~qM3iUV<%b&dDPd;O`YAGejckwsqVg zggfXe;K}6v0-lZ@E8^J(u@*3R4+*yVa1mdx;)tSw>tf7x50UKUEpwl{Z?hNA-&gL% z{~&z|$_V}`0PwF0f;Z_e2;u<*=jBjNWDvWGpho0 z5XeE2@dS3E3!Uf=fQkEHnn}^Wag$(VwaRbLa=QlJ#}#;{4=+{&FXzKEqj|!s;_--i zit(Re{A0v(Jb)!u!4j##B9>Y#cPd!kCzg65KNP@{lxHbe0hdo5D3e9QYkcwOdTkZD z1_St6#eoYU(bDtE&*_S#Hy^ysm``*ePFGEdp>WzEi~O zgedhiqu*Ob*d}+^(`>g9YWZw{tQH^1CPdu*tA+C{wPY<+_P^!tKM)|x)s^(w_odH% zAboaC`s`h=&!~OZgNjc!?)OChBVY8M);igCzy*>wM$tddc6)*KeUb8ii48DL6^>DR z6F345{g?`*GT^6j1RGJry?_Qi%O^D&T&$$>5mS-6_Xbi)?vLIm;KzRTJ={SV6!G)u zjfw<*75$)y-&QsHD6fIwg;hlcQDj+OllU!SxA83U0WtJe#BkUbLo2&zxfndlN-@;o WQ|?iR`;h-vh%mn$99W-W{r>@}U7a2P literal 0 HcmV?d00001 diff --git a/target/test-classes/task/service/impl/NotificationServiceImplTest.class b/target/test-classes/task/service/impl/NotificationServiceImplTest.class new file mode 100644 index 0000000000000000000000000000000000000000..00e13456c389a1785ab75bb30f76144dc4dbe853 GIT binary patch literal 4239 zcmb7H`(GT@75~lxS=n4;Bm|pB6O4!pNY)yS3NZ>uWa9=Z5YY5Nhh-p>EHmpoFxcAG zwx7NqwzUuKLv5|K@7n5i(blG~U;0P&)9;y?UGBotCVW23+`0Fjd%owK?>YDEzyI^j zdjKB9zcNUnC5={vHtaI6_ma70=1QislABt*WEBGgyH44T9h^4MlI@$z;0Cm(kx|$U zW#EYGt>jkS;$=H8zbw*;ntnW~noQf|@>>}9(c=`fI94DHgA(OOKV*#q@ z#Qrq86mG%$4D8uNS8$ybp1fw3LThT-z`pER9jPo+`XCOaaaiH~IAUPnIy6%keN?w0 zzhvMc-8s?u*JsNO=r(ZUES=QtS*x}~hX}x93b&!hKx<%KVJt^47$IU?+k`dPWpRF-Di@Leo~+^_gGZx`Avg?$xIn za$$4l@NSIbOd5|WOdxNdH$we?#Yp*OQfH)8GSESvM9~TZyOb-~e!!4ChC&+W6ecmn zq-c`-WZKggEk<=nk5pVr$TVHT55mPo5->OAthjv7B;UmTIHuE>QJBT~T3Xgo7)ZIy z$eyO>Zvng;^LQeSClxLT;GSzyZy*!Uf@v!VJx7B7VTF(2qcm3!N)l(LeH@W%Aq4&R zF_>vADikFseb-DSDqpbzhGkN#8ov0+QdkB{RjY45V?`x8pMi}_XM2Se=0OftkZ4Te75@P^C`$ z3IRg0hx=xuLep7ePjrRwS?^#x&T zUPfP1_%gmiXW0JuYB?ZWUYr-i_OB^?9p50qVt>ziAw$;6@<(Tn|Usd=Cek!~(*J#8&NnzT4Kkt0KMCtG|h1cbrjv|2vmhN9s z|AxXZ@Jn87v3f2~hEkmN>*1?&h2?cRbOL+TnzMbIO+-U0($P?Tq$e4cdaT!kydy17 z)UI%?b&TDHftw1pV@-yuic6?0VL?S-i;2eGKQ;I_;xYLQvC!@qkQ%-3;o}sJ4C~-*S?L3U}>Z%uJNP3^CnViI2kHuJ6GBa-I6|FP25T#p} znrUnej!U^=#^oKy^2SO+a9X}kmq_|lbn_NUvB7HLll=h<{EA<@`2IEDDY>4sx!*){ zY*zSA^Phb^SAWYEmaIwaCZeK-^S3Us$R77(8I)Z1Q{Gf2W{)Z ztsEUgFFVyc(Sy5jy9VV%0;Oj0TM?|c>#*L4yaG)2zlDc4@Q8sb&T>3d#RoSqm%=<#b3{VvpJB|*tY`{t3D)v<1Rk0?*Rjgmdcyz?PAa04AbC8;VJ{-URaSrl% zoIjg#IET9;lwEWWwI?WLM+NjQ)x^$>XEr!fv)~=B0PofAH_+cyC3)A0iqvjf_{(|HlmMbwxj=Z9sSD*`n*X6bWKaE3pm;o3iF~-=OpoY|3v$L E0o&zvxc~qF literal 0 HcmV?d00001 diff --git a/target/test-classes/task/service/impl/TaskServiceImplTest.class b/target/test-classes/task/service/impl/TaskServiceImplTest.class new file mode 100644 index 0000000000000000000000000000000000000000..8cbb5b39b86d0f90e23839fe91636f1184a2bae0 GIT binary patch literal 3916 zcma)9`+pP15&y1i5Qv2kL!3Ye24g_B3ra%k5=>}hV}cT46YSV6q;=2I*&Lkj9No#_ z^pU=jzT5QuPTy_%ZrY&8X`ANf{!#t(J9{VTEE_jJ=x%R!cIG=X-Z&=G#&b7RS+{D}syA&#HJ?nT*cut`s+drMbHf&ELqp<^8;hiU6g&AIk)2D@-i z8oM>_MVG=op%vVusj}_nrZ`kc&s80_Y*!R|vi-%jFYZgDTjPE_ps=fj zqUd`I)U<55ReNGyVNdp{BqCYn?)`W$jRP7F;h@5Un^a%%`!SaUBl%AWq$=vMuttg#o}x%v zZbCfDn?d_4jbDrK&PA(oGaq*^9(Vh$R6XhS(@x;<^j>oZ=vvc)HEA!IQg& zxhHU~bCkzCkNl$J+2hs4IpG79vOk&wYTBwe@*PihhSwcd*zy109OMX~`Yi!TwxrN& zAgnLr5qsXR*ke}dI)w+wjz)8sonezQ)Ev9b-aH%it3YO?SF?~Rc2IRW*d0Z$)fE-G z*J58;YT!T8CVO@r0nQP}fxCc>eL9*X`79ael%tYNf@GA2l5%k|%uaajO2I3|1!Wv; zY>P#Bq(!H@EJo_hXp)>Y{__$Q3CPu_MWjfyP@WyNTsLSPn3vYFCo}0+D<%7aBT0Th zG*7NQxKB#CvBCcg{-qqM0{1YItymD?qL3!K<+c7X^ewZWSx34ZVoM`iX=mE!@qG z3GCgBF?hp#2t)MXG*00$9)@QUxG%=I`taqp0bmtW&Qc`Ks zKrlnA_;%Bs7L#P9hVK^#>-Z6Q)J~t~MuR=7s0e$3|4*LAF%oBhbUB3yrs8q}dm|Oc zSOlvq*LK3Z)kOLX11~k&Lt`@$Cw|IdOyGzJzf95HMoI7D24IT+WT$ZuGsb9C+C6R6 YCEQHmALjW_{EP1lP3`9;;%#jIA6=LR0RR91 literal 0 HcmV?d00001 diff --git a/target/test-classes/task/service/impl/UserServiceImplTest.class b/target/test-classes/task/service/impl/UserServiceImplTest.class new file mode 100644 index 0000000000000000000000000000000000000000..693fff7bd0c60cdc632dd7cbe9b72fc68e7ec325 GIT binary patch literal 4282 zcma)930oW26+I)s65@q8itWb6v5k!lh!}+=t{daH27+UyG7y8Iagx#j4R~xZqs)wO zNcX0D(j`lq?)#FaZTh866p?Q3-lqE>>eq8;Mq(u4Q1f}_&3*6Pcka2%yL#ilum2jr zJ@`)&F|@?ds?dgQ8n$27SM^Lmx0W-L3zv;WPs6s8re%7kG_>^f&nA&TdmKrH4k!)# zY-c&MVlQ4XJv(zQc#l|??dhIrTdsz7yJ%Q4!ST_)T%-2k{)lL#myTVOKX}HnT-77pQZxk{YT*J{2UnrS{yo~nu_2(LkqljdhyZ4|gj=c)EVxNYtH#v!9m3VG8uOSmP*4Ojq z7!x=^wq$qCUN$W`^q|5a^k`@+h(yCsROPhim;|?#(j(kHbjO`{9TSCp3jLxmQPf@c zs_oKcl^-b-G^A*o zA2}t@EM#(~>oGLWA{)p33hzLU)^CyxH00_fgWfw4^s_>y;K3=+w-lwQTb} z9exw@1SaE{Qg{I8tMOYyp&@27bbB_{-vGD+Gq@1PtiqfC?)iU?*O2sR!Fj_gIhHu{ zL4}KWNJEE^ANozhp@4acuIpIx^$6Y-$GpP3h5YU-<1w!Un( ze^#^?6jnfIweVC8JNvTHY7jb23R6+xQ7}3Moj{ZH(XgW$A%6V~GgQ!d0cM~5) z3Sc!VSY^-Rs={MnL~mO)9CL|-Bb#jA6y909N8!DAAI;D$Zaf^_I98zTb!9g^RTAR^ z3LnIWgj{`<_AsOxid}QP@qPM)!bfCZ!ZDVa7ltE7e@x-y_yp@nK=y>~O_U^$c1Gbu zOzy;|6rL1T6J*t|f`aMO3ZKDe8TFEgqiY*%_eJ&8%Hc-9PZq`7dVvU^#xrp|E9vtb z^SF75hB{?cP?287kiz_YLrRATBJSJ@)0Y&!jIXfjo9>ijxQ4}$;~jfZ$orbY z*YOReUO?WAQ=&gw`!322{4~BLVfyXHfD2(K@LlS>>hSKG;%-_0eT5&$NpaI1UnzQP z!s`zeUc`?`cEGFLS#=Q>-dW9L`5ym?!b`HdngF9~*?b#23i-DvNB&IV=Xiy=WypaV zc2#r3uUj=bHS9iLvOIIem^EFK_kLaXkgBVX(nbt(L!B^dNtfbx7@TVzV}rnEA!k~~ zL}_KgaAu^Lpwn~qqF$KQ9aFwTVXJq^Wcv4RUAg2+qWU(M>0Z=u(1*}mV@8c7+cC!V z#YNSNgefKq{j?UA7K?-){7kA1CJ#eb+_?a8Ke zJw+UQuLCx;X>T=W=V$eTnHNa&(@cLKoS4ipW8Raz4p|vCm^i>&F~-Pm;gfv{G`z~MZG4ycj>&Zy zk-g^2*bMQV;D0vWoUL$_;ad|)`ZZ`Ta}dKipE3=$!LReFf(7^me#tN3SDcOcn@ec* z=LXUh#OL_9Az8uAW$aGvFQYqkxQyOZx{TXWgJs-a#+|R?_{I@O&`xEy63c!hX-^8> zY?cpVFDqR)diZx3X&i|_7ziO$EtTIBz;9}BUhvrfCep9qo^_0fh4*oMyn=JHIvvdlb$X*?XUVv=kVXXDPz_w737kk8!Nu?oYK!5Y_!r+v N#>^hJ-Ty}W{{XR%U1tCQ literal 0 HcmV?d00001