diff --git a/build.gradle b/build.gradle
index 3e77eaa..ba5004f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,8 +10,20 @@ repositories {
}
dependencies {
+ testImplementation 'org.mockito:mockito-core:5.14.2'
+ testImplementation 'org.mockito:mockito-junit-jupiter:5.14.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.4'
}
test {
+ systemProperty "file.encoding", "utf-8"
useJUnitPlatform()
-}
\ No newline at end of file
+}
+
+compileJava.options.encoding = 'UTF-8'
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 41dfb87..b6dbf84 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Tue Feb 11 23:22:06 MSK 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/java/com/walking/lesson125_unit_testing/Main.java b/src/main/java/com/walking/lesson125_unit_testing/Main.java
index e6fae03..98e8870 100644
--- a/src/main/java/com/walking/lesson125_unit_testing/Main.java
+++ b/src/main/java/com/walking/lesson125_unit_testing/Main.java
@@ -1,9 +1,5 @@
package com.walking.lesson125_unit_testing;
-
-import com.walking.lesson125_unit_testing.exception.RegexValidationException;
-import com.walking.lesson125_unit_testing.model.FullName;
-
/**
* На базе вашего решения
* задачи из урока 125
@@ -11,67 +7,6 @@
* вашем предыдущем решении.
*/
public class Main {
-
- public static final String FULL_NAME_REGEX = "^[А-Я][А-Яа-я-]* [А-Я][а-я]* [А-Я][а-я]+$";
- public static final String DOUBLE_SURNAME_REGEX = "[А-Я][а-я]*-[А-Я][а-я]*";
- public static final String NAME_REGEX = "[А-Я][а-я]*";
- public static final String PATRONYMIC_REGEX = "[А-Я][а-я]+";
-
public static void main(String[] args) {
- System.out.println(parseName("Иванов Иван Иванович"));
- System.out.println(parseName("Иванов-Иванов Иван Иванович"));
- System.out.println(parseName("Иванов-Иванов И Иванович"));
- System.out.println(parseName("И-Иванов И Иванович"));
- System.out.println(parseName("Иванов иван Иванович"));
-// Все равно упадет на 30й строке.
-// System.out.println(parseName("И-иванов И Иванович"));
-// System.out.println(parseName("Иванов Иван иванович"));
-// System.out.println(parseName("ИваНов Иван Иванович"));
-// System.out.println(parseName("Ivanov Ivan"));
- }
-
- private static FullName parseName(String nameString) {
- if (!nameString.matches(FULL_NAME_REGEX)) {
- throw new RegexValidationException(nameString, FULL_NAME_REGEX);
- }
-
- FullName fullName = new FullName();
- String[] splitNameString = nameString.split(" ");
-
- String surname = splitNameString[0];
- validateSurname(surname);
- fullName.setSurname(surname);
-
- String name = splitNameString[1];
- validateName(name);
- fullName.setName(name);
-
- String patronymic = splitNameString[2];
- validatePatronymic(patronymic);
- fullName.setPatronymic(patronymic);
-
- return fullName;
- }
-
- private static void validateSurname(String surname) {
- if (surname.contains("-")) {
- if (!surname.matches(DOUBLE_SURNAME_REGEX)) {
- throw new RegexValidationException(surname, DOUBLE_SURNAME_REGEX);
- }
- } else {
- validateName(surname);
- }
- }
-
- private static void validateName(String name) {
- if (!name.matches(NAME_REGEX)) {
- throw new RegexValidationException(name, NAME_REGEX);
- }
- }
-
- private static void validatePatronymic(String name) {
- if (!name.matches(PATRONYMIC_REGEX)) {
- throw new RegexValidationException(name, PATRONYMIC_REGEX);
- }
}
}
diff --git a/src/main/java/com/walking/lesson125_unit_testing/model/FullName.java b/src/main/java/com/walking/lesson125_unit_testing/model/FullName.java
index 86c5f1c..65bc32b 100644
--- a/src/main/java/com/walking/lesson125_unit_testing/model/FullName.java
+++ b/src/main/java/com/walking/lesson125_unit_testing/model/FullName.java
@@ -1,5 +1,7 @@
package com.walking.lesson125_unit_testing.model;
+import java.util.Objects;
+
public class FullName {
private String name;
private String surname;
@@ -42,4 +44,30 @@ public void setPatronymic(String patronymic) {
public String toString() {
return "%s %s %s".formatted(surname, name, patronymic);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ FullName fullName = (FullName) o;
+
+ return Objects.equals(name, fullName.name) && Objects.equals(surname, fullName.surname)
+ && Objects.equals(patronymic, fullName.patronymic);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hashCode(name);
+
+ result = 31 * result + Objects.hashCode(surname);
+ result = 31 * result + Objects.hashCode(patronymic);
+
+ return result;
+ }
}
diff --git a/src/main/java/com/walking/lesson125_unit_testing/service/FullNameParsingService.java b/src/main/java/com/walking/lesson125_unit_testing/service/FullNameParsingService.java
new file mode 100644
index 0000000..b94c83e
--- /dev/null
+++ b/src/main/java/com/walking/lesson125_unit_testing/service/FullNameParsingService.java
@@ -0,0 +1,32 @@
+package com.walking.lesson125_unit_testing.service;
+
+import com.walking.lesson125_unit_testing.model.FullName;
+
+public class FullNameParsingService {
+ private final FullNameValidationService fullNameValidationService;
+
+ public FullNameParsingService(FullNameValidationService fullNameValidationService) {
+ this.fullNameValidationService = fullNameValidationService;
+ }
+
+ public FullName parseFullName(String nameString) {
+ if (nameString == null) {
+ throw new IllegalArgumentException("Unable parse null");
+ }
+
+ fullNameValidationService.validateFullName(nameString);
+
+ String[] splitNameString = nameString.split(" ");
+
+ String surname = splitNameString[0];
+ fullNameValidationService.validateSurname(surname);
+
+ String name = splitNameString[1];
+ fullNameValidationService.validateName(name);
+
+ String patronymic = splitNameString[2];
+ fullNameValidationService.validatePatronymic(patronymic);
+
+ return new FullName(name, surname, patronymic);
+ }
+}
diff --git a/src/main/java/com/walking/lesson125_unit_testing/service/FullNameValidationService.java b/src/main/java/com/walking/lesson125_unit_testing/service/FullNameValidationService.java
new file mode 100644
index 0000000..0d003a3
--- /dev/null
+++ b/src/main/java/com/walking/lesson125_unit_testing/service/FullNameValidationService.java
@@ -0,0 +1,38 @@
+package com.walking.lesson125_unit_testing.service;
+
+import com.walking.lesson125_unit_testing.exception.RegexValidationException;
+
+public class FullNameValidationService {
+ private static final String FULL_NAME_REGEX = "^[А-Я][А-Яа-я-]* [А-Я][а-я]* [А-Я][а-я]+$";
+ private static final String DOUBLE_SURNAME_REGEX = "[А-Я][а-я]*-[А-Я][а-я]*";
+ private static final String NAME_REGEX = "[А-Я][а-я]*";
+ private static final String PATRONYMIC_REGEX = "[А-Я][а-я]+";
+
+ public void validateFullName(String nameString) {
+ if (!nameString.matches(FULL_NAME_REGEX)) {
+ throw new RegexValidationException(nameString, FULL_NAME_REGEX);
+ }
+ }
+
+ public void validateSurname(String surname) {
+ if (surname.contains("-")) {
+ if (!surname.matches(DOUBLE_SURNAME_REGEX)) {
+ throw new RegexValidationException(surname, DOUBLE_SURNAME_REGEX);
+ }
+ } else {
+ validateName(surname);
+ }
+ }
+
+ public void validateName(String name) {
+ if (!name.matches(NAME_REGEX)) {
+ throw new RegexValidationException(name, NAME_REGEX);
+ }
+ }
+
+ public void validatePatronymic(String name) {
+ if (!name.matches(PATRONYMIC_REGEX)) {
+ throw new RegexValidationException(name, PATRONYMIC_REGEX);
+ }
+ }
+}
diff --git a/src/test/java/com/walking/lesson125_unit_testing/service/FullNameParsingServiceTest.java b/src/test/java/com/walking/lesson125_unit_testing/service/FullNameParsingServiceTest.java
new file mode 100644
index 0000000..03958bb
--- /dev/null
+++ b/src/test/java/com/walking/lesson125_unit_testing/service/FullNameParsingServiceTest.java
@@ -0,0 +1,72 @@
+package com.walking.lesson125_unit_testing.service;
+
+import com.walking.lesson125_unit_testing.exception.RegexValidationException;
+import com.walking.lesson125_unit_testing.model.FullName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.function.Executable;
+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.*;
+
+@ExtendWith(MockitoExtension.class)
+class FullNameParsingServiceTest {
+ @InjectMocks
+ private FullNameParsingService fullNameParsingService;
+
+ @Mock
+ private FullNameValidationService fullNameValidationService;
+
+ @Test
+ void parseFullName_success() {
+// given
+ FullName expected = new FullName("Иван", "Иванов", "Иванович");
+
+// when
+ FullName result = fullNameParsingService.parseFullName("Иванов Иван Иванович");
+
+// then
+ assertEquals(expected, result);
+
+ verify(fullNameValidationService).validateFullName(anyString());
+ verify(fullNameValidationService).validateSurname(anyString());
+ verify(fullNameValidationService).validateName(anyString());
+ verify(fullNameValidationService).validatePatronymic(anyString());
+ }
+
+ @Test
+ void parseFullName_failed_with_invalidFullName() {
+// given
+ doThrow(RegexValidationException.class).when(fullNameValidationService)
+ .validateFullName(anyString());
+
+// when
+ Executable actual = () -> fullNameParsingService.parseFullName(anyString());
+
+// then
+ assertThrows(RegexValidationException.class, actual);
+
+ verify(fullNameValidationService).validateFullName(anyString());
+
+ verify(fullNameValidationService, never()).validateSurname(anyString());
+ verify(fullNameValidationService, never()).validateName(anyString());
+ verify(fullNameValidationService, never()).validatePatronymic(anyString());
+ }
+
+ @Test
+ void parseFullName_failed_with_null() {
+// when
+ Executable actual = () -> fullNameParsingService.parseFullName(null);
+
+// then
+ assertThrows(IllegalArgumentException.class, actual);
+
+ verify(fullNameValidationService, never()).validateFullName(anyString());
+ verify(fullNameValidationService, never()).validateSurname(anyString());
+ verify(fullNameValidationService, never()).validateName(anyString());
+ verify(fullNameValidationService, never()).validatePatronymic(anyString());
+ }
+}
diff --git a/src/test/java/com/walking/lesson125_unit_testing/service/FullNameValidationServiceTest.java b/src/test/java/com/walking/lesson125_unit_testing/service/FullNameValidationServiceTest.java
new file mode 100644
index 0000000..0cd1eb6
--- /dev/null
+++ b/src/test/java/com/walking/lesson125_unit_testing/service/FullNameValidationServiceTest.java
@@ -0,0 +1,166 @@
+package com.walking.lesson125_unit_testing.service;
+
+import com.walking.lesson125_unit_testing.exception.RegexValidationException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class FullNameValidationServiceTest {
+ private final FullNameValidationService fullNameValidationService =
+ new FullNameValidationService();
+
+ @ParameterizedTest
+ @MethodSource("sourceValidFullName")
+ void validateFullName_success(String validFullName) {
+// when
+ Executable actual = () -> fullNameValidationService.validateFullName(validFullName);
+
+// then
+ assertDoesNotThrow(actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceInvalidFullNames")
+ void validateFullName_failed_with_invalidFullName(String invalidFullName) {
+// when
+ Executable actual = () -> fullNameValidationService.validateFullName(invalidFullName);
+
+// then
+ assertThrows(RegexValidationException.class, actual);
+ }
+
+ @Test
+ void validateFullName_failed_with_null() {
+// when
+ Executable actual = () -> fullNameValidationService.validateFullName(null);
+
+// then
+ assertThrows(NullPointerException.class, actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceValidNames")
+ void validateName_success(String validName) {
+// when
+ Executable actual = () -> fullNameValidationService.validateName(validName);
+
+// then
+ assertDoesNotThrow(actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceInvalidNames")
+ void validateName_failed_with_invalidName(String invalidName) {
+// when
+ Executable actual = () -> fullNameValidationService.validateName(invalidName);
+
+// then
+ assertThrows(RegexValidationException.class, actual);
+ }
+
+ @Test
+ void validateName_failed_with_null() {
+// when
+ Executable actual = () -> fullNameValidationService.validateName(null);
+
+// then
+ assertThrows(NullPointerException.class, actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceValidDoubleSurnames")
+ void validateSurName_success(String validSurname) {
+// when
+ Executable actual = () -> fullNameValidationService.validateSurname(validSurname);
+
+// then
+ assertDoesNotThrow(actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceInvalidDoubleSurnames")
+ void validateSurname_failed_with_invalidSurname(String invalidSurname) {
+// when
+ Executable actual = () -> fullNameValidationService.validateSurname(invalidSurname);
+
+// then
+ assertThrows(RegexValidationException.class, actual);
+ }
+
+ @Test
+ void validateSurname_failed_with_null() {
+// when
+ Executable actual = () -> fullNameValidationService.validateSurname(null);
+
+// then
+ assertThrows(NullPointerException.class, actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceValidPatronymics")
+ void validatePatronymic_success(String validPatronymic) {
+// when
+ Executable actual = () -> fullNameValidationService.validatePatronymic(validPatronymic);
+
+// then
+ assertDoesNotThrow(actual);
+ }
+
+ @ParameterizedTest
+ @MethodSource("sourceInvalidPatronymics")
+ void validatePatronymic_failed_with_invalidPatronymic(String invalidPatronymic) {
+// when
+ Executable actual = () -> fullNameValidationService.validatePatronymic(invalidPatronymic);
+
+// then
+ assertThrows(RegexValidationException.class, actual);
+ }
+
+ @Test
+ void validatePatronymic_failed_with_null() {
+// when
+ Executable actual = () -> fullNameValidationService.validatePatronymic(null);
+
+// then
+ assertThrows(NullPointerException.class, actual);
+ }
+
+ static List sourceValidFullName() {
+ return List.of("Иванов Иван Иванович", "Иванов-Иванов Иван Иванович",
+ "Иванов-Иванов И Иванович", "И-Иванов И Иванович");
+ }
+
+ static List sourceInvalidFullNames() {
+ return List.of("", "иванов Иван Иванович", "Иванов иван Иванович", "Иванов Иван иванович",
+ "Иванов Иван", "Ivanov Ivan");
+ }
+
+ static List sourceValidNames() {
+ return List.of("Иван");
+ }
+
+ static List sourceInvalidNames() {
+ return List.of("", "иван", "Ivan", "Иван-иван");
+ }
+
+ static List sourceValidDoubleSurnames() {
+ return List.of("Иванов-Иванов", "И-Иванов");
+ }
+
+ static List sourceInvalidDoubleSurnames() {
+ return List.of("", "И-иванов", "иванов-И", "Иванов-И-Иванов", "Ivanov-I");
+ }
+
+ static List sourceValidPatronymics() {
+ return List.of("Иванович");
+ }
+
+ static List sourceInvalidPatronymics() {
+ return List.of("", "иванович", "Ivanovich", "И", "Иванович-Степанович");
+ }
+}