| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- package service;
- import com.danielbohry.stocks.context.UserContext;
- import com.danielbohry.stocks.context.UserContextHolder;
- import com.danielbohry.stocks.domain.Portfolio;
- import com.danielbohry.stocks.domain.PortfolioStock;
- import com.danielbohry.stocks.exception.BadRequestException;
- import com.danielbohry.stocks.exception.NotFoundException;
- import com.danielbohry.stocks.exception.UnauthorizedException;
- import com.danielbohry.stocks.repository.portfolio.PortfolioEntity;
- import com.danielbohry.stocks.repository.portfolio.PortfolioRepository;
- import com.danielbohry.stocks.service.ExchangeService;
- import com.danielbohry.stocks.service.ExchangeService.ExchangeRateResponse;
- import com.danielbohry.stocks.service.portfolio.PortfolioEncryptService;
- import com.danielbohry.stocks.service.portfolio.PortfolioService;
- import com.danielbohry.stocks.service.stock.StockService;
- 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 java.math.BigDecimal;
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- import static java.math.BigDecimal.TEN;
- import static java.math.BigDecimal.TWO;
- import static java.time.Instant.now;
- import static org.junit.jupiter.api.Assertions.*;
- import static org.mockito.Mockito.*;
- public class PortfolioServiceTest {
- @Mock
- private PortfolioRepository repository;
- @Mock
- private StockService stockService;
- @Mock
- private ExchangeService exchangeService;
- @Mock
- private PortfolioEncryptService encryptService;
- @InjectMocks
- private PortfolioService portfolioService;
- private static final String APPLE_CODE = "AAPL";
- private static final String APPLE_NAME = "Apple Inc.";
- @BeforeEach
- void setUp() {
- MockitoAnnotations.openMocks(this);
- UserContextHolder.set(new UserContext("user-1", "user", List.of("USER")));
- }
- @Test
- void testGetAllIds_returnsIds() {
- //given
- List<String> ids = List.of("id1", "id2");
- when(repository.findAllPortfolioIds()).thenReturn(ids);
- //expect
- assertEquals(ids, portfolioService.getAllIds());
- }
- @Test
- void testGetByUser_mapsPortfolios() {
- //given
- PortfolioEntity entity = PortfolioEntity.builder()
- .id("p1")
- .user("user-1")
- .encryptedStocks("encrypted")
- .build();
- when(repository.findAllByUser("user-1")).thenReturn(List.of(entity));
- when(repository.findById("p1")).thenReturn(Optional.of(entity));
- when(encryptService.decryptStocks("encrypted")).thenReturn(List.of());
- when(exchangeService.getCurrentRate("USD"))
- .thenReturn(new ExchangeRateResponse("USD", "", Map.of("USD", BigDecimal.ONE)));
- //when
- List<Portfolio> result = portfolioService.getByUser("user-1", "USD");
- //then
- assertEquals(1, result.size());
- }
- @Test
- void testGet_withMissingPortfolio_throws() {
- //given
- when(repository.findById("missing")).thenReturn(Optional.empty());
- //expect
- assertThrows(NotFoundException.class, () -> portfolioService.get("missing", "USD"));
- }
- @Test
- void testCreate_savesNewPortfolio() {
- //given
- PortfolioEntity saved = PortfolioEntity.builder()
- .id("new-id").user("user-1")
- .stocks(List.of())
- .createdAt(now())
- .updatedAt(now())
- .build();
- when(repository.save(any())).thenReturn(saved);
- //when
- Portfolio result = portfolioService.create();
- //then
- assertEquals("new-id", result.getId());
- }
- @Test
- void testUpdate_validStocks_saves() {
- //given
- PortfolioEntity existing = PortfolioEntity.builder()
- .id("pid").
- user("user-1")
- .build();
- List<PortfolioStock> stocks = List.of(new PortfolioStock(APPLE_CODE, APPLE_NAME, 5, TWO, TEN));
- when(repository.findById("pid")).thenReturn(Optional.of(existing));
- when(stockService.isValid(APPLE_CODE)).thenReturn(true);
- when(encryptService.encryptStocks(any())).thenReturn("encrypted");
- when(repository.save(any())).thenReturn(existing);
- when(encryptService.decryptStocks("encrypted")).thenReturn(List.of(new PortfolioEntity.PortfolioStock(APPLE_CODE, 5)));
- //when
- Portfolio updated = portfolioService.update("pid", stocks);
- //then
- assertNotNull(updated);
- }
- @Test
- void testUpdate_invalidUser_throwsUnauthorized() {
- //given
- PortfolioEntity existing = PortfolioEntity.builder()
- .id("pid").user("another-user").build();
- when(repository.findById("pid")).thenReturn(Optional.of(existing));
- //expect
- assertThrows(UnauthorizedException.class, () -> portfolioService.update("pid", List.of()));
- }
- @Test
- void testUpdate_withInvalidStock_throwsBadRequest() {
- //given
- PortfolioEntity existing = PortfolioEntity.builder()
- .id("pid").user("user-1").build();
- when(repository.findById("pid")).thenReturn(Optional.of(existing));
- when(stockService.isValid("FAKE"))
- .thenReturn(false);
- //expect
- assertThrows(BadRequestException.class, () ->
- portfolioService.update("pid", List.of(new PortfolioStock("FAKE", "FAKE", 0, TWO, BigDecimal.ZERO))));
- }
- @Test
- void testDelete_callsRepository() {
- //when
- portfolioService.delete("pid");
- //expect
- verify(repository).deleteById("pid");
- }
- @Test
- void testCleanup_deletesEmptyEncrypted() {
- //given
- PortfolioEntity empty = PortfolioEntity.builder()
- .id("pid").encryptedStocks("").build();
- when(repository.findAll()).thenReturn(List.of(empty));
- //when
- portfolioService.cleanup();
- //then
- verify(repository).deleteById("pid");
- }
- }
|