getDonations();
+
/**
* Este método é usado para alterar o endereço do abrigo.
*
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Address.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Address.java
index b45ccff..8d72060 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Address.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Address.java
@@ -14,7 +14,7 @@
* Este classe é utilizada na criação de entidades tais como {@link Shelter}, que precisam de uma representação de endereço.
*
* @author diegoneves
- * @version 1.0.0
+ * @since 1.0.0
*/
@Getter
public class Address {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Donation.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Donation.java
index 300f84b..1037214 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Donation.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/value/Donation.java
@@ -8,7 +8,7 @@
* Uma doação é caracterizada pela sua descrição e quantidade.
*
* @author diegoneves
- * @version 1.0.0
+ * @since 1.0.0
*/
@Getter
public class Donation {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/factory/ShelterFactory.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/factory/ShelterFactory.java
index 4c02e26..50cb3fe 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/factory/ShelterFactory.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/factory/ShelterFactory.java
@@ -3,12 +3,39 @@
import diegosneves.github.conectardoacoes.core.domain.shelter.entity.Shelter;
import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Address;
import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.exception.ShelterCreationFailureException;
import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+/**
+ * Classe {@link ShelterFactory} responsável por fornecer métodos para criar instâncias da classe {@link Shelter}.
+ *
+ * Esta classe é um exemplo de aplicação do padrão de projeto Factory, que fornece um método estático para a criação de instâncias de {@link Shelter}.
+ * Neste caso, a criação do objeto Shelter é abstraída para a esta classe.
+ *
+ * Esta classe destaca a declaração de um método público estático create, responsável pela criação de uma instance de {@link Shelter}.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ * @see Shelter
+ */
public class ShelterFactory {
private ShelterFactory() {}
+ /**
+ * Construtor estático para a classe {@link Shelter}.
+ *
+ * Este método é responsável por criar uma nova instancia de {@link Shelter} com um UUID gerado dinamicamente, juntamente com os detalhes fornecidos.
+ *
+ * Este método utiliza o método {@link UuidUtils#generateUuid} para gerar um UUID único para o novo objeto {@link Shelter}.
+ *
+ * @param shelterName A string que representa o nome do abrigo.
+ * @param address A instância de {@link Address} que representa o endereço do abrigo.
+ * @param responsibleUser A instância de {@link UserContract} quem representa o usuário responsável pelo abrigo.
+ * @return {@link Shelter} A nova instância de Shelter com os detalhes fornecidos.
+ * @throws ShelterCreationFailureException se qualquer informação do Abrigo fornecida for inválida.
+ *
+ */
public static Shelter create(String shelterName, Address address, UserContract responsibleUser) {
return new Shelter(UuidUtils.generateUuid(), shelterName, address, responsibleUser);
}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/shared/repository/ShelterRepository.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/shared/repository/ShelterRepository.java
new file mode 100644
index 0000000..5f77e14
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/shelter/shared/repository/ShelterRepository.java
@@ -0,0 +1,29 @@
+package diegosneves.github.conectardoacoes.core.domain.shelter.shared.repository;
+
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.Shelter;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.ShelterContract;
+import diegosneves.github.conectardoacoes.core.repository.RepositoryContract;
+
+/**
+ * A interface {@link ShelterRepository} herda da interface {@link RepositoryContract}.
+ * Ela define o contrato para um repositório que persiste e recupera as entidades {@link ShelterContract}.
+ *
+ * Tem as seguintes operações básicas:
+ * - Encontrar uma entidade {@link Shelter} pelo seu identificador único
+ * - Encontrar todas as instâncias da entidade {@link Shelter}
+ * - Salvar uma instância da entidade {@link Shelter}
+ * - Deletar uma entidade {@link Shelter} através seu identificador único
+ *
+ *
+ * O uso desta interface é específico para operações relacionados com objeto {@link ShelterContract}
+ * e as suas implementações devem ser consideradas para trabalhar com dados da entidade Shelter.
+ *
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ * @see RepositoryContract
+ * @see Shelter
+ */
+public interface ShelterRepository extends RepositoryContract {
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/User.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/User.java
index b6b8427..79faa7c 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/User.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/User.java
@@ -4,6 +4,7 @@
import diegosneves.github.conectardoacoes.core.exception.UserCreationFailureException;
import diegosneves.github.conectardoacoes.core.exception.UuidUtilsException;
import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+import diegosneves.github.conectardoacoes.core.utils.ValidationUtils;
/**
* Representa um usuário dentro do sistema.
@@ -30,7 +31,7 @@
*
*
* @author diegoneves
- * @version 1.0
+ * @since 1.0.0
*/
public class User implements UserContract {
@@ -75,25 +76,18 @@ public User(String id, String userName, String email, UserProfile userProfile, S
* faltando, em branco ou é inválido
*/
private void validateData() throws UserCreationFailureException {
- if (this.userProfile == null) {
- throw new UserCreationFailureException(PROFILE_NOT_PROVIDED);
- }
- if (this.userName == null || this.userName.isBlank()) {
- throw new UserCreationFailureException(String.format(USERNAME_REQUIRED, this.userProfile));
- }
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.userProfile, PROFILE_NOT_PROVIDED, UserCreationFailureException.class);
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.userName, String.format(USERNAME_REQUIRED, this.userProfile), UserCreationFailureException.class);
try {
UuidUtils.isValidUUID(this.id);
} catch (UuidUtilsException e) {
throw new UserCreationFailureException(USER_ID_REQUIRED, e);
}
- if (this.email == null || this.email.isBlank()) {
- throw new UserCreationFailureException(EMAIL_NOT_PROVIDED);
- }
- if (this.userPassword == null || this.userPassword.isBlank()) {
- throw new UserCreationFailureException(PASSWORD_NOT_PROVIDED);
- }
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.email, EMAIL_NOT_PROVIDED, UserCreationFailureException.class);
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.userPassword, PASSWORD_NOT_PROVIDED, UserCreationFailureException.class);
}
+
@Override
public String getId() {
return this.id;
@@ -121,17 +115,13 @@ public String getEmail() {
@Override
public void changeUserPassword(String password) throws UserCreationFailureException {
- if (password == null || password.isBlank()) {
- throw new UserCreationFailureException(PASSWORD_NOT_PROVIDED);
- }
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(password, PASSWORD_NOT_PROVIDED, UserCreationFailureException.class);
this.userPassword = password;
}
@Override
public void changeUserName(String updatedUsername) {
- if (updatedUsername == null || updatedUsername.isBlank()) {
- throw new UserCreationFailureException(String.format(USERNAME_REQUIRED, this.userProfile));
- }
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(updatedUsername, String.format(USERNAME_REQUIRED, this.userProfile), UserCreationFailureException.class);
this.userName = updatedUsername;
}
}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/UserContract.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/UserContract.java
index a22780d..5941059 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/UserContract.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/UserContract.java
@@ -14,7 +14,7 @@
* {@link UserCreationFailureException}.
*
* @author diegoneves
- * @version 1.0
+ * @since 1.0.0
* @see UserCreationFailureException
* @see RuntimeException
*/
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/value/UserProfile.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/value/UserProfile.java
index eeb0e64..1bbd7a1 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/value/UserProfile.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/entity/value/UserProfile.java
@@ -5,7 +5,7 @@
* Os perfis disponíveis são {@code 'Doador'} e {@code 'Beneficiário'}.
*
* @author diegoneves
- * @version 1.0.0
+ * @since 1.0.0
*/
public enum UserProfile {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/factory/UserFactory.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/factory/UserFactory.java
index 965dd29..cf210bc 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/factory/UserFactory.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/factory/UserFactory.java
@@ -2,14 +2,45 @@
import diegosneves.github.conectardoacoes.core.domain.user.entity.User;
import diegosneves.github.conectardoacoes.core.domain.user.entity.value.UserProfile;
+import diegosneves.github.conectardoacoes.core.exception.UserCreationFailureException;
import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+/**
+ * Classe de utilidade para a criação de usuário.
+ *
+ * Oferece um método estático para criar um usuário com todas as informações necessárias
+ * como nome de usuário, e-mail, perfil de usuário e senha.
+ * Além disso, gera um identificador UUID para o novo usuário.
+ *
+ *
+ * Esta classe foi projetada para ser usada em todo o código que precisa criar um novo usuário,
+ * permitindo uma abordagem consistente para a criação de usuário.
+ *
+ *
+ * Esta classe não pode ser instanciada.
+ *
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ * @see User
+ */
public class UserFactory {
private UserFactory() {
}
+ /**
+ * Cria um novo usuário com todas as informações necessárias e um identificador UUID gerado.
+ *
+ * Este método utiliza o método {@link UuidUtils#generateUuid} para gerar um UUID único para o novo objeto {@link User}.
+ * @param username O nome de usuário desejado para o novo usuário. Não deve ser nulo ou vazio.
+ * @param email O e-mail do novo usuário. Não deve ser nulo ou vazio.
+ * @param userProfile O perfil do usuário {@link UserProfile} para o novo usuário. Não deve ser nulo.
+ * @param password A senha para o novo usuário. Não deve ser nula ou vazia.
+ * @return O usuário criado com todas as informações fornecidas e um identificador UUID.
+ * @throws UserCreationFailureException se qualquer informação de usuário fornecida for inválida.
+ */
public static User create(String username, String email, UserProfile userProfile, String password) {
return new User(UuidUtils.generateUuid(), username, email, userProfile, password);
}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/shared/repository/UserRepository.java b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/shared/repository/UserRepository.java
new file mode 100644
index 0000000..5f12dae
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/domain/user/shared/repository/UserRepository.java
@@ -0,0 +1,31 @@
+package diegosneves.github.conectardoacoes.core.domain.user.shared.repository;
+
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.repository.RepositoryContract;
+
+/**
+ * A interface {@link UserRepository} herda de {@link RepositoryContract} que é parametrizada com {@link UserContract}.
+ * Ela fornece funcionalidades específicas ao usuário como adicionar, atualizar, deletar e procurar informações de usuários no banco de dados.
+ *
+ *
Os métodos herdados de {@link RepositoryContract} devem ser implementados em uma classe de repositório de usuário para fornecer o impacto
+ * adequado para cada ação correspondente no banco de dados.
+ *
Isso inclui encontrar usuário(s) por id, salvar usuário, deletar usuário pelo id e buscar todos os usuários.
+ *
Os detalhes de cada operação são como segue:
+ *
+ *
+ * - {@link RepositoryContract#save(Object) save(UserContract entity)} - Salva ou atualiza as informações de um usuário no banco de dados
+ *
- {@link RepositoryContract#findById(String id) findById(String id)} - Retorna um usuário procurando pelo ID
+ *
- {@link RepositoryContract#findAll() findAll()} - Retorna todos os usuários do banco de dados
+ *
- {@link RepositoryContract#deleteById(String id) deleteById(String id)} - Busca e deleta o usuário pelo ID
+ *
+ *
+ * Caso as operações de pesquisa não possam encontrar usuário(s) correspondente, eles retornarão um valor nulo ou uma lista vazia.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ * @see RepositoryContract
+ * @see UserContract
+ */
+public interface UserRepository extends RepositoryContract {
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/enums/ExceptionDetails.java b/src/main/java/diegosneves/github/conectardoacoes/core/enums/ExceptionDetails.java
index 338850a..37b5886 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/enums/ExceptionDetails.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/enums/ExceptionDetails.java
@@ -19,15 +19,18 @@
*
*
* @author diegoneves
- * @version 1.0.0
+ * @since 1.0.0
*/
public enum ExceptionDetails {
USER_CREATION_ERROR("Um erro ocorreu ao tentar criar um usuario devido ao seguinte motivo: %s"),
+ USER_MANIPULATION_ERROR("Ocorreu um erro no UserService ao tentar manipular um usuário. Motivo: %s"),
+ SHELTER_MANIPULATION_ERROR("Ocorreu um erro no ShelterService ao tentar manipular um abrigo. Motivo: %s"),
DONATION_CREATION_ERROR("Um erro ocorreu ao tentar registrar uma doação devido ao seguinte motivo: %s"),
SHELTER_CREATION_ERROR("Um erro ocorreu ao tentar criar um Abrigo devido ao seguinte motivo: %s"),
ADDRESS_CREATION_ERROR("Um erro ocorreu ao tentar criar um endereço devido ao seguinte motivo: %s"),
- INVALID_UUID_FORMAT_MESSAGE("O ID %s precisa estar no formato UUID");
+ INVALID_UUID_FORMAT_MESSAGE("O ID %s precisa estar no formato UUID"),
+ EXCEPTION_TYPE_NOT_THROWN("Não foi possível lançar a exceção do tipo %s");
private final String message;
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/AddressCreationFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/AddressCreationFailureException.java
index 7a0434e..635b159 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/exception/AddressCreationFailureException.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/AddressCreationFailureException.java
@@ -23,7 +23,7 @@
*
* @author diegosneves
* @see RuntimeException
- * @version 1.0
+ * @since 1.0.0
*/
public class AddressCreationFailureException extends RuntimeException {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/DonationRegisterFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/DonationRegisterFailureException.java
index 2724266..c975f44 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/exception/DonationRegisterFailureException.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/DonationRegisterFailureException.java
@@ -17,7 +17,7 @@
* String para o construtor ao instanciar um novo objeto {@link DonationRegisterFailureException}.
*
* @author diegoneves
- * @version 1.0
+ * @since 1.0.0
* @see RuntimeException
*/
public class DonationRegisterFailureException extends RuntimeException {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterCreationFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterCreationFailureException.java
index 2c57cee..5da63e2 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterCreationFailureException.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterCreationFailureException.java
@@ -38,7 +38,7 @@
*
* @author diegosneves
* @see RuntimeException
- * @version 1.0
+ * @since 1.0.0
*/
public class ShelterCreationFailureException extends RuntimeException {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterServiceFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterServiceFailureException.java
new file mode 100644
index 0000000..6da0365
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ShelterServiceFailureException.java
@@ -0,0 +1,68 @@
+package diegosneves.github.conectardoacoes.core.exception;
+
+import diegosneves.github.conectardoacoes.core.enums.ExceptionDetails;
+
+/**
+ * Esta é uma classe de exceção personalizada que estende a {@link RuntimeException}.
+ * É usado especialmente para lidar com erros que ocorrem durante a criação de um abrigo.
+ *
+ * A classe contém uma constante de ERROR, que define o detalhe da exceção. Esta constante é do tipo {@link ExceptionDetails} e
+ * é inicializada com o valor {@link ExceptionDetails#SHELTER_MANIPULATION_ERROR}.
+ *
+ * Possui dois construtores:
+ *
+ * 1. Que aceita apenas uma String como argumento, que serve como mensagem para a exceção.
+ *
+ * 2. Que aceita uma String e um {@link Throwable} como argumentos. A String serve como mensagem para a exceção e o {@link Throwable} é a causa que levou à exceção.
+ *
+ *
+ * Exemplo de uso:
+ *
+ *
+ * {@code
+ * if (AlgumaValidacaoFalhar) {
+ * throw new ShelterServiceFailureException("Detalhe da falha");
+ * }
+ * // código de criação de um Abrigo
+ * }
+ *
+ *
+ * {@code
+ * try {
+ * // código de criação de um Abrigo
+ * } catch (AlgumaExcecao e) {
+ * throw new ShelterServiceFailureException("Detalhe da falha", e);
+ * }
+ * }
+ *
+ *
+ * @author diegosneves
+ * @see RuntimeException
+ * @since 1.0.0
+ */
+public class ShelterServiceFailureException extends RuntimeException {
+
+ public static final ExceptionDetails ERROR = ExceptionDetails.SHELTER_MANIPULATION_ERROR;
+
+ /**
+ * Construtor que aceita uma mensagem como argumento e chama o construtor da superclasse com a
+ * mensagem de erro construída a partir de {@code ERROR} e a mensagem dada.
+ *
+ * @param message Detalhe adicional específico desta instância de exceção.
+ */
+ public ShelterServiceFailureException(String message) {
+ super(ERROR.buildMessage(message));
+ }
+
+ /**
+ * Construtor que aceita uma mensagem e uma causa como argumentos e chama o construtor da superclasse com a
+ * mensagem de erro construída a partir de ERROR, a mensagem dada e a causa da exceção.
+ *
+ * @param message Detalhe adicional específico desta instância de exceção.
+ * @param cause A causa raiz que levou a esta exceção.
+ */
+ public ShelterServiceFailureException(String message, Throwable cause) {
+ super(ERROR.buildMessage(message), cause);
+ }
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserCreationFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserCreationFailureException.java
index 68eb2e6..b0dd167 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserCreationFailureException.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserCreationFailureException.java
@@ -29,7 +29,7 @@
*
*
* @author diegosneves
- * @version 1.0
+ * @since 1.0.0
*/
public class UserCreationFailureException extends RuntimeException {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserServiceFailureException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserServiceFailureException.java
new file mode 100644
index 0000000..e03bd27
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UserServiceFailureException.java
@@ -0,0 +1,60 @@
+package diegosneves.github.conectardoacoes.core.exception;
+
+import diegosneves.github.conectardoacoes.core.enums.ExceptionDetails;
+
+/**
+ * Esta é uma classe de exceção personalizada que estende a {@link RuntimeException}.
+ * É usado especialmente para lidar com erros que ocorrem durante a criação de um usuário.
+ *
+ * A classe contém uma constante de ERROR, que define o detalhe da exceção. Esta constante é do tipo ExceptionDetails e
+ * é inicializada com o valor {@link ExceptionDetails#USER_MANIPULATION_ERROR USER_MANIPULATION_ERROR}.
+ *
+ * Possui dois construtores:
+ *
+ * 1. Que aceita apenas uma String como argumento, que serve como mensagem para a exceção.
+ *
+ * 2. Que aceita uma String e um {@link Throwable} como argumentos. A String serve como mensagem para a exceção e o {@link Throwable} é a causa que levou à exceção.
+ *
+ *
+ * Exemplo de uso:
+ *
+ *
+ * {@code
+ * try {
+ * // código de criação de usuário
+ * } catch (AlgumaExcecao e) {
+ * throw new UserServiceFailureException("Detalhe da falha", e);
+ * }
+ * }
+ *
+ *
+ * @author diegosneves
+ * @since 1.0.0
+ * @see RuntimeException
+ */
+public class UserServiceFailureException extends RuntimeException {
+
+ public static final ExceptionDetails ERROR = ExceptionDetails.USER_MANIPULATION_ERROR;
+
+ /**
+ * Construtor que aceita uma mensagem como argumento e chama o construtor da superclasse com a
+ * mensagem de erro construída a partir de ERROR e a mensagem dada.
+ *
+ * @param message Detalhe adicional específico desta instância de exceção.
+ */
+ public UserServiceFailureException(String message) {
+ super(ERROR.buildMessage(message));
+ }
+
+ /**
+ * Construtor que aceita uma mensagem e uma causa como argumentos e chama o construtor da superclasse com a
+ * mensagem de erro construída a partir de ERROR, a mensagem dada e a causa da exceção.
+ *
+ * @param message Detalhe adicional específico desta instância de exceção.
+ * @param cause A causa raiz que levou a esta exceção.
+ */
+ public UserServiceFailureException(String message, Throwable cause) {
+ super(ERROR.buildMessage(message), cause);
+ }
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/UuidUtilsException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UuidUtilsException.java
index 4fb1a99..0fb6246 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/exception/UuidUtilsException.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/UuidUtilsException.java
@@ -15,7 +15,7 @@
*
* @author diegoneves
* @see RuntimeException
- * @version 1.0.0
+ * @since 1.0.0
*/
public class UuidUtilsException extends RuntimeException {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/exception/ValidationUtilsException.java b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ValidationUtilsException.java
new file mode 100644
index 0000000..7e56048
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/exception/ValidationUtilsException.java
@@ -0,0 +1,36 @@
+package diegosneves.github.conectardoacoes.core.exception;
+
+import diegosneves.github.conectardoacoes.core.enums.ExceptionDetails;
+
+/**
+ * Esta é uma classe de exceção personalizada que estende a classe {@link RuntimeException}.
+ * É lançado quando um erro relacionado a uma exceção personalizada não pode ser lançada.
+ *
+ * A classe inclui um único campo estático, {@code ERROR}, que especifica o tipo de erro.
+ *
+ *
+ * Note: O construtor desta classe constrói a mensagem de exceção através do método {@code buildMessage}
+ * disponível no objeto ERROR de tipo {@link ExceptionDetails}.
+ *
+ *
+ * @author diegoneves
+ * @see RuntimeException
+ * @since 1.0.0
+ */
+public class ValidationUtilsException extends RuntimeException {
+
+ public static final ExceptionDetails ERROR = ExceptionDetails.EXCEPTION_TYPE_NOT_THROWN;
+
+ /**
+ * Construtor que cria uma instância da exceção {@link ValidationUtilsException} com a mensagem e causa fornecidas.
+ * A mensagem é usada para criar uma mensagem de erro mais detalhada, passada para a superclasse, {@link RuntimeException}.
+ *
+ * @param message A string que representa a mensagem detalhada da exceção, usada para criar uma mensagem de erro mais detalhada.
+ * @param cause A causa raiz da exceção, tipicamente uma instância de {@link Throwable} que levou à ocorrência desta exceção.
+ * Esta informação é usada para depuração e rastreamento do erro.
+ */
+ public ValidationUtilsException(String message, Throwable cause) {
+ super(ERROR.buildMessage(message), cause);
+ }
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/repository/RepositoryContract.java b/src/main/java/diegosneves/github/conectardoacoes/core/repository/RepositoryContract.java
new file mode 100644
index 0000000..25b1cc9
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/repository/RepositoryContract.java
@@ -0,0 +1,55 @@
+package diegosneves.github.conectardoacoes.core.repository;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Esta é uma interface de contrato de repositório genérica que define operações CRUD básicas.
+ * A interface do repositório é genérica e pode ser usada com qualquer tipo de entidade.
+ *
+ *
+ * Esta interface define as seguintes operações:
+ * - Encontrar uma entidade pelo seu identificador único ({@code String})
+ * - Encontrar todas as instâncias de uma determinada entidade
+ * - Salvar uma instância de uma entidade
+ * - Deletar uma entidade pelo seu identificador único ({@code String})
+ *
+ * @param o tipo de entidade com a qual essa interface de repositório trabalha.
+ * @author diegoneves
+ * @since 1.0.0
+ */
+public interface RepositoryContract {
+
+ /**
+ * Encontra uma entidade pelo seu identificador.
+ *
+ * @param id o identificador único da entidade que deve ser procurada.
+ * @return a entidade encontrada ou {@code null} se nenhuma entidade com o identificador especificado pôde ser encontrada.
+ */
+ T findById(String id);
+
+ /**
+ * Encontra todas as entidades de um determinado tipo.
+ *
+ * @return uma lista contendo todas as entidades ou uma lista vazia se não houver entidades.
+ */
+ List findAll();
+
+ /**
+ * Salva uma entidade.
+ *
+ * @param entity a entidade que deve ser salva.
+ * @return a entidade salva.
+ * @throws IllegalArgumentException se a entidade passada como parâmetro for {@code null}.
+ */
+ T save(T entity);
+
+ /**
+ * Deleta uma entidade pelo seu identificador.
+ *
+ * @param id o identificador único da entidade que deve ser deletada.
+ * @throws NoSuchElementException se nenhuma entidade com o identificador especificado pôde ser encontrada.
+ */
+ void deleteById(String id);
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterService.java b/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterService.java
new file mode 100644
index 0000000..4a48ade
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterService.java
@@ -0,0 +1,183 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.Shelter;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.ShelterContract;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Address;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Donation;
+import diegosneves.github.conectardoacoes.core.domain.shelter.factory.ShelterFactory;
+import diegosneves.github.conectardoacoes.core.domain.shelter.shared.repository.ShelterRepository;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.exception.ShelterCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.ShelterServiceFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UuidUtilsException;
+import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+import diegosneves.github.conectardoacoes.core.utils.ValidationUtils;
+
+import java.util.List;
+
+/**
+ * A classe de serviço {@link ShelterService} é responsável pelas operações de negócios relacionadas a abrigos.
+ * Essas operações incluem criação de abrigos, busca por abrigos e alterações nos atributos dos abrigos.
+ * Esta classe implementa a interface {@link ShelterServiceContract}.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ * @see ShelterServiceContract
+ * @see ShelterRepository
+ */
+public class ShelterService implements ShelterServiceContract {
+
+ public static final String INVALID_SHELTER_ID_MESSAGE = "A ID especificada para o abrigo é inválida.";
+ public static final String INVALID_SHELTER_NAME_ERROR_MESSAGE = "O nome do Abrigo fornecido é inválido.";
+ public static final String ERROR_MESSAGE_ADDRESS_NULL = "O Endereço fornecido não deve ser nulo";
+ public static final String DONATION_REQUIRED_ERROR_MESSAGE = "A Doação fornecida deve ser válida.";
+
+ private final ShelterRepository shelterRepository;
+
+ public ShelterService(ShelterRepository shelterRepository) {
+ this.shelterRepository = shelterRepository;
+ }
+
+ /**
+ * Este método cria um novo {@link ShelterContract} utilizando {@link ShelterFactory#create}.
+ * O novo objeto {@link Shelter} é salvo usando o método {@link ShelterRepository#save}.
+ *
+ * @param shelterName O nome do abrigo como uma string.
+ * @param address uma instancia do objeto {@link Address} representando o endereço do abrigo
+ * @param responsibleUser um objeto {@link UserContract} representando o usuário responsável pelo abrigo
+ * @return um novo objeto {@link ShelterContract}
+ * @throws ShelterCreationFailureException quando uma falha ocorre durante a criação do {@link ShelterContract}
+ * @see ShelterFactory
+ * @see ShelterRepository
+ */
+ @Override
+ public ShelterContract createShelter(String shelterName, Address address, UserContract responsibleUser) throws ShelterCreationFailureException {
+ Shelter newShelter = ShelterFactory.create(shelterName, address, responsibleUser);
+ return this.shelterRepository.save(newShelter);
+ }
+
+ /**
+ * Retorna um objeto {@link ShelterContract} baseado no ID do abrigo fornecido.
+ *
+ * @param shelterId O ID do abrigo como uma string.
+ * @return um objeto {@link ShelterContract} que corresponde ao ID do abrigo fornecido
+ * @throws ShelterServiceFailureException quando uma falha ocorre durante a busca pelo abrigo
+ */
+ @Override
+ public ShelterContract getShelter(String shelterId) throws ShelterServiceFailureException {
+ validateShelterId(shelterId);
+ return this.shelterRepository.findById(shelterId);
+ }
+
+ /**
+ * Valida o ID do abrigo fornecido. Primeiro, verifica se o ID do abrigo é nulo ou vazio usando
+ * {@link ValidationUtils#checkNotNullAndNotEmptyOrThrowException}. Em seguida, tenta verificar se o ID do abrigo é um UUID válido
+ * usando {@link UuidUtils#isValidUUID}.
+ * Se qualquer uma dessas verificações falhar, ele lançará uma {@link ShelterServiceFailureException} com uma mensagem que indica
+ * que o ID do abrigo fornecido é inválido.
+ *
+ * @param shelterId O ID do abrigo a ser validado.
+ * @throws ShelterServiceFailureException Se o ID do abrigo fornecido for nulo, vazio ou não for um UUID válido.
+ */
+ private static void validateShelterId(String shelterId) throws ShelterServiceFailureException {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(shelterId, INVALID_SHELTER_ID_MESSAGE, ShelterServiceFailureException.class);
+ try {
+ UuidUtils.isValidUUID(shelterId);
+ } catch (UuidUtilsException e) {
+ throw new ShelterServiceFailureException(INVALID_SHELTER_ID_MESSAGE, e);
+ }
+ }
+
+ /**
+ * Este método é usado para alterar o nome do abrigo identificado pelo ID fornecido.
+ *
+ * Primeiro, o método valida se o novo nome não é nulo nem vazio usando
+ * {@link ValidationUtils#checkNotNullAndNotEmptyOrThrowException}. Se a validação falhar,
+ * uma {@link ShelterServiceFailureException} é lançada com uma mensagem indicando que o novo nome do abrigo é inválido.
+ *
+ * O nome do abrigo recuperado é então alterado para o novo nome fornecido usando o método
+ * {@link ShelterContract#changeShelterName}.
+ *
+ * Finalmente, o abrigo com o nome atualizado é salvo no repositório usando {@link ShelterRepository#save}.
+ *
+ * @param shelterId O ID do abrigo cujo nome será alterado. Deve ser uma identificação válida de um abrigo existente.
+ * @param newName O novo nome para o abrigo. Ele não pode ser {@code null} ou uma String vazia.
+ * @throws ShelterServiceFailureException Se o novo nome do abrigo fornecido for inválido (ou seja, nulo ou vazio),
+ * ou se ocorrer um problema ao recuperar o abrigo com o ID fornecido ou ao salvar o abrigo com o nome alterado.
+ */
+ @Override
+ public void changeShelterName(String shelterId, String newName) throws ShelterServiceFailureException {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(newName, INVALID_SHELTER_NAME_ERROR_MESSAGE, ShelterServiceFailureException.class);
+ ShelterContract updatedShelter = this.getShelter(shelterId);
+ updatedShelter.changeShelterName(newName);
+ this.shelterRepository.save(updatedShelter);
+ }
+
+ /**
+ * Este método é usado para alterar o endereço do abrigo identificado pelo ID fornecido.
+ *
+ * Primeiro, o método valida se o novo endereço não é nulo usando
+ * {@link ValidationUtils#checkNotNullAndNotEmptyOrThrowException}. Se a validação falhar,
+ * uma {@link ShelterServiceFailureException} é lançada com uma mensagem indicando que o novo endereço do abrigo é inválido.
+ *
+ * O endereço do abrigo recuperado é então alterado para o novo endereço fornecido usando o método
+ * {@link ShelterContract#changeAddress}.
+ *
+ * Finalmente, o abrigo com o endereço atualizado é salvo no repositório usando {@link ShelterRepository#save}.
+ *
+ * @param shelterId O ID do abrigo cujo endereço será alterado. Deve ser uma identificação válida de um abrigo existente.
+ * @param address O novo endereço para o abrigo. Ele não pode ser {@code null} ou uma instância inválida de {@link Address}.
+ * @throws ShelterServiceFailureException Se o novo endereço do abrigo fornecido for inválido (ou seja, null ou instância inválida),
+ * ou se ocorrer um problema ao recuperar o abrigo com o ID fornecido ou ao salvar o abrigo com o endereço alterado.
+ */
+ @Override
+ public void changeAddress(String shelterId, Address address) throws ShelterServiceFailureException {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(address, ERROR_MESSAGE_ADDRESS_NULL, ShelterServiceFailureException.class);
+ ShelterContract updatedShelter = this.getShelter(shelterId);
+ updatedShelter.changeAddress(address);
+ this.shelterRepository.save(updatedShelter);
+ }
+
+ /**
+ * Este método é responsável por adicionar uma {@link Donation} a um {@link ShelterContract} específico, identificado por seu id.
+ *
+ * Primeiro, ele confirma que o objeto {@link Donation} não é nulo usando
+ * {@link ValidationUtils#checkNotNullAndNotEmptyOrThrowException}. Se este objeto {@link Donation} for nulo,
+ * ele lança uma {@link ShelterServiceFailureException}.
+ *
+ * Em seguida, ele usa o id do abrigo fornecido para obter o {@link ShelterContract} correspondente.
+ * Este {@link ShelterContract} é então atualizado adicionando a {@link Donation} fornecida.
+ *
+ * Finalmente, o {@link ShelterContract} atualizado é salvo no repositorio usando {@link ShelterRepository#save}.
+ *
+ * @param shelterId O ID do abrigo ao qual a doação será adicionada. Deve ser uma identificação válida de um abrigo existente.
+ * @param donation Uma instancia do objeto {@link Donation} representando a doação a ser adicionada.
+ * @throws ShelterServiceFailureException Se a doação fornecida for inválida (ou seja, nula ou vazia),
+ * ou se ocorrer um problema ao recuperar o abrigo com o ID fornecido ou ao salvar o abrigo com a doação adicionada.
+ */
+ @Override
+ public void addDonation(String shelterId, Donation donation) throws ShelterServiceFailureException {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(donation, DONATION_REQUIRED_ERROR_MESSAGE, ShelterServiceFailureException.class);
+ ShelterContract updatedShelter = this.getShelter(shelterId);
+ updatedShelter.addDonation(donation);
+ this.shelterRepository.save(updatedShelter);
+ }
+
+ /**
+ * Este método é responsável por recuperar a lista de {@link Donation} de um {@link ShelterContract} específico, identificado por seu id.
+ *
+ * Primeiro, ele usa o id do abrigo fornecido para obter o {@link ShelterContract} correspondente.
+ * A lista de {@link Donation} deste {@link ShelterContract} específico é então retornada.
+ *
+ * Note que este método pode lançar uma {@link ShelterServiceFailureException}. Isto ocorrerá se houver um problema ao tentar recuperar o {@link ShelterContract} com o id fornecido.
+ *
+ * @param shelterId O ID do abrigo do qual as doações serão recuperadas. Deve ser uma identificação válida de um abrigo existente.
+ * @return Uma lista de {@link Donation} que foram feitas para o abrigo identificado pelo id fornecido.
+ * @throws ShelterServiceFailureException Se ocorrer um problema ao tentar recuperar o {@link ShelterContract} com o id fornecido.
+ */
+ @Override
+ public List getDonations(String shelterId) throws ShelterServiceFailureException {
+ ShelterContract shelter = this.getShelter(shelterId);
+ return shelter.getDonations();
+ }
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceContract.java b/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceContract.java
new file mode 100644
index 0000000..78e9db7
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceContract.java
@@ -0,0 +1,78 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.Shelter;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.ShelterContract;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Address;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Donation;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.exception.ShelterCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.ShelterServiceFailureException;
+
+import java.util.List;
+
+/**
+ * Interface {@link ShelterServiceContract} define vários métodos que manipulam um objeto {@link Shelter}.
+ * Isso inclui criar um abrigo, alterar o nome e o endereço de um abrigo, adicionar uma doação e obter detalhes de um abrigo.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ */
+public interface ShelterServiceContract {
+
+ /**
+ * Cria um novo {@link Shelter} usando o nome do abrigo, endereço e o objeto do usuário responsável fornecidos.
+ *
+ * @param shelterName nome do abrigo como uma String
+ * @param address uma instância do objeto {@link Address} representando o endereço do abrigo
+ * @param responsibleUser um objeto {@link UserContract} representando o usuário responsável pelo abrigo
+ * @return um objeto {@link ShelterContract} do novo abrigo criado
+ * @throws ShelterCreationFailureException se um erro ocorrer durante a criação do abrigo
+ */
+ ShelterContract createShelter(String shelterName, Address address, UserContract responsibleUser) throws ShelterCreationFailureException;
+
+ /**
+ * Obtém os detalhes de um abrigo existente.
+ *
+ * @param shelterId ID do abrigo como uma String
+ * @return um objeto {@link ShelterContract} com detalhes do abrigo
+ * @throws ShelterServiceFailureException se um erro ocorrer durante a obtenção dos detalhes do abrigo
+ */
+ ShelterContract getShelter(String shelterId) throws ShelterServiceFailureException;
+
+ /**
+ * Muda o nome de um abrigo existente.
+ *
+ * @param shelterId ID do abrigo como uma String
+ * @param newName o novo nome do abrigo como uma String
+ * @throws ShelterServiceFailureException se um erro ocorrer durante a alteração do nome do abrigo
+ */
+ void changeShelterName(String shelterId, String newName) throws ShelterServiceFailureException;
+
+ /**
+ * Muda o endereço de um abrigo existente.
+ *
+ * @param shelterId ID do abrigo como uma String
+ * @param address uma instância do objeto Address representando o novo endereço do abrigo
+ * @throws ShelterServiceFailureException se um erro ocorrer durante a alteração do endereço do abrigo
+ */
+ void changeAddress(String shelterId, Address address) throws ShelterServiceFailureException;
+
+ /**
+ * Adiciona uma nova doação ao abrigo.
+ *
+ * @param shelterId ID do abrigo como uma String
+ * @param donation uma instância do objeto {@link Donation} representando a doação a ser adicionada
+ * @throws ShelterServiceFailureException se um erro ocorrer durante a adição da doação ao abrigo
+ */
+ void addDonation(String shelterId, Donation donation) throws ShelterServiceFailureException;
+
+ /**
+ * Busca a lista de todas as {@link Donation} de um determinado abrigo.
+ *
+ * @param shelterId ID do abrigo como uma String
+ * @return Uma lista de objetos {@link Donation}, que representa todas as doações recebidas pelo abrigo.
+ * @throws ShelterServiceFailureException se um erro ocorrer durante a recuperação das doações.
+ */
+ List getDonations(String shelterId) throws ShelterServiceFailureException;
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/service/UserService.java b/src/main/java/diegosneves/github/conectardoacoes/core/service/UserService.java
new file mode 100644
index 0000000..161df95
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/service/UserService.java
@@ -0,0 +1,132 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.user.entity.User;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.value.UserProfile;
+import diegosneves.github.conectardoacoes.core.domain.user.factory.UserFactory;
+import diegosneves.github.conectardoacoes.core.domain.user.shared.repository.UserRepository;
+import diegosneves.github.conectardoacoes.core.exception.UserCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UserServiceFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UuidUtilsException;
+import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+import diegosneves.github.conectardoacoes.core.utils.ValidationUtils;
+
+/**
+ * A classe {@link UserService} implementa um contratato do serviço do usuário {@link UserServiceContract}.
+ * Ela fornece os métodos para gerenciar usuários, incluindo criação de um novo usuário, recuperação de um usuário pelo seu ID,
+ * alteração da senha do usuário e alteração do nome de usuário.
+ * Isso é feito por meio da interação com o repositório de usuários {@link UserRepository}, onde os dados do usuário são armazenados.
+ *
Os métodos implementados nesta classe realizam checagens de validação para garantir que os dados do usuário sejam válidos.
+ * Se quaisquer dados inválidos forem fornecidos, como um ID de usuário, senha ou nome de usuário nulo ou em branco,
+ * eles lançarão uma exceção {@link UserServiceFailureException}.
+ *
+ * @author diegoneves
+ * @see UserServiceContract
+ * @see UserRepository
+ * @see UserServiceFailureException
+ * @since 1.0.0
+ */
+public class UserService implements UserServiceContract {
+
+ public static final String INVALID_IDENTIFIER_ERROR_MESSAGE = "Falha ao recuperar o usuário. Identificador fornecido possui valor inválido";
+ public static final String INVALID_NEW_PASSWORD_MESSAGE = "A nova senha informada é invalida";
+ public static final String USER_NOT_FOUND_MESSAGE = "Usuário não encontrado";
+ public static final String USERNAME_INVALID_ERROR_MESSAGE = "O novo nome de usuário informado é inválido.";
+
+ private final UserRepository userRepository;
+
+ public UserService(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ /**
+ * Cria um novo usuário com os detalhes fornecidos e armazena no repositório de usuários.
+ *
+ * @param username O nome de usuário para o novo usuário.
+ * @param email O email para o novo usuário.
+ * @param userProfile O perfil do novo usuário.
+ * @param password A senha para o novo usuário.
+ * @return A instância de {@link UserContract} que representa o usuário criado.
+ * @throws UserCreationFailureException se alguma informação fornecida for inválida.
+ */
+ @Override
+ public UserContract createUser(String username, String email, UserProfile userProfile, String password) throws UserCreationFailureException {
+ User newUser = UserFactory.create(username, email, userProfile, password);
+ return this.userRepository.save(newUser);
+ }
+
+ /**
+ * Recupera um usuário pelo seu ID do repositório de usuários.
+ *
+ * @param userId O ID do usuário a ser recuperado.
+ * @return A instância de {@link UserContract} que representa o usuário recuperado.
+ * @throws UserServiceFailureException se o ID do usuário for nulo ou em branco.
+ */
+ @Override
+ public UserContract getUser(String userId) {
+ validateUserId(userId);
+ return this.userRepository.findById(userId);
+ }
+
+ /**
+ * Valida o identificador do usuário fornecido.
+ *
+ *
Este método utiliza os utilitários fornecidos pelas classes {@link ValidationUtils} e
+ * {@link UuidUtils} para validar o identificador do usuário. A validação ocorre em dois passos:
+ *
+ *
+ * - Primeiro, este método verifica se o identificador do usuário fornecido não é nulo ou
+ * vazio utilizando o método {@code checkNotNullAndNotEmptyOrThrowException} da classe {@link ValidationUtils}.
+ * - Na sequência, valida se o identificador do usuário é um {@link java.util.UUID UUID} válido através do método
+ * {@code isValidUUID} da classe {@link UuidUtils}.
+ *
+ *
+ * Se qualquer uma das validações falhar, este método lança uma exceção {@link UserServiceFailureException},
+ * que é uma exceção personalizada que estende a {@link RuntimeException}.
+ *
+ * @param userId O identificador do usuário a ser validado.
+ * @throws UserServiceFailureException Se o identificador do usuário for nulo, vazio ou não for um UUID válido.
+ * Aqui, {@link UserServiceFailureException} encapsula a exceção original ({@link UuidUtilsException}) dentro dela para fornecer
+ * informação contextual adicional quando o UUID não é válido.
+ */
+ private static void validateUserId(String userId) throws UserServiceFailureException {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(userId, INVALID_IDENTIFIER_ERROR_MESSAGE, UserServiceFailureException.class);
+ try {
+ UuidUtils.isValidUUID(userId);
+ } catch (UuidUtilsException e) {
+ throw new UserServiceFailureException(INVALID_IDENTIFIER_ERROR_MESSAGE, e);
+ }
+ }
+
+ /**
+ * Altera a senha do usuário especificado.
+ *
+ * @param userId O ID do usuário cuja senha será alterada.
+ * @param newPassword A nova senha para o usuário.
+ * @throws UserServiceFailureException se o ID do usuário ou a nova senha forem nulos ou em branco, ou se o usuário não for encontrado.
+ */
+ @Override
+ public void changePassword(String userId, String newPassword) {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(newPassword, INVALID_NEW_PASSWORD_MESSAGE, UserServiceFailureException.class);
+ UserContract retrievedUser = this.getUser(userId);
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(retrievedUser, USER_NOT_FOUND_MESSAGE, UserServiceFailureException.class);
+ retrievedUser.changeUserPassword(newPassword);
+ this.userRepository.save(retrievedUser);
+ }
+
+ /**
+ * Altera o nome do usuário especificado.
+ *
+ * @param userId O ID do usuário cujo nome será alterado.
+ * @param newUsername O novo nome de usuário para o usuário.
+ * @throws UserServiceFailureException se o ID do usuário ou o novo nome de usuário forem nulos ou em branco, ou se o usuário não for encontrado.
+ */
+ @Override
+ public void changeUserName(String userId, String newUsername) {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(newUsername, USERNAME_INVALID_ERROR_MESSAGE, UserServiceFailureException.class);
+ UserContract retrievedUser = this.getUser(userId);
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(retrievedUser, USER_NOT_FOUND_MESSAGE, UserServiceFailureException.class);
+ retrievedUser.changeUserName(newUsername);
+ this.userRepository.save(retrievedUser);
+ }
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/service/UserServiceContract.java b/src/main/java/diegosneves/github/conectardoacoes/core/service/UserServiceContract.java
new file mode 100644
index 0000000..53f0ad8
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/service/UserServiceContract.java
@@ -0,0 +1,55 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.value.UserProfile;
+import diegosneves.github.conectardoacoes.core.exception.UserCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UserServiceFailureException;
+
+/**
+ * Interface para o contrato de serviço do usuário. Define os métodos funcionais para todos os serviços de usuário.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ */
+public interface UserServiceContract {
+
+ /**
+ * Método para criar usuário.
+ *
+ * @param username nome de usuário exclusivo.
+ * @param email e-mail do usuário.
+ * @param userProfile perfil do usuário.
+ * @param password senha da conta do usuário.
+ * @return Um {@link UserContract} instância contendo detalhes do usuário.
+ * @throws UserCreationFailureException se ocorrer um erro ao criar o usuário.
+ */
+ UserContract createUser(String username, String email, UserProfile userProfile, String password) throws UserCreationFailureException;
+
+ /**
+ * Método para obter detalhes do usuário.
+ *
+ * @param userId ID único do usuário.
+ * @return A {@link UserContract} instância contendo detalhes do usuário.
+ * @throws UserServiceFailureException se ocorrer um erro ao buscar detalhes do usuário.
+ */
+ UserContract getUser(String userId);
+
+ /**
+ * Método para alterar a senha do usuário.
+ *
+ * @param userId ID único do usuário.
+ * @param newPassword Nova senha do usuário.
+ * @throws UserServiceFailureException se ocorrer um erro ao alterar a senha do usuário.
+ */
+ void changePassword(String userId, String newPassword);
+
+ /**
+ * Método para alterar o nome de usuário.
+ *
+ * @param userId ID único do usuário.
+ * @param newUsername Novo nome de usuário.
+ * @throws UserServiceFailureException se ocorrer um erro ao alterar o nome de usuário.
+ */
+ void changeUserName(String userId, String newUsername);
+
+}
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/utils/UuidUtils.java b/src/main/java/diegosneves/github/conectardoacoes/core/utils/UuidUtils.java
index 9ccceb4..4bf2884 100644
--- a/src/main/java/diegosneves/github/conectardoacoes/core/utils/UuidUtils.java
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/utils/UuidUtils.java
@@ -10,6 +10,7 @@
* Esta classe fornece métodos estáticos para gerar um novo {@link UUID} e para validar um {@link UUID} existente.
*
* @author diegoneves
+ * @since 1.0.0
*/
@Slf4j
public class UuidUtils {
diff --git a/src/main/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtils.java b/src/main/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtils.java
new file mode 100644
index 0000000..ae90b3d
--- /dev/null
+++ b/src/main/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtils.java
@@ -0,0 +1,55 @@
+package diegosneves.github.conectardoacoes.core.utils;
+
+import diegosneves.github.conectardoacoes.core.exception.ValidationUtilsException;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * A classe {@link ValidationUtils} é um utilitário que fornece métodos para validar dados de entrada.
+ * Contém todos os métodos estáticos e não pode ser instanciada.
+ *
+ * @author diegoneves
+ * @since 1.0.0
+ */
+public class ValidationUtils {
+
+ private ValidationUtils() {
+ }
+
+ /**
+ * Valida se o objeto especificado é nulo ou vazio, caso seja uma instância de String.
+ * Lança uma exceção com a mensagem de erro fornecida, se uma destas condições for verdadeira.
+ * Este método pode ser utilizado para a validação de entradas onde dados são obrigatórios.
+ *
+ * @param o tipo de objeto a ser verificado
+ * @param object o objeto a ser validado
+ * @param errorMessage a mensagem de erro a ser anexada à exceção em caso de falhas na validação
+ * @param customException a classe da exceção RuntimeException a ser lançada
+ * @throws RuntimeException se o objeto fornecido for nulo ou se fora uma instância de String e estiver vazia
+ */
+ public static void checkNotNullAndNotEmptyOrThrowException(T object, String errorMessage, Class extends RuntimeException> customException) throws RuntimeException {
+ if (object == null) {
+ throwException(errorMessage, customException);
+ }
+ if (object instanceof String && ((String) object).trim().isEmpty()) {
+ throwException(errorMessage, customException);
+ }
+ }
+
+ /**
+ * Lança uma exceção customizada com a mensagem de erro fornecida.
+ *
+ * @param message a mensagem de erro a ser anexada à exceção
+ * @param runtimeExceptionClass a classe da exceção RuntimeException a ser lançada
+ * @throws ValidationUtilsException se houve um erro ao tentar lançar a exceção
+ */
+ private static void throwException(String message, Class extends RuntimeException> runtimeExceptionClass) {
+ try {
+ Constructor extends RuntimeException> exceptionConstructor = runtimeExceptionClass.getConstructor(String.class);
+ throw exceptionConstructor.newInstance(message);
+ } catch (ReflectiveOperationException e) {
+ throw new ValidationUtilsException(runtimeExceptionClass.getSimpleName(), e);
+ }
+ }
+
+}
diff --git a/src/test/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/ShelterTest.java b/src/test/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/ShelterTest.java
index 0f3fc2d..53ce521 100644
--- a/src/test/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/ShelterTest.java
+++ b/src/test/java/diegosneves/github/conectardoacoes/core/domain/shelter/entity/ShelterTest.java
@@ -186,12 +186,10 @@ void shouldThrowExceptionWhenChangeAddressWithNullAddress() {
@SneakyThrows
void shouldAddDonation() {
Donation newDonation = new Donation("Doação", 1);
- Field field = Shelter.class.getDeclaredField("donations");
- field.setAccessible(true);
this.shelter.addDonation(newDonation);
- List actualDonations = (List) field.get(this.shelter);
+ List actualDonations = this.shelter.getDonations();
assertNotNull(actualDonations);
assertFalse(actualDonations.isEmpty());
diff --git a/src/test/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceTest.java b/src/test/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceTest.java
new file mode 100644
index 0000000..4e2da2e
--- /dev/null
+++ b/src/test/java/diegosneves/github/conectardoacoes/core/service/ShelterServiceTest.java
@@ -0,0 +1,462 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.Shelter;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.ShelterContract;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Address;
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.value.Donation;
+import diegosneves.github.conectardoacoes.core.domain.shelter.shared.repository.ShelterRepository;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.User;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.value.UserProfile;
+import diegosneves.github.conectardoacoes.core.exception.ShelterCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.ShelterServiceFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UuidUtilsException;
+import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+import org.junit.jupiter.api.BeforeEach;
+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.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(SpringExtension.class)
+class ShelterServiceTest {
+
+ public static final String SHELTER_IDENTIFIER = "89142bda-7b0c-4421-af28-f9cadb316024";
+ public static final String USER_UUID = "0ed6e6a1-882c-4d2d-83ee-67034ee1ab9f";
+ public static final String USERNAME = "Fulano";
+ public static final String USER_EMAIL = "teste@email.com";
+ public static final String USER_PASSWORD = "senha";
+ public static final String SHELTER_NAME = "Abrigo";
+ public static final String ADDRESS_STREET = "Rua";
+ public static final String BUILDING_NUMBER = "54";
+ public static final String NEIGHBORHOOD = "Bairro";
+ public static final String SHELTER_CITY = "Canoas";
+ public static final String STATE_ABBREVIATION = "RS";
+ public static final String SHELTER_ZIPCODE = "95000000";
+
+ @InjectMocks
+ private ShelterService service;
+
+ @Mock
+ private ShelterRepository repository;
+
+ @Captor
+ private ArgumentCaptor shelterCaptor;
+
+ private Shelter shelter;
+ private User user;
+ private Address address;
+
+ @BeforeEach
+ void setUp() {
+ this.user = new User(USER_UUID, USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD);
+ this.address = new Address(ADDRESS_STREET, BUILDING_NUMBER, NEIGHBORHOOD, SHELTER_CITY, STATE_ABBREVIATION, SHELTER_ZIPCODE);
+ this.shelter = new Shelter(SHELTER_IDENTIFIER, SHELTER_NAME, this.address, this.user);
+ }
+
+ @Test
+ void shouldReturnShelterContract() {
+ when(this.repository.save(any(ShelterContract.class))).thenReturn(this.shelter);
+
+ ShelterContract actual = this.service.createShelter(SHELTER_NAME, this.address, this.user);
+
+ verify(this.repository, times(1)).save(this.shelterCaptor.capture());
+
+ assertNotNull(actual);
+ assertNotNull(this.shelterCaptor.getValue());
+ assertEquals(this.shelter, actual);
+ ShelterContract expected = this.shelterCaptor.getValue();
+ assertTrue(UuidUtils.isValidUUID(expected.getId()));
+ assertEquals(SHELTER_NAME, expected.getShelterName());
+ assertEquals(this.user, expected.getUser());
+ assertEquals(this.address, expected.getAddress());
+ }
+
+ @Test
+ void shouldThrowShelterCreationFailureExceptionWhenShelterNameIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.service.createShelter(null, this.address, this.user));
+
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(actual);
+ assertEquals(ShelterCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowShelterCreationFailureExceptionWhenShelterNameIsEmpty() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.service.createShelter("", this.address, this.user));
+
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(actual);
+ assertEquals(ShelterCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowShelterCreationFailureExceptionWhenShelterAddressIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.service.createShelter(SHELTER_NAME, null, this.user));
+
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(actual);
+ assertEquals(ShelterCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowShelterCreationFailureExceptionWhenShelterUserIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.service.createShelter(SHELTER_NAME, this.address, null));
+
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(actual);
+ assertEquals(ShelterCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldRetrieveShelterContractUsingGivenShelterIdentifier() {
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ ShelterContract actual = this.service.getShelter(SHELTER_IDENTIFIER);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+
+ assertNotNull(actual);
+ assertEquals(this.shelter, actual);
+ }
+
+ @Test
+ void shouldRetrieveNullShelterContractUsingGivenShelterIdentifier() {
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(null);
+
+ ShelterContract actual = this.service.getShelter(SHELTER_IDENTIFIER);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+
+ assertNull(actual);
+ }
+
+ @Test
+ void shouldThrowExceptionWhenGivenNullShelterId() {
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.getShelter(null));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenGivenEmptyShelterId() {
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.getShelter(""));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenGivenInvalidShelterId() {
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.getShelter("idInvalid"));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ assertEquals(UuidUtilsException.class, exception.getCause().getClass());
+ }
+
+ @Test
+ void shouldChangeShelterNameWhenGivenValidShelterIdentifier() {
+ String newShelterName = "newShelterName";
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ this.service.changeShelterName(SHELTER_IDENTIFIER, newShelterName);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+ verify(this.repository, times(1)).save(this.shelterCaptor.capture());
+
+ assertNotNull(shelterCaptor.getValue());
+ Shelter updatedShelter = this.shelterCaptor.getValue();
+ assertEquals(newShelterName, updatedShelter.getShelterName());
+ assertEquals(SHELTER_IDENTIFIER, updatedShelter.getId());
+ assertEquals(this.user, updatedShelter.getUser());
+ assertEquals(this.address, updatedShelter.getAddress());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterNameIsEmpty() {
+ String newShelterName = "";
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeShelterName(SHELTER_IDENTIFIER, newShelterName));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_NAME_ERROR_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterNameIsNull() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeShelterName(SHELTER_IDENTIFIER, null));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_NAME_ERROR_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsInvalidOnChangeShelterName() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeShelterName("SHELTER_IDENTIFIER", SHELTER_NAME));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ assertEquals(UuidUtilsException.class, exception.getCause().getClass());
+ }
+
+ @Test
+ void shouldUpdateAndSaveShelterAddressGivenValidShelterId() {
+ Address addressUpdate = new Address(ADDRESS_STREET, "377", NEIGHBORHOOD, "Esteio", STATE_ABBREVIATION, SHELTER_ZIPCODE);
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ this.service.changeAddress(SHELTER_IDENTIFIER, addressUpdate);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+ verify(this.repository, times(1)).save(this.shelterCaptor.capture());
+
+ assertNotNull(shelterCaptor.getValue());
+ Shelter updatedShelter = this.shelterCaptor.getValue();
+ assertEquals(addressUpdate, updatedShelter.getAddress());
+ assertEquals(SHELTER_IDENTIFIER, updatedShelter.getId());
+ assertEquals(this.user, updatedShelter.getUser());
+ assertNotEquals(this.address, updatedShelter.getAddress());
+ assertEquals(SHELTER_NAME, updatedShelter.getShelterName());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsEmptyOnChangeAddress() {
+ Address addressUpdate = new Address(ADDRESS_STREET, "377", NEIGHBORHOOD, "Esteio", STATE_ABBREVIATION, SHELTER_ZIPCODE);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeAddress("", addressUpdate));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsNullOnChangeAddress() {
+ Address addressUpdate = new Address(ADDRESS_STREET, "377", NEIGHBORHOOD, "Esteio", STATE_ABBREVIATION, SHELTER_ZIPCODE);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeAddress(null, addressUpdate));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsInvalidOnChangeAddress() {
+ Address addressUpdate = new Address(ADDRESS_STREET, "377", NEIGHBORHOOD, "Esteio", STATE_ABBREVIATION, SHELTER_ZIPCODE);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeAddress("SHELTER_IDENTIFIER", addressUpdate));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ assertEquals(UuidUtilsException.class, exception.getCause().getClass());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenNewAddressIsNullOnChangeAddress() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.changeAddress(SHELTER_IDENTIFIER, null));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.ERROR_MESSAGE_ADDRESS_NULL), exception.getMessage());
+ }
+
+ @Test
+ void shouldAddDonationToShelter() {
+ Donation donation = new Donation("item", 1);
+
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ this.service.addDonation(SHELTER_IDENTIFIER, donation);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+ verify(this.repository, times(1)).save(this.shelterCaptor.capture());
+
+ assertNotNull(shelterCaptor.getValue());
+ Shelter updatedShelter = this.shelterCaptor.getValue();
+ assertFalse(updatedShelter.getDonations().isEmpty());
+ assertEquals(1, updatedShelter.getDonations().size());
+ assertEquals(donation, updatedShelter.getDonations().get(0));
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsNullOnAddDonation() {
+ Donation donation = new Donation("item", 1);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.addDonation(null, donation));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsEmptyOnAddDonation() {
+ Donation donation = new Donation("item", 1);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.addDonation(" ", donation));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsInvalidOnAddDonation() {
+ Donation donation = new Donation("item", 1);
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.addDonation("SHELTER_IDENTIFIER", donation));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ assertEquals(UuidUtilsException.class, exception.getCause().getClass());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenDonationIsNullOnAddDonation() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class,
+ () -> this.service.addDonation(SHELTER_IDENTIFIER, null));
+
+ verify(this.repository, never()).findById(anyString());
+ verify(this.repository, never()).save(any(ShelterContract.class));
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.DONATION_REQUIRED_ERROR_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldReturnListOfDonations() {
+ Donation donation = new Donation("item", 1);
+ this.shelter.addDonation(donation);
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ List list = this.service.getDonations(SHELTER_IDENTIFIER);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+
+ assertNotNull(list);
+ assertFalse(this.shelter.getDonations().isEmpty());
+ assertEquals(1, list.size());
+ assertEquals(donation, list.get(0));
+ }
+
+ @Test
+ void shouldReturnListOfDonationsEmpty() {
+ when(this.repository.findById(SHELTER_IDENTIFIER)).thenReturn(this.shelter);
+
+ List list = this.service.getDonations(SHELTER_IDENTIFIER);
+
+ verify(this.repository, times(1)).findById(SHELTER_IDENTIFIER);
+
+ assertNotNull(list);
+ assertTrue(this.shelter.getDonations().isEmpty());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsNullOnGetDonations() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class, () -> this.service.getDonations(null));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsEmptyOnGetDonations() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class, () -> this.service.getDonations(""));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowShelterServiceFailureExceptionWhenShelterIdIsInvalidOnGetDonations() {
+
+ ShelterServiceFailureException exception = assertThrows(ShelterServiceFailureException.class, () -> this.service.getDonations("SHELTER_IDENTIFIER"));
+
+ verify(this.repository, never()).findById(anyString());
+
+ assertNotNull(exception);
+ assertEquals(ShelterServiceFailureException.ERROR.buildMessage(ShelterService.INVALID_SHELTER_ID_MESSAGE), exception.getMessage());
+ }
+
+}
diff --git a/src/test/java/diegosneves/github/conectardoacoes/core/service/UserServiceTest.java b/src/test/java/diegosneves/github/conectardoacoes/core/service/UserServiceTest.java
new file mode 100644
index 0000000..9c9054b
--- /dev/null
+++ b/src/test/java/diegosneves/github/conectardoacoes/core/service/UserServiceTest.java
@@ -0,0 +1,502 @@
+package diegosneves.github.conectardoacoes.core.service;
+
+import diegosneves.github.conectardoacoes.core.domain.shelter.entity.ShelterContract;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.User;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.UserContract;
+import diegosneves.github.conectardoacoes.core.domain.user.entity.value.UserProfile;
+import diegosneves.github.conectardoacoes.core.domain.user.shared.repository.UserRepository;
+import diegosneves.github.conectardoacoes.core.enums.ExceptionDetails;
+import diegosneves.github.conectardoacoes.core.exception.ShelterCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UserCreationFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UserServiceFailureException;
+import diegosneves.github.conectardoacoes.core.exception.UuidUtilsException;
+import diegosneves.github.conectardoacoes.core.utils.UuidUtils;
+import org.junit.jupiter.api.BeforeEach;
+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 org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class UserServiceTest {
+
+ public static final String USER_IDENTIFIER = "89142bda-7b0c-4421-af28-f9cadb316024";
+ public static final String USER_UUID = "0ed6e6a1-882c-4d2d-83ee-67034ee1ab9f";
+ public static final String USERNAME = "Fulano";
+ public static final String USER_EMAIL = "teste@email.com";
+ public static final String USER_PASSWORD = "senha";
+
+ @InjectMocks
+ private UserService userService;
+
+ @Mock
+ private UserRepository userRepository;
+
+ @Captor
+ private ArgumentCaptor userCaptor;
+
+ private User user;
+
+ @BeforeEach
+ void setUp() {
+ this.user = new User(USER_UUID, USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD);
+ }
+
+ @Test
+ void shouldCreateUserAndReturnCreatedUser() {
+ when(this.userRepository.save(any(UserContract.class))).thenReturn(this.user);
+
+ UserContract actual = this.userService.createUser(USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD);
+
+ verify(this.userRepository, times(1)).save(this.userCaptor.capture());
+
+ assertNotNull(this.userCaptor.getValue());
+ User returnedUser = this.userCaptor.getValue();
+ assertNotNull(actual);
+ assertTrue(UuidUtils.isValidUUID(returnedUser.getId()));
+ assertEquals(USER_UUID, actual.getId());
+ assertEquals(USERNAME, returnedUser.getUsername());
+ assertEquals(USERNAME, actual.getUsername());
+ assertEquals(USER_EMAIL, returnedUser.getEmail());
+ assertEquals(USER_EMAIL, actual.getEmail());
+ assertEquals(UserProfile.BENEFICIARY, returnedUser.getUserProfile());
+ assertEquals(UserProfile.BENEFICIARY, actual.getUserProfile());
+ assertEquals(USER_PASSWORD, returnedUser.getUserPassword());
+ assertEquals(USER_PASSWORD, actual.getUserPassword());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUsernameIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(null, USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUsernameIsEmpty() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(" ", USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUserEmailIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(USERNAME, null, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUserEmailIsEmpty() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(USERNAME, "", UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUserProfileIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, null, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUserPasswordIsNull() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, null));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowUserCreationFailureExceptionWhenUserPasswordIsEmpty() {
+
+ Exception actual = assertThrows(Exception.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, " "));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.class, actual.getClass());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenUsernameIsNullOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(null, USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(String.format(User.USERNAME_REQUIRED, UserProfile.BENEFICIARY)), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenUsernameIsEmptyOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(" ", USER_EMAIL, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(String.format(User.USERNAME_REQUIRED, UserProfile.BENEFICIARY)), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenEmailIsNullOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(USERNAME, null, UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(User.EMAIL_NOT_PROVIDED), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenEmailIsEmptyOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(USERNAME, "", UserProfile.BENEFICIARY, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(User.EMAIL_NOT_PROVIDED), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenUserProfileIsNullOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, null, USER_PASSWORD));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(User.PROFILE_NOT_PROVIDED), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenPasswordIsNullOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, null));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(User.PASSWORD_NOT_PROVIDED), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenPasswordIsEmptyOnCreateUser() {
+
+ UserCreationFailureException actual = assertThrows(UserCreationFailureException.class,
+ () -> this.userService.createUser(USERNAME, USER_EMAIL, UserProfile.BENEFICIARY, " "));
+
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(actual);
+ assertEquals(UserCreationFailureException.ERROR.buildMessage(User.PASSWORD_NOT_PROVIDED), actual.getMessage());
+ }
+
+ @Test
+ void shouldGetUserById() {
+ when(this.userRepository.findById(USER_UUID)).thenReturn(this.user);
+
+ UserContract actual = this.userService.getUser(USER_UUID);
+
+ verify(this.userRepository, times(1)).findById(USER_UUID);
+
+ assertNotNull(actual);
+ assertEquals(this.user, actual);
+ }
+
+ @Test
+ void shouldReturnNullWhenUserNotFoundOnGetUser() {
+ when(this.userRepository.findById(USER_IDENTIFIER)).thenReturn(null);
+
+ UserContract actual = this.userService.getUser(USER_IDENTIFIER);
+
+ verify(this.userRepository, times(1)).findById(USER_IDENTIFIER);
+
+ assertNull(actual);
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNullUserIdProvidedOnGetUser() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.getUser(null));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenEmptyUserIdProvidedOnGetUser() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.getUser(" "));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenInvalidUserIdProvidedOnGetUser() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.getUser("id"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ assertEquals(UuidUtilsException.class, actual.getCause().getClass());
+ }
+
+ @Test
+ void shouldChangeUserPasswordAndPersistTheChange() {
+ String newPassword = "newPassword";
+ when(this.userRepository.findById(USER_UUID)).thenReturn(this.user);
+
+ this.userService.changePassword(USER_UUID, newPassword);
+
+ verify(this.userRepository, times(1)).findById(USER_UUID);
+ verify(this.userRepository, times(1)).save(this.userCaptor.capture());
+
+ assertNotNull(userCaptor.getValue());
+ User updatedUser = userCaptor.getValue();
+ assertEquals(USER_UUID, updatedUser.getId());
+ assertEquals(USERNAME, updatedUser.getUsername());
+ assertEquals(USER_EMAIL, updatedUser.getEmail());
+ assertEquals(newPassword, updatedUser.getUserPassword());
+ assertEquals(UserProfile.BENEFICIARY, updatedUser.getUserProfile());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNewPasswordIsNull() {
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changePassword(USER_UUID, null));
+
+ verify(this.userRepository, never()).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_NEW_PASSWORD_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNewPasswordIsEmpty() {
+ String newPassword = " ";
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changePassword(USER_UUID, newPassword));
+
+ verify(this.userRepository, never()).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_NEW_PASSWORD_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenUserNotFound() {
+ String newPassword = "newPassword";
+ when(this.userRepository.findById(USER_UUID)).thenReturn(null);
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changePassword(USER_UUID, newPassword));
+
+ verify(this.userRepository, times(1)).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.USER_NOT_FOUND_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNullUserIdProvidedOnChangePassword() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.changePassword(null, "newPassword"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenEmptyUserIdProvidedOnChangePassword() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.changePassword(" ", "newPassword"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenInvalidUserIdProvidedOnChangePassword() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class, () -> this.userService.changePassword("Invalid", "newPassword"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ assertEquals(UuidUtilsException.class, actual.getCause().getClass());
+ }
+
+ @Test
+ void shouldChangeUsernameAndPersistTheChange() {
+ String newUsername = "newUsername";
+ when(this.userRepository.findById(USER_UUID)).thenReturn(this.user);
+
+ this.userService.changeUserName(USER_UUID, newUsername);
+
+ verify(this.userRepository, times(1)).findById(USER_UUID);
+ verify(this.userRepository, times(1)).save(this.userCaptor.capture());
+
+ assertNotNull(userCaptor.getValue());
+ User updatedUser = userCaptor.getValue();
+ assertEquals(USER_UUID, updatedUser.getId());
+ assertEquals(newUsername, updatedUser.getUsername());
+ assertEquals(USER_EMAIL, updatedUser.getEmail());
+ assertEquals(USER_PASSWORD, updatedUser.getUserPassword());
+ assertEquals(UserProfile.BENEFICIARY, updatedUser.getUserProfile());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNewUsernameIsNull() {
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName(USER_UUID, null));
+
+ verify(this.userRepository, never()).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.USERNAME_INVALID_ERROR_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNewUsernameIsEmpty() {
+ String newUsername = " ";
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName(USER_UUID, newUsername));
+
+ verify(this.userRepository, never()).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.USERNAME_INVALID_ERROR_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenUserNotFoundOnChangeUsername() {
+ String newUsername = "newUsername";
+ when(this.userRepository.findById(USER_UUID)).thenReturn(null);
+
+ UserServiceFailureException exception = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName(USER_UUID, newUsername));
+
+ verify(this.userRepository, times(1)).findById(USER_UUID);
+ verify(this.userRepository, never()).save(any(UserContract.class));
+
+ assertNotNull(exception);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.USER_NOT_FOUND_MESSAGE), exception.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenNullUserIdProvidedOnChangeUsername() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName(null, "newUsername"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenEmptyUserIdProvidedOnChangeUsername() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName(" ", "newUsername"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ }
+
+ @Test
+ void shouldThrowUserServiceFailureExceptionWhenInvalidUserIdProvidedOnChangeUsername() {
+
+ UserServiceFailureException actual = assertThrows(UserServiceFailureException.class,
+ () -> this.userService.changeUserName("ID", "newUsername"));
+
+ verify(this.userRepository, never()).findById(anyString());
+
+ assertNotNull(actual);
+ assertEquals(UserServiceFailureException.ERROR.buildMessage(UserService.INVALID_IDENTIFIER_ERROR_MESSAGE), actual.getMessage());
+ assertEquals(UuidUtilsException.class, actual.getCause().getClass());
+ }
+
+}
diff --git a/src/test/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtilsTest.java b/src/test/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtilsTest.java
new file mode 100644
index 0000000..1cbe45d
--- /dev/null
+++ b/src/test/java/diegosneves/github/conectardoacoes/core/utils/ValidationUtilsTest.java
@@ -0,0 +1,98 @@
+package diegosneves.github.conectardoacoes.core.utils;
+
+import diegosneves.github.conectardoacoes.core.exception.ValidationUtilsException;
+import lombok.SneakyThrows;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ValidationUtilsTest {
+
+ public static final String NULL_VALUE_ERROR_MESSAGE = "Valor Nulo";
+ public static final String EMPTY_STRING = " ";
+ public static final String EMPTY_VALUE_ERROR = "Valor vazio";
+ public static final String UNEXPECTED_EXCEPTION = "Exceção não deveria ter sido lançada";
+
+ private String value;
+
+ @BeforeEach
+ void setUp() {
+ this.value = EMPTY_STRING;
+ }
+
+ @Test
+ void isNullOrEmpty() {
+ this.value = "Teste";
+ try {
+ ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.value, EMPTY_VALUE_ERROR, IllegalArgumentException.class);
+ } catch (Exception e) {
+ fail(UNEXPECTED_EXCEPTION);
+ }
+ }
+
+ @Test
+ void checkStringNotNull() {
+ this.value = null;
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+ () -> ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.value, NULL_VALUE_ERROR_MESSAGE, IllegalArgumentException.class));
+
+ assertNotNull(exception);
+ assertEquals(NULL_VALUE_ERROR_MESSAGE, exception.getMessage());
+ }
+
+ @Test
+ void checkStringNotNullWithValidateUtilsException() {
+ this.value = null;
+
+ ValidationUtilsException exception = assertThrows(ValidationUtilsException.class,
+ () -> ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.value, NULL_VALUE_ERROR_MESSAGE, NoMethodFoundException.class));
+
+ assertNotNull(exception);
+ assertEquals(ValidationUtilsException.ERROR.buildMessage(NoMethodFoundException.class.getSimpleName()), exception.getMessage());
+ }
+
+ @Test
+ void checkStringNotEmptyWithValidateUtilsException() {
+
+ ValidationUtilsException exception = assertThrows(ValidationUtilsException.class,
+ () -> ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.value, EMPTY_VALUE_ERROR, NoMethodFoundException.class));
+
+ assertNotNull(exception);
+ assertEquals(ValidationUtilsException.ERROR.buildMessage(NoMethodFoundException.class.getSimpleName()), exception.getMessage());
+ }
+
+ @Test
+ void checkStringNotEmpty() {
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
+ () -> ValidationUtils.checkNotNullAndNotEmptyOrThrowException(this.value, EMPTY_VALUE_ERROR, IllegalArgumentException.class));
+
+ assertNotNull(exception);
+ assertEquals(EMPTY_VALUE_ERROR, exception.getMessage());
+ }
+
+ @Test
+ @SneakyThrows
+ void shouldThrowNoSuchMethodException() {
+ Method method = ValidationUtils.class.getDeclaredMethod("throwException", String.class, Class.class);
+ method.setAccessible(true);
+
+ InvocationTargetException exception = assertThrows(InvocationTargetException.class,
+ () -> method.invoke(ValidationUtils.class, this.value, NoMethodFoundException.class));
+
+ assertNotNull(exception);
+ assertInstanceOf(NoSuchMethodException.class, exception.getCause().getCause());
+ assertEquals(ValidationUtilsException.ERROR.buildMessage(NoMethodFoundException.class.getSimpleName()), exception.getTargetException().getMessage());
+ }
+
+ static class NoMethodFoundException extends RuntimeException {
+
+ public NoMethodFoundException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+}