From 4544f172aed4f04cd7ca005e7935be4a236f2dea Mon Sep 17 00:00:00 2001 From: roost-io <8110509+mgdevstack@users.noreply.github.com> Date: Sun, 3 May 2026 21:35:44 +0530 Subject: [PATCH] Unit test generated by RoostGPT Using AI Model gpt-5 --- pom.xml | 249 ++++-- ...erAccountControllerDeleteUserByIdTest.java | 115 +++ ...UserAccountControllerFindUserByIdTest.java | 562 ++++++++++++ ...AccountControllerUpdateInfoUserByTest.java | 165 ++++ ...erAccountControllerUpdateUserByIdTest.java | 825 ++++++++++++++++++ 5 files changed, 1820 insertions(+), 96 deletions(-) create mode 100644 src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerDeleteUserByIdTest.java create mode 100644 src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerFindUserByIdTest.java create mode 100644 src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateInfoUserByTest.java create mode 100644 src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateUserByIdTest.java diff --git a/pom.xml b/pom.xml index d5e071f9..cf9d3292 100644 --- a/pom.xml +++ b/pom.xml @@ -1,96 +1,153 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.0.6 - - - com.medeiros - SPRINGProject - 0.0.1-SNAPSHOT - SPRINGProject - Demo project for Spring Boot - - 20 - - 6.0.3 - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - com.mysql - mysql-connector-j - runtime - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.boot - spring-boot-starter-thymeleaf - 3.0.6 - - - - org.springframework.boot - spring-boot-starter-security - - - - io.jsonwebtoken - jjwt-api - 0.11.5 - - - - - - - org.springframework.security - spring-security-core - 6.0.3 - - - - - - - io.jsonwebtoken - jjwt-impl - 0.11.5 - runtime - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.0.6 + + + + com.medeiros + SPRINGProject + 0.0.1-SNAPSHOT + SPRINGProject + Demo project for Spring Boot + + 20 + + 6.0.3 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + com.mysql + mysql-connector-j + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-thymeleaf + 3.0.6 + + + org.springframework.boot + spring-boot-starter-security + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + + org.springframework.security + spring-security-core + 6.0.3 + + + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + org.mockito + mockito-junit-jupiter + 2.23.4 + test + + + + io.spring.javaformat + spring-javaformat-formatter + 0.0.40 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.jacoco + jacoco-maven-plugin + 0.8.11 + + + + prepare-agent + + + + report + test + + report + + + coverageReport + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.2.5 + + testReport + + + + + org.apache.maven.plugins + maven-site-plugin + 2.1 + + testReport + + + + + io.spring.javaformat + spring-javaformat-maven-plugin + 0.0.40 + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerDeleteUserByIdTest.java b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerDeleteUserByIdTest.java new file mode 100644 index 00000000..cfaac0ce --- /dev/null +++ b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerDeleteUserByIdTest.java @@ -0,0 +1,115 @@ + +// ********RoostGPT******** +/* +Test generated by RoostGPT for test maven-music-github using AI Type Azure Open AI and AI Model gpt-5 + +ROOST_METHOD_HASH=deleteUserById_d65ace15d7 +ROOST_METHOD_SIG_HASH=deleteUserById_91ecd15d81 + +Scenario 1: Successfully deletes when ID is a valid numeric string + +Details: + TestName: deletesUserWhenValidNumericId + Description: Verifies that when a valid numeric string (e.g., "123") is provided, the method parses it, calls UserAccRepo.deleteById with the correct integer value, and returns the expected success message. + +Execution: + Arrange: Set up a UserAccountController with a mock UserAccRepository that does not throw on deleteById, and mock UserInfoRepository and LogRepository. + Act: Call deleteUserById with "123". + Assert: Check that the returned string equals "Conta Deletada" and that UserAccRepo.deleteById was invoked exactly once with 123. Also verify no interactions with UserInfoRepo or Log. + +Validation: + Confirms the primary happy path: valid input leads to a delete call and a fixed success message. Ensures the method uses only UserAccRepo for this operation and returns the literal Portuguese message as designed. + +*/ + +// ********RoostGPT******** + +package com.medeiros.SPRINGProject.Controllers; + +import com.medeiros.SPRINGProject.Controllers.UserAccountController; +import com.medeiros.SPRINGProject.Models.*; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Optional; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.*; + +@ExtendWith(MockitoExtension.class) +public class UserAccountControllerDeleteUserByIdTest { + + @InjectMocks + private UserAccountController controller; + + @Mock + private UserAccRepository UserAccRepo; + + @Mock + private UserInfoRepository UserInfoRepo; + + @Mock + private LogRepository Log; + + @Test + @Tag("valid") + public void testDeletesUserWhenValidNumericId() { + String inputId = "123"; + String result = controller.deleteUserById(inputId); + assertEquals((String) "Conta Deletada", (String) result); + verify(UserAccRepo, times(1)).deleteById(123); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testDeleteUserWithZeroId() { + String inputId = "0"; + String result = controller.deleteUserById(inputId); + assertEquals((String) "Conta Deletada", (String) result); + verify(UserAccRepo, times(1)).deleteById(0); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testDeleteUserWithNegativeId() { + String inputId = "-1"; + String result = controller.deleteUserById(inputId); + assertEquals((String) "Conta Deletada", (String) result); + verify(UserAccRepo, times(1)).deleteById(-1); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testDeleteUserWithNonNumericIdThrowsNumberFormatException() { + String inputId = "abc"; // TODO: Replace with other non-numeric strings if needed + assertThrows(NumberFormatException.class, () -> controller.deleteUserById(inputId)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testDeleteUserWithWhitespaceOnlyThrowsNumberFormatException() { + String inputId = " 123 "; // TODO: Replace with other whitespace formats if needed + assertThrows(NumberFormatException.class, () -> controller.deleteUserById(inputId)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testDeleteUserWithNullIdThrowsNumberFormatException() { + String inputId = null; + assertThrows(NumberFormatException.class, () -> controller.deleteUserById(inputId)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + +} \ No newline at end of file diff --git a/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerFindUserByIdTest.java b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerFindUserByIdTest.java new file mode 100644 index 00000000..f6a04b77 --- /dev/null +++ b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerFindUserByIdTest.java @@ -0,0 +1,562 @@ + +// ********RoostGPT******** +/* +Test generated by RoostGPT for test maven-music-github using AI Type Azure Open AI and AI Model gpt-5 + +ROOST_METHOD_HASH=findUserById_fca20bfdc9 +ROOST_METHOD_SIG_HASH=findUserById_46f9fcf424 + +Scenario 1: Valid numeric ID string returns the User_Credentials from the repository + +Details: + TestName: validNumericIdReturnsUserCredentials + Description: Verifies that when a valid numeric string ID (e.g., "42") is provided, the method parses it to an integer and returns exactly the User_Credentials object provided by UserAccRepo.findById. + +Execution: + Arrange: Set up UserAccRepo as a mock to return a specific User_Credentials instance (e.g., mockUser) when called with 42. Ensure UserInfoRepo and Log are present as mocks/dummies but not interacted with. + Act: Call findUserById with "42". + Assert: Use assertions to confirm the returned object is the same instance as mockUser and that no exception is thrown. Verify UserAccRepo.findById is invoked exactly once with 42 and that there are no interactions with UserInfoRepo or Log. + +Validation: + Confirms correct parsing of a standard numeric string and proper delegation to the repository. Ensures the controller does not mutate or wrap the repository’s return value and avoids unintended interactions with unrelated components. + +Scenario 2: Nonexistent user (repository returns null) results in null return + +Details: + TestName: nonexistentUserReturnsNull + Description: Ensures that if UserAccRepo.findById returns null for a valid parsed integer ID, the method returns null directly. + +Execution: + Arrange: Mock UserAccRepo.findById(100) to return null. + Act: Call findUserById with "100". + Assert: Assert that the returned value is null and that no exception is thrown. Verify findById is called once with 100 and no interactions occur with UserInfoRepo or Log. + +Validation: + Verifies pass-through behavior for missing data and that the method does not attempt to handle absence beyond returning null, consistent with the current implementation. + +Scenario 3: ID with leading zeros is parsed correctly and repository is called with the parsed int + +Details: + TestName: idWithLeadingZerosParsesToInt + Description: Confirms that a numeric string with leading zeros (e.g., "0005") is parsed to the integer 5 and that the repository is called with 5. + +Execution: + Arrange: Mock UserAccRepo.findById(5) to return a known User_Credentials instance (mockUser). + Act: Call findUserById with "0005". + Assert: Assert that the returned object is mockUser and that UserAccRepo.findById received 5. Assert no other components are interacted with. + +Validation: + Ensures robust parsing behavior consistent with Integer.parseInt and correct argument propagation to the repository. + +Scenario 4: ID with a leading plus sign parses correctly + +Details: + TestName: plusSignedIdParsesCorrectly + Description: Validates that an ID like "+10" is accepted by Integer.parseInt and results in a repository call with 10. + +Execution: + Arrange: Mock UserAccRepo.findById(10) to return a User_Credentials instance (mockUser). + Act: Call findUserById with "+10". + Assert: Assert that the returned object is mockUser, and verify the repository was called with 10 exactly once. No interactions with UserInfoRepo or Log. + +Validation: + Confirms support for optional leading plus sign as allowed by Integer.parseInt. + +Scenario 5: ID equal to zero is handled by parsing and repository invocation + +Details: + TestName: zeroIdHandled + Description: Checks that "0" parses to 0 and the repository is invoked with 0, returning whatever the repository provides. + +Execution: + Arrange: Mock UserAccRepo.findById(0) to return a specific User_Credentials instance (mockUser). + Act: Call findUserById with "0". + Assert: Assert the returned object is mockUser and verify findById was called with 0. No other interactions. + +Validation: + Verifies acceptance of boundary value 0 and correct handoff to the repository. + +Scenario 6: Maximum int value as string is handled correctly + +Details: + TestName: maxIntIdHandled + Description: Ensures that "2147483647" (Integer.MAX_VALUE) is parsed successfully and used to call the repository. + +Execution: + Arrange: Mock UserAccRepo.findById(2147483647) to return mockUser. + Act: Call findUserById with "2147483647". + Assert: Assert the returned object is mockUser, and verify the repository was called once with 2147483647. No interactions with other components. + +Validation: + Confirms correct boundary handling at the upper limit of int. + +Scenario 7: Minimum int value (negative boundary) is handled correctly + +Details: + TestName: minIntIdHandled + Description: Ensures that "-2147483648" (Integer.MIN_VALUE) parses and the repository is called with that exact value. + +Execution: + Arrange: Mock UserAccRepo.findById(-2147483648) to return either a mock user or null, and set expected outcome accordingly. + Act: Call findUserById with "-2147483648". + Assert: Assert the result matches the repository’s configured return (either the mock user or null). Verify findById was called with -2147483648. + +Validation: + Confirms that negative boundary values are supported and properly delegated. + +Scenario 8: Purely non-numeric string results in NumberFormatException + +Details: + TestName: nonNumericIdThrowsNumberFormatException + Description: Verifies that providing an ID like "abc" triggers NumberFormatException from Integer.parseInt and the repository is not invoked. + +Execution: + Arrange: Ensure no repository stubbing for this input. + Act: Call findUserById with "abc". + Assert: Assert that NumberFormatException is thrown. Assert no interactions with UserAccRepo, UserInfoRepo, or Log. + +Validation: + Ensures input validation via parsing behaves as expected for non-numeric values. + +Scenario 9: Alphanumeric string results in NumberFormatException + +Details: + TestName: alphanumericIdThrowsNumberFormatException + Description: Confirms that "123abc" is rejected by the parser and the method throws NumberFormatException without calling the repository. + +Execution: + Arrange: No repository stubs are needed. + Act: Call findUserById with "123abc". + Assert: Assert that NumberFormatException is thrown. Verify no interactions with any repositories or Log. + +Validation: + Enforces strict numeric formatting requirements. + +Scenario 10: Empty string results in NumberFormatException + +Details: + TestName: emptyIdThrowsNumberFormatException + Description: An empty ID string should cause Integer.parseInt to throw NumberFormatException, preventing any repository calls. + +Execution: + Arrange: No repository stubs are needed. + Act: Call findUserById with "". + Assert: Assert NumberFormatException is thrown and verify no interactions with UserAccRepo, UserInfoRepo, or Log. + +Validation: + Confirms enforcement of non-empty, numeric input. + +Scenario 11: Whitespace-only string results in NumberFormatException + +Details: + TestName: whitespaceOnlyIdThrowsNumberFormatException + Description: A string containing only whitespace (e.g., " ") is invalid and should cause NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Call findUserById with " ". + Assert: Assert NumberFormatException is thrown and no repository interactions occur. + +Validation: + Ensures trimming is not performed and pure whitespace is treated as invalid input. + +Scenario 12: Null ID results in NumberFormatException + +Details: + TestName: nullIdThrowsNumberFormatException + Description: Passing a null ID to Integer.parseInt should raise NumberFormatException ("null"). + +Execution: + Arrange: No repository stubbing required. + Act: Call findUserById with null. + Assert: Assert NumberFormatException is thrown. Verify no interactions with UserAccRepo, UserInfoRepo, or Log. + +Validation: + Verifies that null inputs are not accepted and parsing enforces input presence. + +Scenario 13: Overflow beyond Integer.MAX_VALUE results in NumberFormatException + +Details: + TestName: overflowIdThrowsNumberFormatException + Description: Providing "2147483648" (MAX_VALUE + 1) should cause NumberFormatException due to overflow. + +Execution: + Arrange: No repository setup needed. + Act: Call findUserById with "2147483648". + Assert: Assert NumberFormatException is thrown and confirm no repository calls. + +Validation: + Ensures numeric boundary enforcement and safe failure on overflow. + +Scenario 14: Underflow beyond Integer.MIN_VALUE results in NumberFormatException + +Details: + TestName: underflowIdThrowsNumberFormatException + Description: Providing "-2147483649" (MIN_VALUE - 1) should cause NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Call findUserById with "-2147483649". + Assert: Assert NumberFormatException is thrown and verify no repository interaction. + +Validation: + Confirms enforcement of lower integer boundary conditions. + +Scenario 15: Non-ASCII digit string results in NumberFormatException + +Details: + TestName: nonAsciiDigitIdThrowsNumberFormatException + Description: A string like "123" (full-width digits) is not recognized by Integer.parseInt and should cause NumberFormatException. + +Execution: + Arrange: No repository setup needed. + Act: Call findUserById with "123". + Assert: Assert NumberFormatException is thrown. Confirm no calls to UserAccRepo. + +Validation: + Ensures inputs must be standard ASCII numeric characters. + +Scenario 16: Hex-prefixed string is rejected with NumberFormatException + +Details: + TestName: hexPrefixedIdThrowsNumberFormatException + Description: A string like "0x10" should not be interpreted as a valid decimal number and should cause NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Call findUserById with "0x10". + Assert: Assert NumberFormatException is thrown and no repository calls are made. + +Validation: + Confirms decimal-only parsing and rejection of non-decimal formats. + +Scenario 17: String with trailing newline results in NumberFormatException + +Details: + TestName: idWithTrailingNewlineThrowsNumberFormatException + Description: A string such as "5\n" should fail parsing and raise NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Call findUserById with "5\n". + Assert: Assert NumberFormatException is thrown. Verify no repository interactions occur. + +Validation: + Confirms that extraneous whitespace/control characters render the input invalid. + +Scenario 18: Double sign prefix results in NumberFormatException + +Details: + TestName: doubleSignIdThrowsNumberFormatException + Description: A string like "++1" is invalid and should cause NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Call findUserById with "++1". + Assert: Assert NumberFormatException is thrown and no repository interactions occur. + +Validation: + Ensures strict adherence to valid sign formatting for numeric strings. + +Scenario 19: Repository runtime exception is propagated unchanged + +Details: + TestName: repositoryThrowsRuntimeExceptionPropagates + Description: If UserAccRepo.findById throws a RuntimeException (e.g., data access failure), the controller method should not catch it and should propagate the exception. + +Execution: + Arrange: Mock UserAccRepo.findById(7) to throw a RuntimeException. + Act: Call findUserById with "7". + Assert: Assert that the same RuntimeException is thrown and not wrapped. Verify findById was attempted exactly once. + +Validation: + Confirms that the method does not suppress or alter exceptions from the repository, preserving error semantics. + +Scenario 20: No interaction with UserInfoRepo and Log for find operation + +Details: + TestName: noInteractionWithOtherRepositories + Description: Ensures that findUserById never interacts with UserInfoRepo or Log, regardless of successful or failing parse. + +Execution: + Arrange: Provide mocks for UserInfoRepo and Log. Set UserAccRepo.findById(9) to return a mock user. + Act: Call findUserById with "9". + Assert: Assert the returned object is the mock user. Verify zero interactions with UserInfoRepo and Log. Optionally, repeat with an invalid input (e.g., "x") and verify that neither is touched. + +Validation: + Ensures the method’s scope is limited to user credential retrieval and does not perform unrelated operations. + +Scenario 21: Extremely long numeric string causes NumberFormatException + +Details: + TestName: extremelyLongNumericStringThrowsNumberFormatException + Description: An excessively long numeric string (e.g., 1000 digits) should not parse successfully and should cause NumberFormatException. + +Execution: + Arrange: Generate a long numeric string and avoid stubbing the repository. + Act: Call findUserById with the long string. + Assert: Assert NumberFormatException is thrown. Verify no repository calls. + +Validation: + Confirms robust failure behavior under unusually large inputs that exceed int capacity. + +Scenario 22: Negative zero string parses to zero and calls repository with 0 + +Details: + TestName: negativeZeroIdParsesToZero + Description: Validates that "-0" is parsed by Integer.parseInt as 0 and that the repository receives 0. + +Execution: + Arrange: Mock UserAccRepo.findById(0) to return a known User_Credentials instance (mockUser). + Act: Call findUserById with "-0". + Assert: Assert the returned object is mockUser and verify findById is called with 0 exactly once. No interactions with other components. + +Validation: + Ensures consistent parsing behavior for signed zero inputs and correct delegation to the repository. + +*/ + +// ********RoostGPT******** + +package com.medeiros.SPRINGProject.Controllers; + +import com.medeiros.SPRINGProject.Models.*; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Optional; + +@ExtendWith(MockitoExtension.class) +public class UserAccountControllerFindUserByIdTest { + + @Mock + private UserAccRepository UserAccRepo; + + @Mock + private UserInfoRepository UserInfoRepo; + + @Mock + private LogRepository Log; + + @InjectMocks + private UserAccountController controller; + + @Test + @Tag("valid") + public void validNumericIdReturnsUserCredentials() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(42)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("42")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(42); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void nonexistentUserReturnsNull() { + when(UserAccRepo.findById(100)).thenReturn(null); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("100")); + assertNull((User_Credentials) result); + verify(UserAccRepo, times(1)).findById(100); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void idWithLeadingZerosParsesToInt() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(5)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("0005")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(5); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void plusSignedIdParsesCorrectly() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(10)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("+10")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(10); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void zeroIdHandled() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(0)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("0")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(0); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void maxIntIdHandled() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(2147483647)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("2147483647")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(2147483647); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void minIntIdHandled() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(-2147483648)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("-2147483648")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(-2147483648); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void nonNumericIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("abc")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void alphanumericIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("123abc")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void emptyIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void whitespaceOnlyIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById(" ")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void nullIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById(null)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void overflowIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("2147483648")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void underflowIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("-2147483649")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void nonAsciiDigitIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("123")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void hexPrefixedIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("0x10")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void idWithTrailingNewlineThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("5\n")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void doubleSignIdThrowsNumberFormatException() { + assertThrows(NumberFormatException.class, () -> controller.findUserById("++1")); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("integration") + public void repositoryThrowsRuntimeExceptionPropagates() { + RuntimeException expected = new RuntimeException("Data access failure"); // TODO + // adjust + // message + // if + // repository + // defines + // specific + // errors + when(UserAccRepo.findById(7)).thenThrow(expected); + RuntimeException thrown = assertThrows(RuntimeException.class, () -> controller.findUserById("7")); + assertSame((RuntimeException) expected, (RuntimeException) thrown); + verify(UserAccRepo, times(1)).findById(7); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void noInteractionWithOtherRepositories() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(9)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("9")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(9); + verifyNoInteractions(UserInfoRepo, Log); + assertThrows(NumberFormatException.class, () -> controller.findUserById("x")); + verifyNoMoreInteractions(UserAccRepo); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void extremelyLongNumericStringThrowsNumberFormatException() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 1000; i++) { + sb.append('1'); + } + String longNumeric = sb.toString(); + assertThrows(NumberFormatException.class, () -> controller.findUserById(longNumeric)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void negativeZeroIdParsesToZero() { + User_Credentials mockUser = mock(User_Credentials.class); + when(UserAccRepo.findById(0)).thenReturn(mockUser); + User_Credentials result = assertDoesNotThrow(() -> controller.findUserById("-0")); + assertSame((User_Credentials) mockUser, (User_Credentials) result); + verify(UserAccRepo, times(1)).findById(0); + verifyNoInteractions(UserInfoRepo, Log); + } + +} \ No newline at end of file diff --git a/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateInfoUserByTest.java b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateInfoUserByTest.java new file mode 100644 index 00000000..b807f64c --- /dev/null +++ b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateInfoUserByTest.java @@ -0,0 +1,165 @@ + +// ********RoostGPT******** +/* +Test generated by RoostGPT for test maven-music-github using AI Type Azure Open AI and AI Model gpt-5 + +ROOST_METHOD_HASH=updateInfoUserBy_b88001e4be +ROOST_METHOD_SIG_HASH=updateInfoUserBy_642c0765ab + +Scenario 1: Successful save returns confirmation and persists new user info + +Details: + TestName: updateInfoSavesAndReturnsUpdated + Description: Verifies the happy-path behavior where valid inputs lead to creation of a User_Info instance, persistence via UserInfoRepo.save, and the controller returns the confirmation string "ATUALIZADO". + +Execution: + Arrange: Mock UserInfoRepository to accept any User_Info instance without throwing exceptions. Instantiate UserAccountController with the mocked UserInfoRepo; other repositories can be mocked or left unused. + Act: Invoke updateInfoUserBy with a valid userId and representative non-empty strings for all parameters (photoURL, favoritesMusics, gender, phone, instaURL, twitterURL, favoritesThings). + Assert: Use a JUnit assertion to check that the returned string equals "ATUALIZADO". Verify that UserInfoRepo.save was called exactly once with an instance of User_Info. + +Validation: + The assertion verifies that the controller responds with the expected success message and that the persistence operation is attempted once. This confirms that the method’s core behavior (constructing and saving User_Info, then returning "ATUALIZADO") works under normal conditions. + +*/ + +// ********RoostGPT******** + +package com.medeiros.SPRINGProject.Controllers; + +import com.medeiros.SPRINGProject.Models.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Optional; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.*; + +@ExtendWith(MockitoExtension.class) +public class UserAccountControllerUpdateInfoUserByTest { + + @InjectMocks + private UserAccountController controller; + + @Mock + private UserInfoRepository UserInfoRepo; + + @Mock + private UserAccRepository UserAccRepo; + + @Mock + private LogRepository Log; + + @Test + @Tag("valid") + @DisplayName("Scenario 1: Successful save returns confirmation and persists new user info") + public void testUpdateInfoSavesAndReturnsUpdated() { + int userId = 42; + String photoURL = "http://example.com/photo.jpg"; + String favoritesMusics = "rock,pop"; + String gender = "non-binary"; + String phone = "+15551234567"; + String instaURL = "http://instagram.com/example"; + String twitterURL = "http://twitter.com/example"; + String favoritesThings = "coding,testing"; + String result = controller.updateInfoUserBy(userId, photoURL, favoritesMusics, gender, phone, instaURL, + twitterURL, favoritesThings); + assertEquals((String) "ATUALIZADO", (String) result); + Optional resultOpt = Optional.ofNullable(result); + assertTrue(resultOpt.isPresent()); + ArgumentCaptor captor = ArgumentCaptor.forClass(User_Info.class); + verify(UserInfoRepo, times(1)).save(captor.capture()); + assertNotNull((Object) captor.getValue()); + // Minimal validation for live values as per instruction + LocalDateTime now = LocalDateTime.now(); + assertNotNull((Object) now); + } + + @Test + @Tag("boundary") + @DisplayName("Empty string parameters should still save and return updated confirmation") + public void testUpdateInfoWithEmptyStringsStillSaves() { + int userId = 7; + String photoURL = ""; + String favoritesMusics = ""; + String gender = ""; + String phone = ""; + String instaURL = ""; + String twitterURL = ""; + String favoritesThings = ""; + String result = controller.updateInfoUserBy(userId, photoURL, favoritesMusics, gender, phone, instaURL, + twitterURL, favoritesThings); + assertEquals((String) "ATUALIZADO", (String) result); + verify(UserInfoRepo, times(1)).save(any(User_Info.class)); + verifyNoMoreInteractions(UserAccRepo, Log); + assertTrue(Objects.nonNull((Object) result)); + } + + @Test + @Tag("boundary") + @DisplayName("Negative userId should still attempt save and return updated confirmation (no validation present)") + public void testUpdateInfoWithNegativeUserId() { + int userId = -1; + String photoURL = "http://example.com/neg.jpg"; + String favoritesMusics = "jazz"; + String gender = "prefer_not_to_say"; + String phone = "0000000000"; + String instaURL = "http://instagram.com/neg"; + String twitterURL = "http://twitter.com/neg"; + String favoritesThings = "reading"; + String result = controller.updateInfoUserBy(userId, photoURL, favoritesMusics, gender, phone, instaURL, + twitterURL, favoritesThings); + assertEquals((String) "ATUALIZADO", (String) result); + verify(UserInfoRepo, times(1)).save(any(User_Info.class)); + verifyNoMoreInteractions(UserAccRepo, Log); + } + + @Test + @Tag("boundary") + @DisplayName("Max int userId should save and return updated confirmation") + public void testUpdateInfoWithMaxIntUserId() { + int userId = Integer.MAX_VALUE; + String photoURL = "http://example.com/max.jpg"; + String favoritesMusics = "classical"; + String gender = "other"; + String phone = "+19998887777"; + String instaURL = "http://instagram.com/max"; + String twitterURL = "http://twitter.com/max"; + String favoritesThings = "hiking"; + String result = controller.updateInfoUserBy(userId, photoURL, favoritesMusics, gender, phone, instaURL, + twitterURL, favoritesThings); + assertEquals((String) "ATUALIZADO", (String) result); + verify(UserInfoRepo, times(1)).save(any(User_Info.class)); + verifyNoMoreInteractions(UserAccRepo, Log); + } + + @Test + @Tag("invalid") + @DisplayName("Repository failure should propagate exception (no handling in controller)") + public void testUpdateInfoSaveThrowsExceptionPropagates() { + int userId = 10; + String photoURL = "http://example.com/fail.jpg"; + String favoritesMusics = "blues"; + String gender = "male"; + String phone = "1234567890"; + String instaURL = "http://instagram.com/fail"; + String twitterURL = "http://twitter.com/fail"; + String favoritesThings = "gaming"; + doThrow(new RuntimeException("DB error")).when(UserInfoRepo).save(any(User_Info.class)); + RuntimeException ex = assertThrows(RuntimeException.class, () -> controller.updateInfoUserBy(userId, photoURL, + favoritesMusics, gender, phone, instaURL, twitterURL, favoritesThings)); + assertEquals((String) "DB error", (String) ex.getMessage()); + verify(UserInfoRepo, times(1)).save(any(User_Info.class)); + verifyNoMoreInteractions(UserAccRepo, Log); + } + +} \ No newline at end of file diff --git a/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateUserByIdTest.java b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateUserByIdTest.java new file mode 100644 index 00000000..afeafb88 --- /dev/null +++ b/src/test/java/com/medeiros/SPRINGProject/Controllers/UserAccountControllerUpdateUserByIdTest.java @@ -0,0 +1,825 @@ + +// ********RoostGPT******** +/* +Test generated by RoostGPT for test maven-music-github using AI Type Azure Open AI and AI Model gpt-5 + +ROOST_METHOD_HASH=updateUserById_45a90e9627 +ROOST_METHOD_SIG_HASH=updateUserById_9cf5a84c94 + +Scenario 1: Successful update when user exists + +Details: + TestName: updateExistingUserSucceedsAndSaves + Description: Verifies that when a valid numeric id is provided and UserAccRepository.findById returns a non-null User_Credentials, the method updates email, password, and username, saves the entity, and returns the success message. + +Execution: + Arrange: Mock UserAccRepository.findById to return a non-null User_Credentials for the given parsed integer id. Prepare sample values for email, password, and username. + Act: Invoke updateUserById with a valid id (e.g., "123"), and non-empty email, password, and username. + Assert: Assert that the returned String equals "Usuário Salvo". Verify that setEmail, setPassword, and setUsername on the returned User_Credentials were called with the provided values, and UserAccRepository.save was called exactly once with that same instance. Verify that UserInfoRepository and LogRepository were not interacted with. + +Validation: + Confirms that the happy path updates and persists the user record and returns the precise success message. Ensures no unintended side effects occur on other repositories. + +Scenario 2: Not found when repository returns null + +Details: + TestName: returnsNotFoundMessageWhenUserDoesNotExist + Description: Ensures that when UserAccRepository.findById returns null for a valid numeric id, the method does not attempt to update or save and returns the not-found message. + +Execution: + Arrange: Mock UserAccRepository.findById to return null for the parsed integer id. + Act: Invoke updateUserById with a valid id string whose parsed value maps to the mocked null result. + Assert: Assert that the returned String equals "User não encontrado". Verify that setEmail, setPassword, setUsername, and UserAccRepository.save are never called. Verify no interactions with UserInfoRepository and LogRepository. + +Validation: + Confirms correct handling of a missing user and validates no updates or persistence occur in this branch. + +Scenario 3: Non-numeric id causes NumberFormatException + +Details: + TestName: throwsNumberFormatExceptionWhenIdIsNonNumeric + Description: Checks that a non-numeric id (e.g., "abc") causes Integer.parseInt to throw NumberFormatException and that the repository is not called. + +Execution: + Arrange: No repository setup required. + Act: Invoke updateUserById with id as "abc" and valid email, password, username. + Assert: Expect a NumberFormatException to be thrown. Verify that UserAccRepository.findById and UserAccRepository.save are never called. Verify no interactions with UserInfoRepository and LogRepository. + +Validation: + Ensures input validation via parseInt is enforced implicitly and that the method fails fast on invalid id input. + +Scenario 4: Null id causes NullPointerException + +Details: + TestName: throwsNullPointerExceptionWhenIdIsNull + Description: Verifies behavior when id is null, which will trigger a NullPointerException at Integer.parseInt before any repository interaction. + +Execution: + Arrange: No repository setup required. + Act: Invoke updateUserById with id as null and valid email, password, username. + Assert: Expect a NullPointerException to be thrown. Verify no interactions with UserAccRepository, UserInfoRepository, and LogRepository. + +Validation: + Confirms that null ids are not handled and result in an exception, matching current method behavior. + +Scenario 5: Out-of-range id causes NumberFormatException + +Details: + TestName: throwsNumberFormatExceptionWhenIdOutOfIntRange + Description: Validates that an id string outside the integer range (e.g., "999999999999") results in NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Invoke updateUserById with a very large numeric string out of int range. + Assert: Expect NumberFormatException. Verify no interactions with repositories. + +Validation: + Ensures the method correctly fails on input that cannot be parsed into a 32-bit integer. + +Scenario 6: Id with whitespace fails parsing + +Details: + TestName: throwsNumberFormatExceptionWhenIdHasSurroundingWhitespace + Description: Confirms that id values with leading/trailing spaces (e.g., " 123 ") are not trimmed and cause NumberFormatException. + +Execution: + Arrange: No repository setup required. + Act: Invoke updateUserById with id as " 123 " and valid other parameters. + Assert: Expect NumberFormatException. Verify no repository interactions. + +Validation: + Shows that the method does not normalize whitespace around id and fails fast on such input. + +Scenario 7: Id with leading zeros parses and updates + +Details: + TestName: updatesSuccessfullyWhenIdHasLeadingZeros + Description: Ensures that an id like "000123" is parsed to 123 and, if the user exists, the update proceeds as normal. + +Execution: + Arrange: Mock UserAccRepository.findById(123) to return a non-null user. + Act: Invoke updateUserById with id "000123" and valid email, password, username. + Assert: Assert returned value is "Usuário Salvo". Verify setters invoked with provided values and save called once with the same instance. + +Validation: + Confirms that leading zeros do not affect integer parsing and normal update flow proceeds. + +Scenario 8: Id with a leading plus sign parses and updates + +Details: + TestName: updatesSuccessfullyWhenIdHasLeadingPlusSign + Description: Verifies that "+42" parses to 42 and the method updates and saves when the user exists. + +Execution: + Arrange: Mock UserAccRepository.findById(42) to return a non-null user. + Act: Invoke updateUserById with id "+42". + Assert: Confirm "Usuário Salvo" is returned and setters/save were executed as expected. + +Validation: + Demonstrates tolerant parsing of signed integers and successful update behavior. + +Scenario 9: Negative id not found path + +Details: + TestName: returnsNotFoundWhenNegativeIdResolvesToNoUser + Description: Checks behavior when id is negative (e.g., "-1") and the repository returns null, leading to the not-found message. + +Execution: + Arrange: Mock UserAccRepository.findById(-1) to return null. + Act: Invoke updateUserById with id "-1". + Assert: Assert returned value is "User não encontrado". Verify no setter or save calls. + +Validation: + Ensures negative ids that do not map to a user are treated as not found. + +Scenario 10: Negative id but user exists still updates + +Details: + TestName: updatesSuccessfullyEvenWithNegativeIdIfUserExists + Description: Shows that the method does not validate id sign; if the repository returns a user for a negative id, it proceeds to update and save. + +Execution: + Arrange: Mock UserAccRepository.findById(-7) to return a non-null user. + Act: Invoke updateUserById with id "-7" and valid fields. + Assert: Assert "Usuário Salvo" is returned and setters/save invoked once. + +Validation: + Highlights that business rules for id sign are not enforced within this method; behavior depends solely on repository result. + +Scenario 11: Null email is accepted and saved + +Details: + TestName: acceptsNullEmailAndSavesWhenUserExists + Description: Validates that email can be null; the method sets null on the entity and still saves successfully. + +Execution: + Arrange: Mock UserAccRepository.findById to return a non-null user. + Act: Invoke updateUserById with email as null, and valid id, password, username. + Assert: Assert "Usuário Salvo" is returned. Verify setEmail(null) invoked, along with setPassword and setUsername, then save called once. + +Validation: + Confirms lack of input validation for email and that null values are persisted as provided. + +Scenario 12: Empty username is accepted and saved + +Details: + TestName: acceptsEmptyUsernameAndSavesWhenUserExists + Description: Ensures that an empty string for username is set and saved without validation. + +Execution: + Arrange: Mock repository to return a user for the parsed id. + Act: Call updateUserById with username as "" and valid id, email, password. + Assert: Assert "Usuário Salvo". Verify setUsername("") called and save executed. + +Validation: + Demonstrates that the method does not enforce non-empty username constraints. + +Scenario 13: Empty password is accepted and saved + +Details: + TestName: acceptsEmptyPasswordAndSavesWhenUserExists + Description: Ensures that an empty password is set and saved, indicating no validation or hashing in this method. + +Execution: + Arrange: Mock repository to return a user. + Act: Invoke updateUserById with password as "" and valid id, email, username. + Assert: Assert "Usuário Salvo". Verify setPassword("") and save called once. + +Validation: + Highlights potential security implications: passwords are accepted verbatim; method does not hash or validate. + +Scenario 14: Very long strings are persisted as-is + +Details: + TestName: persistsVeryLongFieldsWithoutValidation + Description: Confirms the method can handle very long email, password, and username strings and still save successfully. + +Execution: + Arrange: Mock repository to return a user. Prepare very long strings for email/password/username (within memory limits). + Act: Invoke updateUserById with those long strings. + Assert: Assert "Usuário Salvo". Verify setters called with the exact long values and save invoked. + +Validation: + Ensures the method does not truncate or validate string lengths and persists data as provided. + +Scenario 15: Unicode characters are accepted and saved + +Details: + TestName: acceptsUnicodeCharactersInFields + Description: Verifies that fields containing Unicode (e.g., "José", "пароль", "用户@example.com") are set and saved without alteration. + +Execution: + Arrange: Mock repository to return a user. + Act: Invoke updateUserById with Unicode-containing email, password, and username. + Assert: Assert "Usuário Salvo". Verify setters called with the provided Unicode values and save invoked once. + +Validation: + Confirms internationalization tolerance in raw string handling for updates. + +Scenario 16: Special characters and quotes are preserved + +Details: + TestName: preservesSpecialCharactersAndQuotesInFields + Description: Ensures that values containing quotes, symbols, and escape characters (e.g., "name\"with\"quotes", "pass!@#$%^&*()", "email+tag@example.com") are set and saved unchanged. + +Execution: + Arrange: Mock repository to return a user. + Act: Invoke updateUserById with fields containing special characters. + Assert: Assert "Usuário Salvo". Verify setters called with exact values and save invoked. + +Validation: + Confirms that the method performs no sanitization or normalization and persists inputs verbatim. + +Scenario 17: Repository findById throws an exception + +Details: + TestName: propagatesExceptionWhenFindByIdFails + Description: Validates that if UserAccRepository.findById throws a runtime exception (e.g., database error), the method propagates the exception without returning a message. + +Execution: + Arrange: Configure UserAccRepository.findById to throw a RuntimeException. + Act: Invoke updateUserById with a valid id and other fields. + Assert: Expect the same RuntimeException to be thrown. Verify no calls to setters or save occurred. Verify no interactions with UserInfoRepository and LogRepository. + +Validation: + Confirms absence of error handling; exceptions from repository are not swallowed. + +Scenario 18: Repository save throws an exception + +Details: + TestName: propagatesExceptionWhenSaveFailsAfterUpdates + Description: Ensures that if UserAccRepository.save throws a runtime exception after setters have been called, the exception is propagated and no success message is returned. + +Execution: + Arrange: Mock findById to return a user and configure save to throw a RuntimeException. + Act: Invoke updateUserById with valid inputs. + Assert: Expect the RuntimeException. Verify setters were called before the exception, and save was attempted once. + +Validation: + Confirms that persistence errors are surfaced to the caller and that updates occur prior to the save attempt. + +Scenario 19: Verifies exact success message including diacritics + +Details: + TestName: returnsExactSuccessMessageWithDiacritics + Description: Focuses on verifying the exact returned string "Usuário Salvo" including correct capitalization and diacritics when update succeeds. + +Execution: + Arrange: Mock findById to return a user. + Act: Invoke updateUserById with valid inputs. + Assert: Assert that the returned value is exactly "Usuário Salvo" (no extra spaces or different accents). + +Validation: + Ensures clients depending on exact response text will behave correctly. + +Scenario 20: Verifies exact not-found message text + +Details: + TestName: returnsExactNotFoundMessage + Description: Validates that the method returns exactly "User não encontrado" when the repository returns null. + +Execution: + Arrange: Mock findById to return null. + Act: Invoke updateUserById with a valid numeric id string. + Assert: Assert that the returned value is exactly "User não encontrado". + +Validation: + Confirms response text consistency for not-found scenarios. + +Scenario 21: Ensures parsed id passed correctly to repository + +Details: + TestName: passesParsedIntegerIdToRepository + Description: Checks that the integer value resulting from parsing the id string is used in the repository call (e.g., "00123" -> 123). + +Execution: + Arrange: Prepare a spy or verification on UserAccRepository to capture the id argument. Mock findById(123) to return a user. + Act: Invoke updateUserById with id "00123". + Assert: Verify that findById was called with 123 and not the original string. Assert "Usuário Salvo" is returned. + +Validation: + Confirms that id parsing is applied as intended and correct numeric id is used for lookup. + +Scenario 22: Ensures setters are called before save + +Details: + TestName: callsSettersBeforeSave + Description: Verifies that setEmail, setPassword, and setUsername are invoked on the entity prior to calling UserAccRepository.save. + +Execution: + Arrange: Use a spy for User_Credentials returned by findById to verify call order; mock repository to return this spy. + Act: Invoke updateUserById with valid inputs. + Assert: Verify that the three setter methods are called with the provided values and that save is called after these method calls. + +Validation: + Ensures the entity state is updated before persistence, aligning with expected update semantics. + +Scenario 23: Whitespace-only fields are accepted and saved + +Details: + TestName: acceptsWhitespaceOnlyFields + Description: Ensures that strings containing only whitespace for email/username/password are accepted, set, and saved. + +Execution: + Arrange: Mock repository to return a user. + Act: Invoke updateUserById with fields like " " for email/username/password. + Assert: Assert "Usuário Salvo". Verify setters called with whitespace-only strings and save invoked. + +Validation: + Confirms the absence of input normalization or trimming in the update path. + +Scenario 24: No interaction with unused repositories on any path + +Details: + TestName: noInteractionWithUserInfoAndLogRepositories + Description: Validates that UserInfoRepository and LogRepository are not used by updateUserById in either success, not-found, or exception scenarios. + +Execution: + Arrange: Prepare mocks for UserInfoRepository and LogRepository. Create three sub-arrangements: (a) success path with findById returning user, (b) not-found with findById returning null, (c) error path with findById throwing an exception. + Act: Invoke updateUserById under each sub-arrangement. + Assert: In all cases, verify zero interactions with UserInfoRepository and LogRepository. + +Validation: + Ensures method cohesion and prevents unintended side effects in unrelated components. + +Scenario 25: Zero id path based on repository outcome + +Details: + TestName: handlesZeroIdDependingOnRepositoryResult + Description: Confirms that id "0" is parsed and behavior depends solely on repository return: updates if user exists; not found otherwise. + +Execution: + Arrange: Two sub-cases: (a) Mock findById(0) to return a user, (b) Mock findById(0) to return null. + Act: Invoke updateUserById with id "0" for both sub-cases. + Assert: (a) Expect "Usuário Salvo" with setters/save verified; (b) Expect "User não encontrado" with no setters/save. + +Validation: + Demonstrates that zero is treated as a valid id and the outcome is repository-dependent. + +*/ + +// ********RoostGPT******** + +package com.medeiros.SPRINGProject.Controllers; + +import com.medeiros.SPRINGProject.Controllers.UserAccountController; +import com.medeiros.SPRINGProject.Models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Optional; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import org.junit.jupiter.api.*; + +@ExtendWith(MockitoExtension.class) +public class UserAccountControllerUpdateUserByIdTest { + + @Mock + private UserAccRepository UserAccRepo; + + @Mock + private UserInfoRepository UserInfoRepo; + + @Mock + private LogRepository Log; + + @InjectMocks + private UserAccountController controller; + + @Test + @Tag("valid") + public void testUpdateExistingUserSucceedsAndSaves() { + String id = "123"; + String email = "user@example.com"; + String password = "securePass"; + String username = "user123"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(123)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user, times(1)).setEmail(email); + verify(user, times(1)).setPassword(password); + verify(user, times(1)).setUsername(username); + verify(UserAccRepo, times(1)).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testReturnsNotFoundMessageWhenUserDoesNotExist() { + String id = "456"; + String email = "noone@example.com"; + String password = "pass"; + String username = "nouser"; + when(UserAccRepo.findById(456)).thenReturn(null); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "User não encontrado", (String) result); + verify(UserAccRepo, times(1)).findById(456); + verify(UserAccRepo, never()).save(any()); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testThrowsNumberFormatExceptionWhenIdIsNonNumeric() { + String id = "abc"; + String email = "user@example.com"; + String password = "pass"; + String username = "user"; + assertThrows(NumberFormatException.class, () -> controller.updateUserById(id, email, password, username)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testThrowsNullPointerExceptionWhenIdIsNull() { + String id = null; + String email = "user@example.com"; + String password = "pass"; + String username = "user"; + assertThrows(NullPointerException.class, () -> controller.updateUserById(id, email, password, username)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testThrowsNumberFormatExceptionWhenIdOutOfIntRange() { + String id = "999999999999"; + String email = "user@example.com"; + String password = "pass"; + String username = "user"; + assertThrows(NumberFormatException.class, () -> controller.updateUserById(id, email, password, username)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testThrowsNumberFormatExceptionWhenIdHasSurroundingWhitespace() { + String id = " 123 "; + String email = "user@example.com"; + String password = "pass"; + String username = "user"; + assertThrows(NumberFormatException.class, () -> controller.updateUserById(id, email, password, username)); + verifyNoInteractions(UserAccRepo, UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testUpdatesSuccessfullyWhenIdHasLeadingZeros() { + String id = "000123"; + String email = "user@example.com"; + String password = "pass"; + String username = "user"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(123)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testUpdatesSuccessfullyWhenIdHasLeadingPlusSign() { + String id = "+42"; + String email = "user42@example.com"; + String password = "pass42"; + String username = "user42"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(42)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testReturnsNotFoundWhenNegativeIdResolvesToNoUser() { + String id = "-1"; + String email = "neg@example.com"; + String password = "neg"; + String username = "neg"; + when(UserAccRepo.findById(-1)).thenReturn(null); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "User não encontrado", (String) result); + verify(UserAccRepo, times(1)).findById(-1); + verify(UserAccRepo, never()).save(any()); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testUpdatesSuccessfullyEvenWithNegativeIdIfUserExists() { + String id = "-7"; + String email = "neg7@example.com"; + String password = "neg7"; + String username = "neg7"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(-7)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testAcceptsNullEmailAndSavesWhenUserExists() { + String id = "10"; + String email = null; + String password = "pwd"; + String username = "uname"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(10)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(null); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testAcceptsEmptyUsernameAndSavesWhenUserExists() { + String id = "11"; + String email = "e@x.com"; + String password = "pwd"; + String username = ""; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(11)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testAcceptsEmptyPasswordAndSavesWhenUserExists() { + String id = "12"; + String email = "e@x.com"; + String password = ""; + String username = "uname"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(12)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testPersistsVeryLongFieldsWithoutValidation() { + String id = "13"; + // TODO: Adjust lengths as needed for performance constraints in your environment + StringBuilder sbEmail = new StringBuilder(); + StringBuilder sbPassword = new StringBuilder(); + StringBuilder sbUsername = new StringBuilder(); + for (int i = 0; i < 2000; i++) { + sbEmail.append('a'); + sbPassword.append('b'); + sbUsername.append('c'); + } + sbEmail.append("@example.com"); + String email = sbEmail.toString(); + String password = sbPassword.toString(); + String username = sbUsername.toString(); + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(13)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testAcceptsUnicodeCharactersInFields() { + String id = "14"; + String email = "用户@example.com"; + String password = "пароль"; + String username = "José"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(14)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testPreservesSpecialCharactersAndQuotesInFields() { + String id = "15"; + String email = "email+tag@example.com"; + String password = "pass!@#$%^&*()"; + String username = "name\"with\"quotes"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(15)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testPropagatesExceptionWhenFindByIdFails() { + String id = "16"; + String email = "e@x.com"; + String password = "pwd"; + String username = "uname"; + when(UserAccRepo.findById(16)).thenThrow(new RuntimeException("DB error")); + RuntimeException ex = assertThrows(RuntimeException.class, + () -> controller.updateUserById(id, email, password, username)); + assertNotNull((Object) ex); + verify(UserAccRepo, times(1)).findById(16); + verify(UserAccRepo, never()).save(any()); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testPropagatesExceptionWhenSaveFailsAfterUpdates() { + String id = "17"; + String email = "e@x.com"; + String password = "pwd"; + String username = "uname"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(17)).thenReturn(user); + doThrow(new RuntimeException("Save error")).when(UserAccRepo).save(user); + assertThrows(RuntimeException.class, () -> controller.updateUserById(id, email, password, username)); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo, times(1)).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testReturnsExactSuccessMessageWithDiacritics() { + String id = "18"; + String email = "exact@example.com"; + String password = "pass"; + String username = "exact"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(18)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("invalid") + public void testReturnsExactNotFoundMessage() { + String id = "19"; + String email = "x@example.com"; + String password = "pass"; + String username = "x"; + when(UserAccRepo.findById(19)).thenReturn(null); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "User não encontrado", (String) result); + verify(UserAccRepo, times(1)).findById(19); + verify(UserAccRepo, never()).save(any()); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testPassesParsedIntegerIdToRepository() { + String id = "00123"; + String email = "p@example.com"; + String password = "pass"; + String username = "user"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(123)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class); + verify(UserAccRepo).findById(captor.capture()); + assertEquals((int) 123, (int) captor.getValue()); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testCallsSettersBeforeSave() { + String id = "20"; + String email = "order@example.com"; + String password = "orderPwd"; + String username = "orderUser"; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(20)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + InOrder inOrder = inOrder(user, UserAccRepo); + inOrder.verify(user).setEmail(email); + inOrder.verify(user).setPassword(password); + inOrder.verify(user).setUsername(username); + inOrder.verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("valid") + public void testAcceptsWhitespaceOnlyFields() { + String id = "21"; + String email = " "; + String password = " "; + String username = " "; + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(21)).thenReturn(user); + String result = controller.updateUserById(id, email, password, username); + assertEquals((String) "Usuário Salvo", (String) result); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo).save(user); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("integration") + public void testNoInteractionWithUserInfoAndLogRepositories() { + // Success path + User_Credentials userSuccess = mock(User_Credentials.class); + when(UserAccRepo.findById(30)).thenReturn(userSuccess); + String res1 = controller.updateUserById("30", "a@a.com", "p", "u"); + assertEquals((String) "Usuário Salvo", (String) res1); + // Not-found path + when(UserAccRepo.findById(31)).thenReturn(null); + String res2 = controller.updateUserById("31", "b@b.com", "p", "u"); + assertEquals((String) "User não encontrado", (String) res2); + // Exception path + when(UserAccRepo.findById(32)).thenThrow(new RuntimeException("error")); + assertThrows(RuntimeException.class, () -> controller.updateUserById("32", "c@c.com", "p", "u")); + verifyNoInteractions(UserInfoRepo, Log); + } + + @Test + @Tag("boundary") + public void testHandlesZeroIdDependingOnRepositoryResult() { + String idZero = "0"; + String email = "zero@example.com"; + String password = "zero"; + String username = "zero"; + // Sub-case (a): user exists + User_Credentials user = mock(User_Credentials.class); + when(UserAccRepo.findById(0)).thenReturn(user); + String resultA = controller.updateUserById(idZero, email, password, username); + assertEquals((String) "Usuário Salvo", (String) resultA); + verify(user).setEmail(email); + verify(user).setPassword(password); + verify(user).setUsername(username); + verify(UserAccRepo, times(1)).save(user); + // Reset interactions for sub-case (b) + reset(UserAccRepo, user); + when(UserAccRepo.findById(0)).thenReturn(null); + String resultB = controller.updateUserById(idZero, email, password, username); + assertEquals((String) "User não encontrado", (String) resultB); + verify(UserAccRepo, times(1)).findById(0); + verify(UserAccRepo, never()).save(any()); + verifyNoInteractions(UserInfoRepo, Log); + } + +} \ No newline at end of file