From 7866275b10ac98708fac1131c1a490fae88b1cf8 Mon Sep 17 00:00:00 2001
From: mperor <mpietryga93@gmail.com>
Date: Tue, 1 Apr 2025 14:24:28 +0200
Subject: [PATCH] Implement validator using Visitor pattern and move Customer
 to a dedicated package

---
 .../behavioral/visitor/CorporateCustomer.java |  4 ---
 .../pattern/behavioral/visitor/Letter.java    |  4 ---
 .../behavioral/visitor/PremiumCustomer.java   |  4 ---
 .../behavioral/visitor/RegularCustomer.java   |  4 ---
 .../visitor/customer/CorporateCustomer.java   |  4 +++
 .../visitor/{ => customer}/Customer.java      |  2 +-
 .../{ => customer}/CustomerVisitor.java       |  2 +-
 .../visitor/{ => customer}/DiscountLevel.java |  2 +-
 .../{ => customer}/DiscountProvider.java      |  2 +-
 .../InvitationLetterGenerator.java            |  2 +-
 .../behavioral/visitor/customer/Letter.java   |  4 +++
 .../visitor/customer/PremiumCustomer.java     |  4 +++
 .../visitor/customer/RegularCustomer.java     |  4 +++
 ...AggregatingValidationExceptionHandler.java | 22 ++++++++++++++
 .../behavioral/visitor/validator/Email.java   | 29 +++++++++++++++++++
 .../visitor/validator/Password.java           | 25 ++++++++++++++++
 .../ThrowingValidationExceptionHandler.java   |  9 ++++++
 .../validator/ValidationException.java        |  4 +++
 .../validator/ValidationExceptionHandler.java |  6 ++++
 .../visitor/validator/Validator.java          |  6 ++++
 .../{ => customer}/CustomerVisitorTest.java   |  2 +-
 .../validator/ValidatorVisitorTest.java       | 26 +++++++++++++++++
 22 files changed, 149 insertions(+), 22 deletions(-)
 delete mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CorporateCustomer.java
 delete mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Letter.java
 delete mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/PremiumCustomer.java
 delete mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/RegularCustomer.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CorporateCustomer.java
 rename DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/Customer.java (73%)
 rename DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/CustomerVisitor.java (51%)
 rename DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/DiscountLevel.java (71%)
 rename DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/DiscountProvider.java (86%)
 rename DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/InvitationLetterGenerator.java (88%)
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Letter.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/PremiumCustomer.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/RegularCustomer.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/AggregatingValidationExceptionHandler.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Email.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Password.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ThrowingValidationExceptionHandler.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationException.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationExceptionHandler.java
 create mode 100644 DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Validator.java
 rename DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/{ => customer}/CustomerVisitorTest.java (93%)
 create mode 100644 DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidatorVisitorTest.java

diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CorporateCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CorporateCustomer.java
deleted file mode 100644
index 19fe58e..0000000
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CorporateCustomer.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
-
-record CorporateCustomer() implements Customer {
-}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Letter.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Letter.java
deleted file mode 100644
index f334633..0000000
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Letter.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
-
-record Letter(String content) {
-}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/PremiumCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/PremiumCustomer.java
deleted file mode 100644
index 082024d..0000000
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/PremiumCustomer.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
-
-record PremiumCustomer() implements Customer {
-}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/RegularCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/RegularCustomer.java
deleted file mode 100644
index c1e00c7..0000000
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/RegularCustomer.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
-
-record RegularCustomer() implements Customer {
-}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CorporateCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CorporateCustomer.java
new file mode 100644
index 0000000..a96c2c9
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CorporateCustomer.java
@@ -0,0 +1,4 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
+
+record CorporateCustomer() implements Customer {
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Customer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Customer.java
similarity index 73%
rename from DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Customer.java
rename to DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Customer.java
index 9af89f3..0074729 100644
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/Customer.java
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Customer.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 public sealed interface Customer permits CorporateCustomer, RegularCustomer, PremiumCustomer {
 
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitor.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitor.java
similarity index 51%
rename from DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitor.java
rename to DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitor.java
index 7e2844f..f9c866d 100644
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitor.java
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitor.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 public interface CustomerVisitor<T> {
 
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountLevel.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountLevel.java
similarity index 71%
rename from DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountLevel.java
rename to DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountLevel.java
index 27bdd1d..b0bc5f6 100644
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountLevel.java
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountLevel.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 enum DiscountLevel {
     BRONZE(10),
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountProvider.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountProvider.java
similarity index 86%
rename from DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountProvider.java
rename to DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountProvider.java
index b3d8546..41cc9f3 100644
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/DiscountProvider.java
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/DiscountProvider.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 public class DiscountProvider implements CustomerVisitor<DiscountLevel> {
 
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/InvitationLetterGenerator.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/InvitationLetterGenerator.java
similarity index 88%
rename from DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/InvitationLetterGenerator.java
rename to DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/InvitationLetterGenerator.java
index 1e15749..cb7091d 100644
--- a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/InvitationLetterGenerator.java
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/InvitationLetterGenerator.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 public class InvitationLetterGenerator implements CustomerVisitor<Letter> {
 
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Letter.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Letter.java
new file mode 100644
index 0000000..7261aba
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/Letter.java
@@ -0,0 +1,4 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
+
+record Letter(String content) {
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/PremiumCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/PremiumCustomer.java
new file mode 100644
index 0000000..af644f9
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/PremiumCustomer.java
@@ -0,0 +1,4 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
+
+record PremiumCustomer() implements Customer {
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/RegularCustomer.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/RegularCustomer.java
new file mode 100644
index 0000000..794abf0
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/RegularCustomer.java
@@ -0,0 +1,4 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
+
+record RegularCustomer() implements Customer {
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/AggregatingValidationExceptionHandler.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/AggregatingValidationExceptionHandler.java
new file mode 100644
index 0000000..fb200ab
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/AggregatingValidationExceptionHandler.java
@@ -0,0 +1,22 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class AggregatingValidationExceptionHandler implements ValidationExceptionHandler {
+
+    private List<ValidationException> errors = new ArrayList<>();
+
+    @Override
+    public void handle(ValidationException exception) {
+        errors.add(exception);
+    }
+
+    boolean hasErrors() {
+        return !errors.isEmpty();
+    }
+
+    public List<ValidationException> getErrors() {
+        return List.copyOf(errors);
+    }
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Email.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Email.java
new file mode 100644
index 0000000..a1cdffc
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Email.java
@@ -0,0 +1,29 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+import java.util.regex.Pattern;
+
+record Email(String address) {
+
+    public Email {
+        test(address, new ThrowingValidationExceptionHandler());
+    }
+
+    public static void test(String address, ValidationExceptionHandler handler) {
+        new EmailValidator().validate(address, handler);
+    }
+
+    static class EmailValidator implements Validator<String> {
+
+        public static final Pattern FORMAT_PATTERN = Pattern.compile("^[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+$");
+
+        @Override
+        public void validate(String address, ValidationExceptionHandler validationExceptionHandler) {
+            if (FORMAT_PATTERN.asMatchPredicate().negate().test(address)) {
+                validationExceptionHandler.handle(new InvalidFormatException());
+            }
+        }
+    }
+
+    static class InvalidFormatException extends ValidationException {
+    }
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Password.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Password.java
new file mode 100644
index 0000000..e55688d
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Password.java
@@ -0,0 +1,25 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+record Password(String value) {
+
+    public Password {
+        Password.test(value, new ThrowingValidationExceptionHandler());
+    }
+
+    public static void test(String password, ValidationExceptionHandler validationExceptionHandler) {
+        new PasswordValidator().validate(password, validationExceptionHandler);
+    }
+
+    static class PasswordValidator implements Validator<String> {
+
+        @Override
+        public void validate(String password, ValidationExceptionHandler validationExceptionHandler) {
+            if (password.length() < 8 || password.length() > 16) {
+                validationExceptionHandler.handle(new InvalidLengthException());
+            }
+        }
+    }
+
+    static class InvalidLengthException extends ValidationException {
+    }
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ThrowingValidationExceptionHandler.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ThrowingValidationExceptionHandler.java
new file mode 100644
index 0000000..0500ece
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ThrowingValidationExceptionHandler.java
@@ -0,0 +1,9 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+class ThrowingValidationExceptionHandler implements ValidationExceptionHandler{
+
+    @Override
+    public void handle(ValidationException exception) {
+        throw exception;
+    }
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationException.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationException.java
new file mode 100644
index 0000000..d00a46d
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationException.java
@@ -0,0 +1,4 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+abstract class ValidationException extends RuntimeException {
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationExceptionHandler.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationExceptionHandler.java
new file mode 100644
index 0000000..32c6557
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidationExceptionHandler.java
@@ -0,0 +1,6 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+interface ValidationExceptionHandler {
+
+    void handle(ValidationException exception);
+}
diff --git a/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Validator.java b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Validator.java
new file mode 100644
index 0000000..88b6390
--- /dev/null
+++ b/DesignPatterns/src/main/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/Validator.java
@@ -0,0 +1,6 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+interface Validator<T> {
+
+    void validate(T toValid, ValidationExceptionHandler validationExceptionHandler);
+}
diff --git a/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitorTest.java b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitorTest.java
similarity index 93%
rename from DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitorTest.java
rename to DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitorTest.java
index 782fb4e..fd181f4 100644
--- a/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/CustomerVisitorTest.java
+++ b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/customer/CustomerVisitorTest.java
@@ -1,4 +1,4 @@
-package pl.mperor.lab.java.design.pattern.behavioral.visitor;
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.customer;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
diff --git a/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidatorVisitorTest.java b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidatorVisitorTest.java
new file mode 100644
index 0000000..1a151b0
--- /dev/null
+++ b/DesignPatterns/src/test/java/pl/mperor/lab/java/design/pattern/behavioral/visitor/validator/ValidatorVisitorTest.java
@@ -0,0 +1,26 @@
+package pl.mperor.lab.java.design.pattern.behavioral.visitor.validator;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ValidatorVisitorTest {
+
+    @Test
+    public void testValidatePasswordAndEmailWithExceptionAggregation() {
+        var aggregationHandler = new AggregatingValidationExceptionHandler();
+        Password.test("xyz", aggregationHandler);
+        Email.test("user1$gmail.com", aggregationHandler);
+        Assertions.assertTrue(aggregationHandler.hasErrors());
+        Assertions.assertEquals(aggregationHandler.getErrors().size(), 2);
+    }
+
+    @Test
+    public void testValidatePasswordAndEmailWithExceptionThrowing() {
+        Assertions.assertThrows(Password.InvalidLengthException.class, () -> new Password("xyz"));
+        Assertions.assertThrows(Email.InvalidFormatException.class, () -> new Email("user1$gmail.com"));
+
+        var throwingHandler = new ThrowingValidationExceptionHandler();
+        Assertions.assertThrows(Password.InvalidLengthException.class, () -> Password.test("xyz", throwingHandler));
+        Assertions.assertThrows(Email.InvalidFormatException.class, () -> Email.test("user1$gmail.com", throwingHandler));
+    }
+}
\ No newline at end of file