package se.bilhalsning.service; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import se.bilhalsning.entity.Order; import se.bilhalsning.entity.OrderStatus; import se.bilhalsning.exception.InvalidOrderStateException; import se.bilhalsning.exception.OrderNotFoundException; import se.bilhalsning.repository.OrderRepository; import java.util.List; import java.util.Optional; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class OrderServiceTest { @Mock private OrderRepository orderRepository; @Mock private OrderNotificationService orderNotificationService; @InjectMocks private OrderService orderService; @Captor private ArgumentCaptor orderCaptor; @Test void shouldCreateOrderWithPendingPaymentStatus() { UUID userId = UUID.randomUUID(); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.createOrder(userId, "ABC123", "Hej fin bil!"); assertEquals(OrderStatus.PENDING_PAYMENT, result.getStatus()); verify(orderRepository).save(orderCaptor.capture()); assertEquals(OrderStatus.PENDING_PAYMENT, orderCaptor.getValue().getStatus()); } @Test void shouldGenerateIdOnCreate() { UUID userId = UUID.randomUUID(); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> { Order order = inv.getArgument(0); if (order.getId() == null) { order.setId(UUID.randomUUID()); } return order; }); Order result = orderService.createOrder(userId, "ABC123", "Test text"); assertNotNull(result.getId()); } @Test void shouldNormalizePlateToUppercase() { UUID userId = UUID.randomUUID(); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.createOrder(userId, "abc123", "Test text"); assertEquals("ABC123", result.getPlate()); } @Test void shouldTrimPlateWhitespace() { UUID userId = UUID.randomUUID(); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.createOrder(userId, " ABC123 ", "Test text"); assertEquals("ABC123", result.getPlate()); } @Test void shouldSetAllFieldsOnCreate() { UUID userId = UUID.randomUUID(); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.createOrder(userId, "ABC123", "Hej fin bil!"); assertEquals(userId, result.getUserId()); assertEquals("ABC123", result.getPlate()); assertEquals("Hej fin bil!", result.getLetterText()); assertNull(result.getAmountPaid()); assertNull(result.getTrackingId()); } @Test void shouldReturnOrdersByUserId() { UUID userId = UUID.randomUUID(); Order order1 = new Order(); Order order2 = new Order(); when(orderRepository.findByUserIdOrderByCreatedAtDesc(userId)) .thenReturn(List.of(order1, order2)); List result = orderService.getOrdersByUserId(userId); assertEquals(2, result.size()); verify(orderRepository).findByUserIdOrderByCreatedAtDesc(userId); } @Test void shouldReturnOrderById() { UUID orderId = UUID.randomUUID(); Order order = new Order(); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); Order result = orderService.getOrderById(orderId); assertSame(order, result); } @Test void shouldThrowWhenOrderNotFound() { UUID orderId = UUID.randomUUID(); when(orderRepository.findById(orderId)).thenReturn(Optional.empty()); assertThrows(OrderNotFoundException.class, () -> orderService.getOrderById(orderId)); } @Test void shouldCancelOrderWhenPendingPayment() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.PENDING_PAYMENT); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.cancelOrder(orderId, userId); assertEquals(OrderStatus.CANCELLED, result.getStatus()); } @Test void shouldThrowWhenCancellingNonPendingOrder() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.PROCESSING); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); assertThrows(InvalidOrderStateException.class, () -> orderService.cancelOrder(orderId, userId)); } @Test void shouldThrowWhenCancellingOtherUsersOrder() { UUID orderId = UUID.randomUUID(); UUID ownerId = UUID.randomUUID(); UUID otherUserId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(ownerId); order.setStatus(OrderStatus.PENDING_PAYMENT); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); assertThrows(OrderNotFoundException.class, () -> orderService.cancelOrder(orderId, otherUserId)); } @Test void shouldUpdatePendingOrderLetterText() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.PENDING_PAYMENT); order.setLetterText("Old text"); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.updatePendingOrder(orderId, userId, "New text"); assertEquals("New text", result.getLetterText()); } @Test void shouldThrowWhenUpdatingNonPendingOrder() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.PROCESSING); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); assertThrows(InvalidOrderStateException.class, () -> orderService.updatePendingOrder(orderId, userId, "New text")); } @Test void shouldConfirmPaymentForPendingOrder() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.PENDING_PAYMENT); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); when(orderRepository.save(any(Order.class))).thenAnswer(inv -> inv.getArgument(0)); Order result = orderService.confirmPayment(orderId, userId); assertEquals(OrderStatus.PROCESSING, result.getStatus()); } @Test void shouldThrowWhenConfirmingPaymentForNonPendingOrder() { UUID orderId = UUID.randomUUID(); UUID userId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(userId); order.setStatus(OrderStatus.CANCELLED); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); assertThrows(InvalidOrderStateException.class, () -> orderService.confirmPayment(orderId, userId)); } @Test void shouldThrowWhenConfirmingPaymentForOtherUsersOrder() { UUID orderId = UUID.randomUUID(); UUID ownerId = UUID.randomUUID(); UUID otherUserId = UUID.randomUUID(); Order order = new Order(); order.setId(orderId); order.setUserId(ownerId); order.setStatus(OrderStatus.PENDING_PAYMENT); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); assertThrows(OrderNotFoundException.class, () -> orderService.confirmPayment(orderId, otherUserId)); } }