package eu.ztsh.wymiana.service; import eu.ztsh.wymiana.EntityCreator; import eu.ztsh.wymiana.RepositoryBasedTest; import eu.ztsh.wymiana.data.repository.UserRepository; import eu.ztsh.wymiana.exception.ExchangeFailedException; import eu.ztsh.wymiana.exception.InsufficientFundsException; import eu.ztsh.wymiana.validation.InstanceValidator; import eu.ztsh.wymiana.validation.ValidationFailedException; import jakarta.transaction.Transactional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import java.util.stream.Stream; import static eu.ztsh.wymiana.EntityCreator.Constants.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; class CurrencyServiceTest extends RepositoryBasedTest { private final CurrencyService currencyService; @Autowired public CurrencyServiceTest(UserRepository userRepository, InstanceValidator instanceValidator) { super(userRepository); var nbp = Mockito.mock(NbpService.class); Mockito.when(nbp.getSellRate("USD")).thenReturn(USD_SELL); Mockito.when(nbp.getBuyRate("USD")).thenReturn(USD_BUY); currencyService = new CurrencyService(new UserService(userRepository, instanceValidator), nbp, instanceValidator); } @Transactional @Test void plnToUsdToSellSuccessTest() { var entity = EntityCreator.user().build(); userRepository.save(entity); var result = currencyService.exchange(EntityCreator.exchangeRequest() .from(PLN_SYMBOL) .to(USD_SYMBOL) .toSell(PLN) .build()); assertThat(result.currencies()) .matches(map -> map.get(PLN_SYMBOL).amount() == 0 && map.get(USD_SYMBOL).amount() == USD_BUY); var expected = EntityCreator.user().pln(0).usd(USD_BUY).build(); expect(expected); } @Transactional @Test void plnToUsdToBuySuccessTest() { var entity = EntityCreator.user().build(); userRepository.save(entity); var result = currencyService.exchange(EntityCreator.exchangeRequest() .from(PLN_SYMBOL) .to(USD_SYMBOL) .toBuy(USD_BUY) .build()); assertThat(result.currencies()) .matches(map -> map.get(PLN_SYMBOL).amount() == 0 && map.get(USD_SYMBOL).amount() == USD_BUY); var expected = EntityCreator.user().pln(0).usd(USD_BUY).build(); expect(expected); } @Transactional @Test void usdToPlnToSellSuccessTest() { var entity = EntityCreator.user().build(); userRepository.save(entity); var result = currencyService.exchange(EntityCreator.exchangeRequest() .from(USD_SYMBOL) .to(PLN_SYMBOL) .toSell(USD_SELL) .build()); assertThat(result.currencies()) .matches(map -> map.get(PLN_SYMBOL).amount() == PLN && map.get(USD_SYMBOL).amount() == 0); var expected = EntityCreator.user().pln(PLN).usd(0).build(); expect(expected); } @Transactional @Test void usdToPlnToBuySuccessTest() { var entity = EntityCreator.user().build(); userRepository.save(entity); var result = currencyService.exchange(EntityCreator.exchangeRequest() .from(USD_SYMBOL) .to(PLN_SYMBOL) .toBuy(PLN) .build()); assertThat(result.currencies()) .matches(map -> map.get(PLN_SYMBOL).amount() == PLN && map.get(USD_SYMBOL).amount() == 0); var expected = EntityCreator.user().pln(PLN).usd(0).build(); expect(expected); } @Test void insufficientFundsTest() { var entity = EntityCreator.exchangeRequest() .from(PLN_SYMBOL) .to(USD_SYMBOL) .toBuy(PLN) .build(); assertThatThrownBy(() -> currencyService.exchange(entity)) .isInstanceOf(InsufficientFundsException.class); } @DisplayName("Invalid PESEL value") @ParameterizedTest @MethodSource void invalidPeselTest(String pesel) { var entity = EntityCreator.exchangeRequest() .pesel(pesel) .from(PLN_SYMBOL) .to(USD_SYMBOL) .toSell(USD_SELL) .build(); assertThatThrownBy(() -> currencyService.exchange(entity)) .isInstanceOf(ValidationFailedException.class) .hasMessageContaining("PESEL"); } @Test void notExistingUserTest() { var entity = EntityCreator.exchangeRequest() .from(PLN_SYMBOL) .to(USD_SYMBOL) .toSell(USD_SELL) .build(); assertThatThrownBy(() -> currencyService.exchange(entity)) .isInstanceOf(ExchangeFailedException.class); } @Test @DisplayName("Empty 'from' value") void emptyFromTest() { var entity = EntityCreator.exchangeRequest() .to(USD_SYMBOL) .toSell(USD_SELL) .build(); assertThatThrownBy(() -> currencyService.exchange(entity)) .isInstanceOf(ValidationFailedException.class) .hasMessageContaining("null"); } @Test @DisplayName("Empty 'to' value") void emptyToTest() { var entity = EntityCreator.exchangeRequest() .from(PLN_SYMBOL) .toSell(USD_SELL) .build(); assertThatThrownBy(() -> currencyService.exchange(entity)) .isInstanceOf(ValidationFailedException.class) .hasMessageContaining("null"); } private static Stream invalidPeselTest() { return Stream.of("INVALID", PESEL.replace('6', '7')); } }