From 877f600bba0d60124fcc0db1ad13e288e7c57566 Mon Sep 17 00:00:00 2001 From: Victor Rentea Date: Fri, 17 Oct 2025 14:22:52 +0300 Subject: [PATCH 01/16] end day2 --- .../training/cleancode/BooleanParameters.java | 49 --- .../java/victor/training/cleancode/Boss.java | 45 --- .../victor/training/cleancode/CarSearch.java | 123 -------- .../cleancode/ExtractSimilarSyntax.java | 34 -- .../victor/training/cleancode/Guards.java | 46 --- .../training/cleancode/ParameterObjects.java | 72 ----- .../cleancode/PrimitiveObsession.java | 38 --- .../cleancode/PrimitiveObsessionVsTuples.java | 41 --- .../training/cleancode/RefactoringWarmup.java | 69 ---- .../victor/training/cleancode/SplitLoop.java | 31 -- .../training/cleancode/SplitLoopHard.java | 48 --- .../training/cleancode/StructuralReplace.java | 54 ---- .../victor/training/cleancode/Switch.java | 50 --- .../java/victor/training/cleancode/Task.java | 27 -- .../training/cleancode/exception/Biz.java | 23 -- .../training/cleancode/exception/Config.java | 29 -- .../exception/GlobalExceptionHandler.java.txt | 38 --- .../cleancode/exception/MyException.java | 58 ---- .../exception/SomeRestController.java.txt | 23 -- .../cleancode/exception/model/Customer.java | 26 -- .../cleancode/exception/model/MemberCard.java | 23 -- .../cleancode/exception/model/Order.java | 32 -- .../cleancode/fp/FragmentedImmutable.java | 22 -- .../cleancode/fp/FunctionalChainsaw.java | 31 -- .../training/cleancode/fp/LoanPattern.java | 51 --- .../cleancode/fp/LoanPattern_vsAOP.java | 23 -- .../training/cleancode/fp/MonadicError.java | 32 -- .../cleancode/fp/MonadicErrorEnd.java | 38 --- .../training/cleancode/fp/MutantPipeline.java | 50 --- .../training/cleancode/fp/OptionalAbuse.java | 32 -- .../training/cleancode/fp/PureFunction.java | 45 --- .../training/cleancode/fp/ReduceAbuse.java | 14 - .../training/cleancode/fp/ReduceAbuse2.java | 14 - .../victor/training/cleancode/fp/TODO.java | 30 -- .../training/cleancode/fp/TangledTuples.java | 47 --- .../training/cleancode/fp/support/Coupon.java | 35 --- .../cleancode/fp/support/CouponRepo.java | 7 - .../cleancode/fp/support/Customer.java | 8 - .../cleancode/fp/support/CustomerRepo.java | 8 - .../training/cleancode/fp/support/Order.java | 69 ---- .../cleancode/fp/support/OrderLine.java | 6 - .../cleancode/fp/support/OrderRepo.java | 12 - .../cleancode/fp/support/PaymentCard.java | 10 - .../cleancode/fp/support/PaymentCardDto.java | 4 - .../fp/support/PaymentCardMapper.java | 7 - .../fp/support/PaymentCardRepository.java | 9 - .../cleancode/fp/support/Product.java | 51 --- .../cleancode/fp/support/ProductCategory.java | 5 - .../cleancode/fp/support/ProductRepo.java | 9 - .../fp/support/ThirdPartyPricesApi.java | 5 - .../cleancode/immutable/LostInSet.java | 47 --- .../immutable/RefactorToImmutable.java | 75 ----- .../immutable/advanced/ImmutableAdvanced.java | 74 ----- .../immutable/basic/ImmutableBasic.java | 51 --- .../immutable/tracing/ImmutableTracing.java | 55 ---- .../immutable/tracing/MutableTracing.java | 52 --- .../cleancode/kata/expense/Expense.java | 10 - .../cleancode/kata/expense/ExpenseReport.java | 47 --- .../kata/funcfusion/PaymentFileService.java | 41 --- .../kata/funcfusion/PaymentProcessor.java | 86 ----- .../kata/funcfusion/PaymentsFile.java | 6 - .../kata/povalidator/POValidator.java | 108 ------- .../cleancode/kata/streams/Exercises.java | 240 -------------- .../cleancode/kata/streams/Order.java | 105 ------- .../cleancode/kata/streams/OrderDto.java | 20 -- .../cleancode/kata/streams/OrderLine.java | 16 - .../cleancode/kata/streams/OrderMapper.java | 12 - .../cleancode/kata/streams/Product.java | 4 - .../training/cleancode/mass/BaseService.java | 13 - .../training/cleancode/mass/Consultation.java | 25 -- .../victor/training/cleancode/mass/DAO.java | 4 - .../victor/training/cleancode/mass/Data.java | 8 - .../victor/training/cleancode/mass/Job.java | 18 -- .../victor/training/cleancode/mass/Medic.java | 41 --- .../cleancode/mass/OldAnnotation.java | 10 - .../training/cleancode/mass/Patient.java | 111 ------- .../cleancode/mass/PatientController.java | 17 - .../training/cleancode/mass/PatientDAO.java | 23 -- .../cleancode/mass/PatientService.java | 33 -- .../training/cleancode/mass/SpringApp.java | 13 - .../victor/training/cleancode/mass/User.java | 29 -- .../training/cleancode/mass/UserFilter.java | 21 -- .../training/cleancode/mass/UserHolder.java | 13 - .../cleancode/optional/NonNullByDefault.java | 13 - .../cleancode/optional/Optional_Chain.java | 80 ----- .../cleancode/optional/Optional_Intro.java | 46 --- .../optional/abuse/AllCallersFailOnEmpty.java | 44 --- .../optional/abuse/OptionalCollections.java | 39 --- .../optional/abuse/OptionalParameters.java | 26 -- .../optional/abuse/OrElseGetTrap.java | 24 -- .../cleancode/optional/package-info.java | 2 - .../CombineFunctionsIntoTransform.java | 31 -- .../refactoring/EncapsulateCollection.java | 44 --- .../refactoring/EncapsulateConditionals.java | 24 -- .../refactoring/ExtractDelegate.java | 43 --- .../refactoring/ExtractMethodObject.java | 41 --- .../ExtractMethodObject_Validator.java | 57 ---- .../refactoring/ExtractVariable.java | 14 - .../refactoring/ReplaceTempWithQuery.java | 30 -- .../refactoring/SeparateQueryCommand.java | 24 -- .../cleancode/refactoring/SplitPhase.java | 16 - .../cleancode/refactoring/SplitVariable.java | 11 - .../inheritance/ExtractInterface.java | 31 -- .../inheritance/ExtractSuperClass.java | 21 -- .../inheritance/SubclassToDelegate.java | 33 -- .../inheritance/SuperclassToDelegate.java | 32 -- .../inheritance/TypecodeToSubclass.java | 47 --- .../victor/training/cleancode/BossTest.java | 76 ----- .../cleancode/CaptureSystemOutput.java | 167 ---------- .../training/cleancode/CarSearchTest.java | 34 -- .../victor/training/cleancode/GuardsTest.java | 126 -------- .../training/cleancode/SomeServiceTest.java | 18 -- .../training/cleancode/SplitLoopHardTest.java | 65 ---- .../training/cleancode/SplitLoopTest.java | 60 ---- .../victor/training/cleancode/SwitchTest.java | 58 ---- .../extra/ReplaceTempWithQueryTest.java | 30 -- .../cleancode/extra/SplitVariableTest.java | 18 -- .../cleancode/fp/FunctionalChainsawTest.java | 94 ------ .../cleancode/fp/LoanPatternTest.java | 38 --- .../cleancode/fp/MutantPipelineTest.java | 64 ---- .../cleancode/fp/OptionalAbuseTest.java | 43 --- .../cleancode/fp/PureFunctionsTest.java | 56 ---- .../cleancode/fp/ReduceAbuseTest.java | 56 ---- .../cleancode/immutable/PriceServiceTest.java | 35 --- .../kata/expense/ExpenseReportTest.java | 70 ----- .../kata/povalidator/POValidatorTest.java | 54 ---- .../cleancode/kata/streams/ExercisesTest.java | 254 --------------- .../cleancode/kata/streams/sample.csv | 4 - .../cleancode/openrewrite/AssertJAd.java | 297 ------------------ .../openrewrite/JUnitToAssertJTestDemo.java | 33 -- 130 files changed, 5604 deletions(-) delete mode 100644 src/main/java/victor/training/cleancode/BooleanParameters.java delete mode 100644 src/main/java/victor/training/cleancode/Boss.java delete mode 100644 src/main/java/victor/training/cleancode/CarSearch.java delete mode 100644 src/main/java/victor/training/cleancode/ExtractSimilarSyntax.java delete mode 100644 src/main/java/victor/training/cleancode/Guards.java delete mode 100644 src/main/java/victor/training/cleancode/ParameterObjects.java delete mode 100644 src/main/java/victor/training/cleancode/PrimitiveObsession.java delete mode 100644 src/main/java/victor/training/cleancode/PrimitiveObsessionVsTuples.java delete mode 100644 src/main/java/victor/training/cleancode/RefactoringWarmup.java delete mode 100644 src/main/java/victor/training/cleancode/SplitLoop.java delete mode 100644 src/main/java/victor/training/cleancode/SplitLoopHard.java delete mode 100644 src/main/java/victor/training/cleancode/StructuralReplace.java delete mode 100644 src/main/java/victor/training/cleancode/Switch.java delete mode 100644 src/main/java/victor/training/cleancode/Task.java delete mode 100644 src/main/java/victor/training/cleancode/exception/Biz.java delete mode 100644 src/main/java/victor/training/cleancode/exception/Config.java delete mode 100644 src/main/java/victor/training/cleancode/exception/GlobalExceptionHandler.java.txt delete mode 100644 src/main/java/victor/training/cleancode/exception/MyException.java delete mode 100644 src/main/java/victor/training/cleancode/exception/SomeRestController.java.txt delete mode 100644 src/main/java/victor/training/cleancode/exception/model/Customer.java delete mode 100644 src/main/java/victor/training/cleancode/exception/model/MemberCard.java delete mode 100644 src/main/java/victor/training/cleancode/exception/model/Order.java delete mode 100644 src/main/java/victor/training/cleancode/fp/FragmentedImmutable.java delete mode 100644 src/main/java/victor/training/cleancode/fp/FunctionalChainsaw.java delete mode 100644 src/main/java/victor/training/cleancode/fp/LoanPattern.java delete mode 100644 src/main/java/victor/training/cleancode/fp/LoanPattern_vsAOP.java delete mode 100644 src/main/java/victor/training/cleancode/fp/MonadicError.java delete mode 100644 src/main/java/victor/training/cleancode/fp/MonadicErrorEnd.java delete mode 100644 src/main/java/victor/training/cleancode/fp/MutantPipeline.java delete mode 100644 src/main/java/victor/training/cleancode/fp/OptionalAbuse.java delete mode 100644 src/main/java/victor/training/cleancode/fp/PureFunction.java delete mode 100644 src/main/java/victor/training/cleancode/fp/ReduceAbuse.java delete mode 100644 src/main/java/victor/training/cleancode/fp/ReduceAbuse2.java delete mode 100644 src/main/java/victor/training/cleancode/fp/TODO.java delete mode 100644 src/main/java/victor/training/cleancode/fp/TangledTuples.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/Coupon.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/CouponRepo.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/Customer.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/CustomerRepo.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/Order.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/OrderLine.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/OrderRepo.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/PaymentCard.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/PaymentCardDto.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/PaymentCardMapper.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/PaymentCardRepository.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/Product.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/ProductCategory.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/ProductRepo.java delete mode 100644 src/main/java/victor/training/cleancode/fp/support/ThirdPartyPricesApi.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/LostInSet.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/RefactorToImmutable.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/advanced/ImmutableAdvanced.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/basic/ImmutableBasic.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/tracing/ImmutableTracing.java delete mode 100644 src/main/java/victor/training/cleancode/immutable/tracing/MutableTracing.java delete mode 100644 src/main/java/victor/training/cleancode/kata/expense/Expense.java delete mode 100644 src/main/java/victor/training/cleancode/kata/expense/ExpenseReport.java delete mode 100644 src/main/java/victor/training/cleancode/kata/funcfusion/PaymentFileService.java delete mode 100644 src/main/java/victor/training/cleancode/kata/funcfusion/PaymentProcessor.java delete mode 100644 src/main/java/victor/training/cleancode/kata/funcfusion/PaymentsFile.java delete mode 100644 src/main/java/victor/training/cleancode/kata/povalidator/POValidator.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/Exercises.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/Order.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/OrderDto.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/OrderLine.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/OrderMapper.java delete mode 100644 src/main/java/victor/training/cleancode/kata/streams/Product.java delete mode 100644 src/main/java/victor/training/cleancode/mass/BaseService.java delete mode 100644 src/main/java/victor/training/cleancode/mass/Consultation.java delete mode 100644 src/main/java/victor/training/cleancode/mass/DAO.java delete mode 100644 src/main/java/victor/training/cleancode/mass/Data.java delete mode 100644 src/main/java/victor/training/cleancode/mass/Job.java delete mode 100644 src/main/java/victor/training/cleancode/mass/Medic.java delete mode 100644 src/main/java/victor/training/cleancode/mass/OldAnnotation.java delete mode 100644 src/main/java/victor/training/cleancode/mass/Patient.java delete mode 100644 src/main/java/victor/training/cleancode/mass/PatientController.java delete mode 100644 src/main/java/victor/training/cleancode/mass/PatientDAO.java delete mode 100644 src/main/java/victor/training/cleancode/mass/PatientService.java delete mode 100644 src/main/java/victor/training/cleancode/mass/SpringApp.java delete mode 100644 src/main/java/victor/training/cleancode/mass/User.java delete mode 100644 src/main/java/victor/training/cleancode/mass/UserFilter.java delete mode 100644 src/main/java/victor/training/cleancode/mass/UserHolder.java delete mode 100644 src/main/java/victor/training/cleancode/optional/NonNullByDefault.java delete mode 100644 src/main/java/victor/training/cleancode/optional/Optional_Chain.java delete mode 100644 src/main/java/victor/training/cleancode/optional/Optional_Intro.java delete mode 100644 src/main/java/victor/training/cleancode/optional/abuse/AllCallersFailOnEmpty.java delete mode 100644 src/main/java/victor/training/cleancode/optional/abuse/OptionalCollections.java delete mode 100644 src/main/java/victor/training/cleancode/optional/abuse/OptionalParameters.java delete mode 100644 src/main/java/victor/training/cleancode/optional/abuse/OrElseGetTrap.java delete mode 100644 src/main/java/victor/training/cleancode/optional/package-info.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/CombineFunctionsIntoTransform.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/EncapsulateCollection.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/EncapsulateConditionals.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/ExtractDelegate.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject_Validator.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/ExtractVariable.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/ReplaceTempWithQuery.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/SeparateQueryCommand.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/SplitPhase.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/SplitVariable.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractInterface.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractSuperClass.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/inheritance/SubclassToDelegate.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/inheritance/SuperclassToDelegate.java delete mode 100644 src/main/java/victor/training/cleancode/refactoring/inheritance/TypecodeToSubclass.java delete mode 100644 src/test/java/victor/training/cleancode/BossTest.java delete mode 100644 src/test/java/victor/training/cleancode/CaptureSystemOutput.java delete mode 100644 src/test/java/victor/training/cleancode/CarSearchTest.java delete mode 100644 src/test/java/victor/training/cleancode/GuardsTest.java delete mode 100644 src/test/java/victor/training/cleancode/SomeServiceTest.java delete mode 100644 src/test/java/victor/training/cleancode/SplitLoopHardTest.java delete mode 100644 src/test/java/victor/training/cleancode/SplitLoopTest.java delete mode 100644 src/test/java/victor/training/cleancode/SwitchTest.java delete mode 100644 src/test/java/victor/training/cleancode/extra/ReplaceTempWithQueryTest.java delete mode 100644 src/test/java/victor/training/cleancode/extra/SplitVariableTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/FunctionalChainsawTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/LoanPatternTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/MutantPipelineTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/OptionalAbuseTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/PureFunctionsTest.java delete mode 100644 src/test/java/victor/training/cleancode/fp/ReduceAbuseTest.java delete mode 100644 src/test/java/victor/training/cleancode/immutable/PriceServiceTest.java delete mode 100644 src/test/java/victor/training/cleancode/kata/expense/ExpenseReportTest.java delete mode 100644 src/test/java/victor/training/cleancode/kata/povalidator/POValidatorTest.java delete mode 100644 src/test/java/victor/training/cleancode/kata/streams/ExercisesTest.java delete mode 100644 src/test/java/victor/training/cleancode/kata/streams/sample.csv delete mode 100644 src/test/java/victor/training/cleancode/openrewrite/AssertJAd.java delete mode 100644 src/test/java/victor/training/cleancode/openrewrite/JUnitToAssertJTestDemo.java diff --git a/src/main/java/victor/training/cleancode/BooleanParameters.java b/src/main/java/victor/training/cleancode/BooleanParameters.java deleted file mode 100644 index e2baa47cf..000000000 --- a/src/main/java/victor/training/cleancode/BooleanParameters.java +++ /dev/null @@ -1,49 +0,0 @@ -package victor.training.cleancode; - -class SomeController { - SomeService someService; - -// @GetMapping("blue/{storeId}") - public void blueEndpoint(int storeId, Task task) { - someService.blueMethod(storeId, task); - } - -// @GetMapping("red/{storeId}") - public void redEndpoint( int storeId, Task task) { - someService.redMethod(storeId, task); - } -} - -class SomeService { - public void blueMethod(int id, Task task) { - BooleanParameters.bigUglyMethod(id, task, false); - } - - public void greenMethod(int id, Task task) { - BooleanParameters.bigUglyMethod(id, task, false); - } - - public void yellowMethod(int id, Task task) { - BooleanParameters.bigUglyMethod(id, task, false); - } - - public void redMethod(int id, Task task) { - BooleanParameters.bigUglyMethod(id, task, true); - } -} - -public class BooleanParameters { - public static void bigUglyMethod(int storeId, Task task, boolean cr323) { - System.out.println("Donkey Logic 1 " + task + " and " + storeId); - System.out.println(task); - System.out.println("Donkey Logic 3 " + task); - - if (cr323) System.out.println("Logic just for CR#323 : " + task); - - System.out.println("Sheep Logic 1 " + storeId); - System.out.println("Sheep Logic 2 "); - System.out.println("Sheep Logic 3 "); - } -} - - diff --git a/src/main/java/victor/training/cleancode/Boss.java b/src/main/java/victor/training/cleancode/Boss.java deleted file mode 100644 index 8db30a581..000000000 --- a/src/main/java/victor/training/cleancode/Boss.java +++ /dev/null @@ -1,45 +0,0 @@ -package victor.training.cleancode; - -import java.util.ArrayList; -import java.util.List; - -// Deep nested functions are harder to break down -public class Boss { - - // 👌 TODO run tests - public void bossLevel(boolean b, List tasks, boolean cr323) { - int index = 0; - int j = tasks.size(); - if (tasks.size() == 0) { - return; - } - System.out.println("Logic1"); - List taskIds = new ArrayList<>(); - if (b) { - System.out.println("Logic3"); - check(tasks); - for (Task task : tasks) { - System.out.println("Starting " + task); - task.setStarted(true); - - taskIds.add(task.getId()); - - if (cr323) { // TODO remove the boolean - System.out.println("My Logic: " + task); - } - - index++; - System.out.println("Audit task #" + index + ": " + task); - } - System.out.println("Logic6 " + j); - System.out.println("Task Ids: " + taskIds); - } else { - System.out.println("Logic7 on fluff=false " + tasks); - } - System.out.println("Logic8"); - } - - private void check(List tasks) { -// tasks.remove(0); // surprise - } -} diff --git a/src/main/java/victor/training/cleancode/CarSearch.java b/src/main/java/victor/training/cleancode/CarSearch.java deleted file mode 100644 index e4298bdae..000000000 --- a/src/main/java/victor/training/cleancode/CarSearch.java +++ /dev/null @@ -1,123 +0,0 @@ -package victor.training.cleancode; - -import java.util.List; -import java.util.stream.Collectors; - -class CarSearch { - - // run tests - public List filterCarModels(CarSearchCriteria criteria, List carModels) { - List results = carModels.stream() - .filter(carModel -> MathUtil.intervalsIntersect( - criteria.getStartYear(), criteria.getEndYear(), - carModel.getStartYear(), carModel.getEndYear())) - .collect(Collectors.toList()); - System.out.println("More filtering logic ..."); - return results; - } -} - -class SomeOtherClientCode { - private void applyLengthFilter() { // pretend - System.out.println(MathUtil.intervalsIntersect(1000, 1600, 1250, 2000)); - } - private void applyCapacityFilter() { // pretend - System.out.println(MathUtil.intervalsIntersect(1000, 1600, 1250, 2000)); - } -} - -class MathUtil { - - public static boolean intervalsIntersect(int start1, int end1, int start2, int end2) { - return start1 <= end2 && start2 <= end1; - } -} - - -class CarSearchCriteria { // a DTO received from JSON - private final int startYear; - private final int endYear; - private final String make; - - public CarSearchCriteria(int startYear, int endYear, String make) { - this.make = make; - if (startYear > endYear) throw new IllegalArgumentException("start larger than end"); - this.startYear = startYear; - this.endYear = endYear; - } - - public int getStartYear() { - return startYear; - } - - public int getEndYear() { - return endYear; - } - - public String getMake() { - return make; - } -} - -// @Entity -class CarModel { // the Entity Model👑 test - // @Id - private Long id; - private String make; - private String model; - private int startYear; - private int endYear; - - protected CarModel() { - } // for Hibernate - - public CarModel(String make, String model, int startYear, int endYear) { - this.make = make; - this.model = model; - if (startYear > endYear) throw new IllegalArgumentException("start larger than end"); - this.startYear = startYear; - this.endYear = endYear; - } - - public Long getId() { - return id; - } - - public int getEndYear() { - return endYear; - } - - public int getStartYear() { - return startYear; - } - - public String getMake() { - return make; - } - - public String getModel() { - return model; - } -} - -class CarModelMapper { - public CarModelDto toDto(CarModel carModel) { - CarModelDto dto = new CarModelDto(); - dto.make = carModel.getMake(); - dto.model = carModel.getModel(); - dto.startYear = carModel.getStartYear(); - dto.endYear = carModel.getEndYear(); - return dto; - } - - public CarModel fromDto(CarModelDto dto) { - return new CarModel(dto.make, dto.model, dto.startYear, dto.endYear); - } -} - -class CarModelDto { - public String make; - public String model; - public int startYear; - public int endYear; -} diff --git a/src/main/java/victor/training/cleancode/ExtractSimilarSyntax.java b/src/main/java/victor/training/cleancode/ExtractSimilarSyntax.java deleted file mode 100644 index a7c1f1fc5..000000000 --- a/src/main/java/victor/training/cleancode/ExtractSimilarSyntax.java +++ /dev/null @@ -1,34 +0,0 @@ -package victor.training.cleancode; - -class ParameterizeExtractSimilarCode { - - public void f(int n) { - System.out.println("Logic F"); - for (int i = 0; i < 4; i++) { - if (n + i < 0) { - System.out.println("Code " + i); - } else { - throw new IllegalArgumentException(); - } - } - } -} -// ========= separate class ========= - -class SomeOtherClass { - public void g(int n) { - System.out.println("Logic G"); - try { - for (int j = 0; j < 4; j++) { - if (n + j < 0) { - System.out.println("Code" + j); - } else { - throw new IllegalArgumentException(); - } - } - } catch (Exception e) { - throw new RuntimeException("Rethrow", e); - } - } - -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/Guards.java b/src/main/java/victor/training/cleancode/Guards.java deleted file mode 100644 index 54d5a8663..000000000 --- a/src/main/java/victor/training/cleancode/Guards.java +++ /dev/null @@ -1,46 +0,0 @@ -package victor.training.cleancode; - -import java.util.List; - -public class Guards { - - public static final int DEAD_PAY_AMOUNT = 1; - - public int getPayAmount(Marine marine, BonusPackage bonusPackage) { - // if (marine == null || (bonusPackage.value() < 10 || bonusPackage.value() > 100)) { - if (marine == null || (bonusPackage.value() < 10 || bonusPackage.value() > 100)) { - throw new IllegalArgumentException("Not applicable!"); - } - if (marine.dead()) { - return DEAD_PAY_AMOUNT; - } - if (marine.retired()) { // guard condition - return retiredAmount(); // early return - } - if (marine.yearsOfService() == null) { - throw new IllegalArgumentException("Any marine should have the years of service set"); - } - int result = marine.yearsOfService() * 100 + bonusPackage.value(); - if (!marine.awards().isEmpty()) { - result += 1000; - } - if (marine.awards().size() >= 3) { - result += 2000; - } - return result; - } - - private int retiredAmount() { - return 2; - } -} - -record Marine(boolean dead, boolean retired, Integer yearsOfService, List awards) { -} - -record BonusPackage(int value) { -} - -class Award { - -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/ParameterObjects.java b/src/main/java/victor/training/cleancode/ParameterObjects.java deleted file mode 100644 index 7358c41fc..000000000 --- a/src/main/java/victor/training/cleancode/ParameterObjects.java +++ /dev/null @@ -1,72 +0,0 @@ -package victor.training.cleancode; - -public class ParameterObjects { - public static void main(String[] args) { - new ParameterObjects().placeOrder( - "John", "Doe", - "St. Albergue", "Paris", 99); - - new AnotherClass().otherMethod("John", "Doe", 17); - } - - public void placeOrder(String fName, String lName, String city, String streetName, Integer streetNumber) { - if (fName == null || lName == null) throw new IllegalArgumentException(); - - System.out.println("Some Logic"); - System.out.println("Shipping to " + city + " on St. " + streetName + " " + streetNumber); - - } -} - -class AnotherClass { - public void otherMethod(String firstName, String lastName, int x) { - if (firstName == null || lastName == null) throw new IllegalArgumentException(); - - System.out.println("Another distant Logic " + x); - System.out.println("Person: " + lastName); - } -} - -// Domain Entity -class Person { - private Long id; - private String firstName; - private String lastName; - private String phone; - - public Person(String firstName, String lastName) { - if (firstName == null || lastName == null) throw new IllegalArgumentException(); - this.firstName = firstName; - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } - - // TODO hard-core: implement setter - public void setLastName(String lastName) { - this.lastName = lastName; - } -} - -class PersonService { - public void f(Person person) { - System.out.println("Hi there, " + person.getFirstName()); - - String fullNameStr = person.getFirstName() + " " + person.getLastName().toUpperCase(); - System.out.println("Record for " + fullNameStr); - } - - public void p(String streetName, String city, Integer streetNumber) { - System.out.println("Living in " + city + " on street: " + streetName + " " + streetNumber); - } - - public void pcaller() { - p("Champs Elysees", "Paris", 91); - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/PrimitiveObsession.java b/src/main/java/victor/training/cleancode/PrimitiveObsession.java deleted file mode 100644 index e4b15cd94..000000000 --- a/src/main/java/victor/training/cleancode/PrimitiveObsession.java +++ /dev/null @@ -1,38 +0,0 @@ -package victor.training.cleancode; - -import java.util.Map; - -import static java.util.stream.Collectors.joining; - -public class PrimitiveObsession { - - public static void main(String[] args) { - new PrimitiveObsession().primitiveObsession("CARD"); - } - - // - public Map> fetchData(String paymentMethod) { - Long customerId = 1L; - Integer product1Count = 2; - Integer product2Count = 4; - return Map.of(customerId, Map.of( - "Table", product1Count, - "Chair", product2Count - )); - } - // - - public void primitiveObsession(String paymentMethod) { - if (!"CARD".equals(paymentMethod) && !"CASH".equals(paymentMethod)) { - throw new IllegalArgumentException("Only CARD payment method is supported"); - } - Map> map = fetchData(paymentMethod); - - for (var e : map.entrySet()) { // iterating map entries 🤢 - String pl = e.getValue().entrySet().stream() - .map(entry -> entry.getValue() + " pcs. of " + entry.getKey()) - .collect(joining(", ")); - System.out.println("cid=" + e.getKey() + " got " + pl); - } - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/PrimitiveObsessionVsTuples.java b/src/main/java/victor/training/cleancode/PrimitiveObsessionVsTuples.java deleted file mode 100644 index d027f03f7..000000000 --- a/src/main/java/victor/training/cleancode/PrimitiveObsessionVsTuples.java +++ /dev/null @@ -1,41 +0,0 @@ -package victor.training.cleancode; - -import org.jooq.lambda.tuple.Tuple; -import org.jooq.lambda.tuple.Tuple2; - -import java.util.List; -import java.util.Map; - -import static java.util.stream.Collectors.joining; - -public class PrimitiveObsessionVsTuples { - - // - public Map> extremeFP() { - Long customerId = 1L; - Integer product1Count = 2; - Integer product2Count = 4; - return Map.of(new CustomerId(customerId), List.of( - new ProductCount("Table", product1Count), - new ProductCount("Chair", product2Count) - )); - } - // - - record ProductCount(String name, int count) { - } - - record CustomerId(long id) { - } // OMG!! eg agentId - - void lackOfAbstractions() { - Map> map = extremeFP(); - - for (CustomerId cid : map.keySet()) { - String pl = map.get(cid).stream() - .map(t -> t.count() + " pcs. of " + t.name()) - .collect(joining(", ")); - System.out.println("cid=" + cid.id() + " got " + pl); - } - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/RefactoringWarmup.java b/src/main/java/victor/training/cleancode/RefactoringWarmup.java deleted file mode 100644 index 2f6600f57..000000000 --- a/src/main/java/victor/training/cleancode/RefactoringWarmup.java +++ /dev/null @@ -1,69 +0,0 @@ -package victor.training.cleancode; - - -import java.util.List; - -class RefactoringWarmup { - public static void main(String[] args) { - Two two = new Two(); - System.out.println(two.loop(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))); - System.out.println(new One(two).f()); - System.out.println(two.g(new R(1))); - } -} - -class One { - private final Two two; - - One(Two two) { - this.two = two; - } - - public int f() { - return 2 * two.g(new R(3)); - } -} - -class Two { - public int g(R r) { - int b = 2; - System.out.println("b=" + b); - return 1 + b + r.x(); - } - - public double loop(List numbers) { - System.out.println("b=" + 987); - double ssq = 0; - for (Integer number : numbers) { - if (number % 2 == 0) { - ssq += number * number; - } - } - return Math.sqrt(ssq); - } -} - -record R(int x) { -} - -// TODO: Practice Refactoring -// * How to? -// - Select text > Right Click > Refactor -// - Ctrl-Alt-Shift-T/^T to -// - Keys: [Ctrl-Alt / Opt-Cmd] + [V]ariable/[M]ethod/[P]arameter/i[N]line -// * What? // after every action undo/revert to start clean -// - Inline Variable 'b' -// - Extract Variable '1', '3 * two.g()' -// - Extract Method 'System.out..' (+replace duplicate) -// - Inline Method 'g' -// - Extract Parameter '1', 'r.x()' -// - Inline Parameter 'c' -// - Change Signature 'g': add 1 param with default as 1st arg -// - Extract Interface 'Two'->ITwo; + Inline back to destroy interface -// - Rename 'g' -> 'h' by Shift-F6 or just edit>Alt-Enter>Rename -// - Move Method 'g' into R -// - Preview method/class: Ctrl-Shift-I -// - Quickfix (Alt/Option -Enter) for->stream -// - Edit inspection severity & highlighting -// * Download "aggressive_refactoring.xml" from https://victorrentea.ro -// and import it in Settings>Editor>Inspections diff --git a/src/main/java/victor/training/cleancode/SplitLoop.java b/src/main/java/victor/training/cleancode/SplitLoop.java deleted file mode 100644 index c5c5ebab1..000000000 --- a/src/main/java/victor/training/cleancode/SplitLoop.java +++ /dev/null @@ -1,31 +0,0 @@ -package victor.training.cleancode; - -import lombok.Builder; - -import java.util.ArrayList; -import java.util.List; - -public class SplitLoop { - // TODO Split loops and refactor to .stream. Run Tests✅ - public String computeStats(List employees) { - List employeeIds = new ArrayList<>(); - double totalConsultantSalary = 0; - for (Employee employee : employees) { - if (employee.consultant()) { - totalConsultantSalary += employee.salary(); - } - employeeIds.add(employee.id()); - } - System.out.println("Employee IDs: " + employeeIds); - return "Total consultant salary: " + totalConsultantSalary + "; ids: " + employeeIds; - } - - @Builder(toBuilder = true) - public record Employee( - Integer id, - int age, - Integer salary, - boolean consultant) { - } -} - diff --git a/src/main/java/victor/training/cleancode/SplitLoopHard.java b/src/main/java/victor/training/cleancode/SplitLoopHard.java deleted file mode 100644 index bc6514bea..000000000 --- a/src/main/java/victor/training/cleancode/SplitLoopHard.java +++ /dev/null @@ -1,48 +0,0 @@ -package victor.training.cleancode; - -import victor.training.cleancode.SplitLoop.Employee; - -import java.util.List; - -public class SplitLoopHard { - - EmployeeService employeeService; - - // TODO Split loops and refactor to .stream. Run Tests✅ - public String computeStatsHard(List employees) { - long totalEmpAge = 0; - double totalConsultantSalary = 0; - for (Employee employee : employees) { - if (!employee.consultant()) { - totalEmpAge += employee.age(); - continue; - } - if (employee.id() == null) { - return "Employee(s) not persisted"; - } - - Integer salary = employee.salary(); - if (salary == null) { - salary = employeeService.retrieveSalary(employee.id()); - if (salary == null) { - throw new RuntimeException("NO salary found for employee " + employee.id()); - } - } - totalConsultantSalary += salary; - } - - long averageAge = 0; - if (totalEmpAge != 0) { - averageAge = totalEmpAge / employees.stream().filter(e -> !e.consultant()).count(); - } - double averageConsultantSalary = 0; - if (totalConsultantSalary != 0) { - averageConsultantSalary = totalConsultantSalary / employees.size(); - } - return "Average employee age = " + averageAge + "; Average consultant salary = " + averageConsultantSalary; - } - - interface EmployeeService { - Integer retrieveSalary(int employeeId); - } -} diff --git a/src/main/java/victor/training/cleancode/StructuralReplace.java b/src/main/java/victor/training/cleancode/StructuralReplace.java deleted file mode 100644 index 89f402cac..000000000 --- a/src/main/java/victor/training/cleancode/StructuralReplace.java +++ /dev/null @@ -1,54 +0,0 @@ -package victor.training.cleancode; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.ResourceBundle; - -public class StructuralReplace { - private static final Logger log = LoggerFactory.getLogger(StructuralReplace.class); - - public void location1() { - String firstName = "John"; - log.info(Library.render(Library.translate("Hello %s %s"), - firstName, - "Doe")); - log.info(Library.render(Library.translate("Hi " + "%s"), firstName.toUpperCase())); - log.info(Library.render("No Template", firstName)); - -// log.info(Library.renderTranslate("Hello %s %s", firstName, "Doe")); // result -// log.info(Library.renderTranslate("Hi " + "%s", firstName.toUpperCase())); // result -// log.info(Library.render("No Template", firstName)); // result - } - - public String location2(String in) { - return Library.render(Library.translate("Hi " + "%s"), in.toUpperCase()); -// return Library.renderTranslate("Hi " + "%s", in.toUpperCase()); // result - } - // Go to Edit > Find > Replace Structurally - // Input: victor.training.cleancode.Library.render(victor.training.cleancode.Library.translate($Key$), $Parameters$) - // + set count to $Parameters$ 0..∞ - // Output: victor.training.cleancode.Library.renderTranslate($Key$, $Parameters$) -} - -class Library { - public static ResourceBundle resourceBundle = ResourceBundle.getBundle("messages"); - - public static String render(String template, String... values) { - String[] transformedParams = Arrays.stream(values).map(java.lang.String::toUpperCase).toArray(String[]::new); - return template.formatted((Object[]) transformedParams); - } - - public static String translate(String messageKey) { - if (resourceBundle.containsKey(resourceBundle.getString(messageKey))) { - return resourceBundle.getString(messageKey); - } else { - return messageKey; - } - } - - public static String renderTranslate(String key, String... values) { - return render(translate(key), values); - } -} diff --git a/src/main/java/victor/training/cleancode/Switch.java b/src/main/java/victor/training/cleancode/Switch.java deleted file mode 100644 index 701e13afd..000000000 --- a/src/main/java/victor/training/cleancode/Switch.java +++ /dev/null @@ -1,50 +0,0 @@ -package victor.training.cleancode; - - -public class Switch { - - // run tests - public int computePrice(Movie movie, int days) {// query method - switch (movie.category()) { - case REGULAR: - return days + 1; - case NEW_RELEASE: - return days * 2; - case CHILDREN: - return 5; - } - return 0; - } - - // run tests - public void processMovie(Movie movie) { - System.out.println("Some repo calls"); - System.out.println("Some shared initial stuff"); - - // check parental advisory - switch (movie.category()) { - case REGULAR: - System.out.println("Process regular movie: " + movie); - break; - case CHILDREN: - System.out.println("Process children movie: " + movie); - break; - case NEW_RELEASE: - System.out.println("Process new release movie: " + movie); - break; - } - - System.out.println("More common code after"); - } - - record Movie(Category category, String title) { - @Override - public String toString() { - return "Movie{category=" + category + ", title='" + title + "'}"; - } - - enum Category { - REGULAR, NEW_RELEASE, CHILDREN - } - } -} diff --git a/src/main/java/victor/training/cleancode/Task.java b/src/main/java/victor/training/cleancode/Task.java deleted file mode 100644 index df43d1cf1..000000000 --- a/src/main/java/victor/training/cleancode/Task.java +++ /dev/null @@ -1,27 +0,0 @@ -package victor.training.cleancode; - - -public class Task { - private final int id; - private boolean started; - - public Task(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public void setStarted(boolean started) { - this.started = started; - } - - public boolean isStarted() { - return started; - } - @Override - public String toString() { - return "Task(" + "id=" + id + ", started=" + started + ')'; - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/exception/Biz.java b/src/main/java/victor/training/cleancode/exception/Biz.java deleted file mode 100644 index 5ead8f819..000000000 --- a/src/main/java/victor/training/cleancode/exception/Biz.java +++ /dev/null @@ -1,23 +0,0 @@ -package victor.training.cleancode.exception; - -import lombok.RequiredArgsConstructor; -import victor.training.cleancode.exception.model.Customer; -import victor.training.cleancode.exception.model.Order; - -@RequiredArgsConstructor -public class Biz { - private final Config config; - - public void applyDiscount(Order order, Customer customer) { - System.out.println("START"); - if (order.getOfferDate().before(config.getLastPromoDate()) && - customer.getMemberCard().isPresent()) { // TODO inside - int points = customer.getMemberCard().get().getFidelityPoints(); - order.setPrice(order.getPrice() * (100 - 2 * points) / 100); - System.out.println("APPLIED DISCOUNT using " + customer.getMemberCard().get().getBarcode()); - } else { - System.out.println("NO DISCOUNT"); - } - } -} - diff --git a/src/main/java/victor/training/cleancode/exception/Config.java b/src/main/java/victor/training/cleancode/exception/Config.java deleted file mode 100644 index 8fe51a550..000000000 --- a/src/main/java/victor/training/cleancode/exception/Config.java +++ /dev/null @@ -1,29 +0,0 @@ -package victor.training.cleancode.exception; - - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Properties; - - -//@Component -public class Config { - - public Date getLastPromoDate() { -// File file = new File("config.properties"); -// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); -// Properties properties = new Properties(); -// try (FileReader reader = new FileReader(file)) { -// properties.load(reader); -// } -// return format.parse(properties.getProperty("last.promo.date")); - return new Date(); - } - - -} diff --git a/src/main/java/victor/training/cleancode/exception/GlobalExceptionHandler.java.txt b/src/main/java/victor/training/cleancode/exception/GlobalExceptionHandler.java.txt deleted file mode 100644 index b8f86659c..000000000 --- a/src/main/java/victor/training/cleancode/exception/GlobalExceptionHandler.java.txt +++ /dev/null @@ -1,38 +0,0 @@ -package victor.training.cleancode.exception; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.MessageSource; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -import javax.servlet.http.HttpServletRequest; - -@RequiredArgsConstructor -@RestControllerAdvice -@Slf4j -public class GlobalExceptionHandler { - - private final MessageSource messageSource; - - @ExceptionHandler(Exception.class) - @ResponseStatus - public String handleAnyException(Exception e, HttpServletRequest request) { - String userMessage = messageSource.getMessage("GENERAL", null, request.getLocale()); - - log.error("Unexpected: " + userMessage, e); - return userMessage; - } - - @ExceptionHandler(MyException.class) // more specific, attempted first - @ResponseStatus - public String handleMyException(MyException myException, HttpServletRequest request) { - String userMessage = messageSource.getMessage( - myException.getCode().name(), - myException.getParams(), - request.getLocale()); - log.error("Exception: " + userMessage, myException); - return userMessage; - } -} diff --git a/src/main/java/victor/training/cleancode/exception/MyException.java b/src/main/java/victor/training/cleancode/exception/MyException.java deleted file mode 100644 index 9b03968e6..000000000 --- a/src/main/java/victor/training/cleancode/exception/MyException.java +++ /dev/null @@ -1,58 +0,0 @@ -package victor.training.cleancode.exception; - -public class MyException extends RuntimeException { - - public enum ErrorCode { - GENERAL, - BAD_CONFIG, - CONDITION_RED, - } - - private final ErrorCode code; - private final Object[] params; - - public ErrorCode getCode() { - return code; - } - - public Object[] getParams() { - return params; - } - - public MyException(Exception e) { - this(e, ErrorCode.GENERAL); - } - - public MyException(String message, Exception cause) { - this(message, cause, ErrorCode.GENERAL); - } - - public MyException(ErrorCode code, Object... params) { - this.code = code; - this.params = params; - } - - public MyException(String message, ErrorCode code, Object... params) { - super(message); - this.code = code; - this.params = params; - } - - public MyException(String message, Throwable cause, ErrorCode code, Object... params) { - super(message, cause); - this.code = code; - this.params = params; - } - - public MyException(Throwable cause, ErrorCode code, Object... params) { - super(cause); - this.code = code; - this.params = params; - } - - public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, ErrorCode code, Object... params) { - super(message, cause, enableSuppression, writableStackTrace); - this.code = code; - this.params = params; - } -} diff --git a/src/main/java/victor/training/cleancode/exception/SomeRestController.java.txt b/src/main/java/victor/training/cleancode/exception/SomeRestController.java.txt deleted file mode 100644 index 4d42cd674..000000000 --- a/src/main/java/victor/training/cleancode/exception/SomeRestController.java.txt +++ /dev/null @@ -1,23 +0,0 @@ -package victor.training.cleancode.exception; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@SpringBootApplication -public class SomeRestController { - public static void main(String[] args) { - SpringApplication.run(SomeRestController.class, args); - } - - @Autowired - private Biz biz; - - @GetMapping - public void webEndpoint() { - biz.applyDiscount(new Order()); - } -} diff --git a/src/main/java/victor/training/cleancode/exception/model/Customer.java b/src/main/java/victor/training/cleancode/exception/model/Customer.java deleted file mode 100644 index 22e0d259b..000000000 --- a/src/main/java/victor/training/cleancode/exception/model/Customer.java +++ /dev/null @@ -1,26 +0,0 @@ -package victor.training.cleancode.exception.model; - -import java.util.Optional; - -import static java.util.Optional.ofNullable; - -public class Customer { - private String name; - private MemberCard memberCard; - - public Customer() { - } - - public Customer(MemberCard memberCard) { - this.memberCard = memberCard; - } - - public Optional getMemberCard() { - return Optional.ofNullable(memberCard); - } - - public Customer setMemberCard(MemberCard memberCard) { - this.memberCard = memberCard; - return this; - } -} diff --git a/src/main/java/victor/training/cleancode/exception/model/MemberCard.java b/src/main/java/victor/training/cleancode/exception/model/MemberCard.java deleted file mode 100644 index 39e5698e4..000000000 --- a/src/main/java/victor/training/cleancode/exception/model/MemberCard.java +++ /dev/null @@ -1,23 +0,0 @@ -package victor.training.cleancode.exception.model; - -public class MemberCard { - private final String barcode; - private final int fidelityPoints; - - public MemberCard(String barcode) { - this(barcode, 1); - } - public MemberCard(String barcode, int fidelityPoints) { - this.barcode = barcode; - this.fidelityPoints = fidelityPoints; - } - - public String getBarcode() { - return barcode; - } - - public int getFidelityPoints() { - return fidelityPoints; - } - -} diff --git a/src/main/java/victor/training/cleancode/exception/model/Order.java b/src/main/java/victor/training/cleancode/exception/model/Order.java deleted file mode 100644 index 0a023d2fb..000000000 --- a/src/main/java/victor/training/cleancode/exception/model/Order.java +++ /dev/null @@ -1,32 +0,0 @@ -package victor.training.cleancode.exception.model; - -import java.util.Date; - -import static java.util.Objects.requireNonNull; - -public class Order { - private int price; - private Date offerDate; - - public Order(Date offerDate) { - setOfferDate(offerDate); - } - - public int getPrice() { - return price; - } - - public Order setPrice(int price) { - this.price = price; - return this; - } - - public Date getOfferDate() { - return offerDate; - } - - public Order setOfferDate(Date offerDate) { - this.offerDate = requireNonNull(offerDate); - return this; - } -} diff --git a/src/main/java/victor/training/cleancode/fp/FragmentedImmutable.java b/src/main/java/victor/training/cleancode/fp/FragmentedImmutable.java deleted file mode 100644 index 633931767..000000000 --- a/src/main/java/victor/training/cleancode/fp/FragmentedImmutable.java +++ /dev/null @@ -1,22 +0,0 @@ -package victor.training.cleancode.fp; - -public class FragmentedImmutable { - public static void main(String[] args) { - POI poi = new POI(50, 50, "drop", "Toilet"); - jitter(poi); - System.out.println("jittered poi: " + poi); - } - - private static void jitter(POI poi) { - // TODO +1 to poi.x - // TODO +1 to poi.y - } - - record POI( - int x, - int y, - String icon, - String name - ) {} -} - diff --git a/src/main/java/victor/training/cleancode/fp/FunctionalChainsaw.java b/src/main/java/victor/training/cleancode/fp/FunctionalChainsaw.java deleted file mode 100644 index 92770f0a4..000000000 --- a/src/main/java/victor/training/cleancode/fp/FunctionalChainsaw.java +++ /dev/null @@ -1,31 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.RequiredArgsConstructor; -import victor.training.cleancode.fp.support.*; - -import java.time.LocalDate; -import java.util.List; -import java.util.Map.Entry; - -import static java.util.stream.Collectors.*; - -@RequiredArgsConstructor -public class FunctionalChainsaw/*Massacre*/ { - private final ProductRepo productRepo; - private final OrderRepo orderRepo; - - public List getHotProducts() { - return orderRepo.findAll().stream() - .filter(Order::isActive) - .filter(o -> o.creationDate().isAfter(LocalDate.now().minusMonths(1))) - .flatMap(o -> o.orderLines().stream()) - .collect(groupingBy(OrderLine::product, summingInt(OrderLine::itemCount))) - .entrySet() - .stream() - .filter(e -> e.getValue() >= 10) - .map(Entry::getKey) - .filter(p -> !p.isDeleted()) - .filter(p -> !productRepo.getHiddenProductIds().contains(p.getId())) - .collect(toList()); - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/LoanPattern.java b/src/main/java/victor/training/cleancode/fp/LoanPattern.java deleted file mode 100644 index 0e697bd1d..000000000 --- a/src/main/java/victor/training/cleancode/fp/LoanPattern.java +++ /dev/null @@ -1,51 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.RequiredArgsConstructor; -import org.jooq.lambda.Unchecked; -import victor.training.cleancode.fp.support.OrderRepo; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; - -@RequiredArgsConstructor -class FileExportService { - private final OrderRepo orderRepo; - - public void exportOrders() throws IOException { - File file = new File("target/orders.csv"); - System.out.println("Starting export into {} ... " + file.getAbsolutePath()); - long t0 = System.currentTimeMillis(); - try (Writer writer = new FileWriter(file)) { - - writer.write("order_id;date\n"); - orderRepo.findByActiveTrue() - .map(o -> o.id() + ";" + o.creationDate() + "\n") - .forEach(Unchecked.consumer(writer::write)); - - System.out.println("Export DONE"); - } catch (Exception e) { - System.out.println("Export FAILED: " + e); // TERROR-Driven Development - // imagine... sendErrorEmail(e); - throw e; - } finally { - long t1 = System.currentTimeMillis(); - System.out.println("Export completed in seconds: " + (t1 - t0) / 1000); - } - } -} - - -@RequiredArgsConstructor -public class LoanPattern { - private final FileExportService fileExporterService; - - public void exportOrders() throws IOException { - fileExporterService.exportOrders(); - } - - public void exportUsers() { - // TODO implement the export of users using *the same workflow* as for orders - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/LoanPattern_vsAOP.java b/src/main/java/victor/training/cleancode/fp/LoanPattern_vsAOP.java deleted file mode 100644 index e3c1b5a64..000000000 --- a/src/main/java/victor/training/cleancode/fp/LoanPattern_vsAOP.java +++ /dev/null @@ -1,23 +0,0 @@ -package victor.training.cleancode.fp; - -import java.util.function.Supplier; - -public class LoanPattern_vsAOP { - - public static void main(String[] args) { - timeIt(() -> suspect()); - } - - public static int suspect() { - System.out.println("Stuff"); - return 1; - } - - public static T timeIt(Supplier f) { - long t0 = System.currentTimeMillis(); - T r = f.get(); - long t1 = System.currentTimeMillis(); - System.out.println("Collect metric: " + (t1 - t0)); - return r; - } -} diff --git a/src/main/java/victor/training/cleancode/fp/MonadicError.java b/src/main/java/victor/training/cleancode/fp/MonadicError.java deleted file mode 100644 index b4a14b158..000000000 --- a/src/main/java/victor/training/cleancode/fp/MonadicError.java +++ /dev/null @@ -1,32 +0,0 @@ -package victor.training.cleancode.fp; - -public class MonadicError { - public Long tryingToDoStuff(String payload) { - var request = process(payload); - Long id = insert(request); - audit(request); - return id; - // TODO plot twist: bulk processing - } - - private String process(String payload) { - if (payload == null || payload.isBlank()) { - throw new IllegalArgumentException("Invalid payload"); - } - if (payload.contains("Analytica")) { - // FIXME: "It's not FP to throw exceptions!", the preacher said - throw new IllegalArgumentException("Banned Business"); - } - return payload.trim().toUpperCase(); - } - - private Long insert(String data) { - if (Math.random() < .001) throw new IllegalArgumentException("UK Violation: NULL tea"); - return 42L; // the new ID - } - - private void audit(String s) { - // pretend kafka.send - //throw new RuntimeException("Kafka is down; #life"); // imagine - } -} diff --git a/src/main/java/victor/training/cleancode/fp/MonadicErrorEnd.java b/src/main/java/victor/training/cleancode/fp/MonadicErrorEnd.java deleted file mode 100644 index c32534d06..000000000 --- a/src/main/java/victor/training/cleancode/fp/MonadicErrorEnd.java +++ /dev/null @@ -1,38 +0,0 @@ -package victor.training.cleancode.fp; - -import io.vavr.Tuple2; -import io.vavr.control.Try; - - -public class MonadicErrorEnd { - public Try tryingToDoStuff(String payload) { - return process(payload) - .flatMap(data -> insert(data).map(id -> new Tuple2<>(data, id)) - .andThen(s -> audit(s._1)) - .map(Tuple2::_2)); - } - - private Try process(String payload) { - if (payload == null || payload.isBlank()) { - return Try.failure(new IllegalArgumentException("Invalid payload")); - } - if (payload.contains("Analytica")) { - // FIXME: "It's not FP to throw exceptions!", the preacher said - return Try.failure(new IllegalArgumentException("Banned Business")); - } - return Try.success(payload.trim().toUpperCase()); - } - - private Try insert(String data) { - return Try.of(() -> { - if (Math.random() < .001) throw new IllegalArgumentException("UK Violation: NULL tea"); - return 42L; // the new ID - }); - } - - private void audit(String s) { - // pretend kafka.send - //throw new RuntimeException("Kafka is down; #life"); // imagine - } -} - diff --git a/src/main/java/victor/training/cleancode/fp/MutantPipeline.java b/src/main/java/victor/training/cleancode/fp/MutantPipeline.java deleted file mode 100644 index 76a7bcc69..000000000 --- a/src/main/java/victor/training/cleancode/fp/MutantPipeline.java +++ /dev/null @@ -1,50 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.RequiredArgsConstructor; -import victor.training.cleancode.fp.support.Order; -import victor.training.cleancode.fp.support.PaymentCardDto; -import victor.training.cleancode.fp.support.PaymentCardMapper; -import victor.training.cleancode.fp.support.PaymentCardRepository; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; - -@RequiredArgsConstructor -public class MutantPipeline { - //region .setField( - private final PaymentCardRepository paymentCardRepository; - //endregion - - //region .add - public List getShipDates(List orders) { - List shipDates = new ArrayList<>(); - orders.stream() - .filter(Order::isActive) - .forEach(order -> order.shipDate().ifPresent(shipDates::add)); - return shipDates; - } - //endregion - private final PaymentCardMapper paymentCardMapper; - - //region += - public int totalActiveOrderPrice(List orders) { - int sum = 0; - for (Order order : orders) { - if (order.isActive()) { - sum += order.price(); - } - } - return sum; - } - public PaymentCardDto updateCardAlias(long paymentCardId, long ssoId, String newAlias) { - return paymentCardRepository.findById(paymentCardId) - .filter(card -> card.getId() == ssoId) - .map(card -> { - card.setAlias(newAlias); - return paymentCardMapper.toDto(paymentCardRepository.save(card)); - }) - .orElseThrow(() -> new IllegalArgumentException("Card " + paymentCardId + " with sso " + ssoId + " cannot be found")); - } - //endregion -} diff --git a/src/main/java/victor/training/cleancode/fp/OptionalAbuse.java b/src/main/java/victor/training/cleancode/fp/OptionalAbuse.java deleted file mode 100644 index bd38304d1..000000000 --- a/src/main/java/victor/training/cleancode/fp/OptionalAbuse.java +++ /dev/null @@ -1,32 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.Data; - -import java.util.Optional; - -public class OptionalAbuse { - public Entity trappedOptional(Dto dto) { - Entity entity = new Entity(); - Optional.ofNullable(dto) - .map(Dto::recipientPerson) - .map(String::trim) - .map(String::toLowerCase) - .filter(s -> !s.isBlank()) - .map(s -> s + "@example.com") - .ifPresentOrElse( - email -> entity.setRecipient(email), - () -> entity.setRecipient("anonymous@example.com") - ); - entity.setAge(dto.age()); - return entity; - } - - public record Dto(String recipientPerson, int age) { - } - - @Data - public static class Entity { - private String recipient; - private int age; - } -} diff --git a/src/main/java/victor/training/cleancode/fp/PureFunction.java b/src/main/java/victor/training/cleancode/fp/PureFunction.java deleted file mode 100644 index c05dac8b4..000000000 --- a/src/main/java/victor/training/cleancode/fp/PureFunction.java +++ /dev/null @@ -1,45 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.RequiredArgsConstructor; -import victor.training.cleancode.fp.support.*; -import victor.training.cleancode.fp.support.Product; -import victor.training.cleancode.fp.support.ProductRepo; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@RequiredArgsConstructor -class PureFunction { - private final CustomerRepo customerRepo; - private final ThirdPartyPricesApi thirdPartyPricesApi; - private final CouponRepo couponRepo; - private final ProductRepo productRepo; - - // TODO extract complexity into a pure function - public Map computePrices(long customerId, List productIds, Map internalPrices) { - Customer customer = customerRepo.findById(customerId); - List products = productRepo.findAllById(productIds); - - List usedCoupons = new ArrayList<>(); - Map finalPrices = new HashMap<>(); - for (Product product : products) { - Double price = internalPrices.get(product.getId()); - if (price == null) { - price = thirdPartyPricesApi.fetchPrice(product.getId()); - } - for (Coupon coupon : customer.coupons()) { - if (coupon.autoApply() && coupon.isApplicableFor(product) && !usedCoupons.contains(coupon)) { - price = coupon.apply(product, price); - usedCoupons.add(coupon); - } - } - finalPrices.put(product.getId(), price); - } - - couponRepo.markUsedCoupons(customerId, usedCoupons); - return finalPrices; - } -} - diff --git a/src/main/java/victor/training/cleancode/fp/ReduceAbuse.java b/src/main/java/victor/training/cleancode/fp/ReduceAbuse.java deleted file mode 100644 index 97cfd51b8..000000000 --- a/src/main/java/victor/training/cleancode/fp/ReduceAbuse.java +++ /dev/null @@ -1,14 +0,0 @@ -package victor.training.cleancode.fp; - -import victor.training.cleancode.fp.support.Order; - -import java.util.List; - -public class ReduceAbuse { - public Order getLastPremiumOrder(List orders) { - return orders.stream().reduce(null, (prev, order) -> - order.orderLines().stream().anyMatch(line -> line.product().isPremium()) && - (prev == null || order.creationDate().isAfter(prev.creationDate())) ? order : prev - ); - } -} diff --git a/src/main/java/victor/training/cleancode/fp/ReduceAbuse2.java b/src/main/java/victor/training/cleancode/fp/ReduceAbuse2.java deleted file mode 100644 index 266acfd5f..000000000 --- a/src/main/java/victor/training/cleancode/fp/ReduceAbuse2.java +++ /dev/null @@ -1,14 +0,0 @@ -package victor.training.cleancode.fp; - -import victor.training.cleancode.fp.support.Order; - -import java.util.List; - -public class ReduceAbuse2 { - public Order getLastShippingDate(List orders) { - return orders.stream().reduce(null, (prev, order) -> - order.shipDate().isPresent() && - (prev == null || order.shipDate().get().isAfter(prev.shipDate().get())) ? order : prev - ); - } -} diff --git a/src/main/java/victor/training/cleancode/fp/TODO.java b/src/main/java/victor/training/cleancode/fp/TODO.java deleted file mode 100644 index 497c21443..000000000 --- a/src/main/java/victor/training/cleancode/fp/TODO.java +++ /dev/null @@ -1,30 +0,0 @@ -package victor.training.cleancode.fp; - -public class TODO { -//private void cancelOrRejectExtension(AppleNotificationPayload payload) { -// List contractDetailsList = payload.getContractList().stream() -// .map(contract -> { -// String contractId = contract.getContractID(); -// String systemName = contract.getSystemName(); -// String networkNodeId = payload.getNetworkNodeId(); -// String customerNo = appleRepository.getCustomerNo(contractId, systemName); -// List changeIds = appleRepository.getFtthServiceOrderChangeId(contractId, systemName, networkNodeId); -// ContractDetails details = new ContractDetails(); -// details.setCustomerName(appleRepository.getCustomerName(customerNo)); -// details.setCustomerNo(customerNo); -// details.setMsisdnDest(appleRepository.getDealerMsisdn(contractId, systemName)); -// details.setChangeIds(changeIds); -// appleRepository.cancelChange(changeIds); -// appleRepository.cancelChangeItem(changeIds); -// return details; -// }) -// .collect(Collectors.toList()); -// -// contractDetailsList.forEach(details -> { -// for (String changeId : details.getChangeIds()) { -// String smsMessage = String.format(MESSAGE_TO_BE_SENT, changeId, details.getCustomerName(), details.getCustomerNo()); -// sendSmsRepository.sendSms(details.getMsisdnDest(), smsMessage); -// } -// }); -} - diff --git a/src/main/java/victor/training/cleancode/fp/TangledTuples.java b/src/main/java/victor/training/cleancode/fp/TangledTuples.java deleted file mode 100644 index 89e6a166a..000000000 --- a/src/main/java/victor/training/cleancode/fp/TangledTuples.java +++ /dev/null @@ -1,47 +0,0 @@ -package victor.training.cleancode.fp; - -import lombok.RequiredArgsConstructor; -import reactor.core.publisher.Mono; - -@RequiredArgsConstructor -public class TangledTuples { - - protected final Api api; - - public Mono reactiveEnrich(int id) { - // blocking⛔️ code: - var a = api.a(id).block(); - var b = api.b(a).block(); - var c = api.c(a, b).block(); - var d = api.d(id).block(); - return Mono.just(new ACD(a, c, d)); - -// var ftw = api.d(id).zipWith( -// api.a(id) -// .flatMap(a -> api.b(a) -// .flatMap(b -> api.c(a, b) -// .map(c -> Tuples.of(a, b, c)) -// ))); -// return ftw; - } - - protected interface Api { - Mono a(int id); - Mono b(A a); - Mono c(A a, B b); - Mono d(int id); - } - - //region support code - public record A() {} - - public record B() {} - - public record C() {} - - public record D() {} - - public record ACD(A a, C c, D d) {} - //endregion - -} diff --git a/src/main/java/victor/training/cleancode/fp/support/Coupon.java b/src/main/java/victor/training/cleancode/fp/support/Coupon.java deleted file mode 100644 index d9f784024..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/Coupon.java +++ /dev/null @@ -1,35 +0,0 @@ -package victor.training.cleancode.fp.support; - -import lombok.EqualsAndHashCode; - -@EqualsAndHashCode -public -class Coupon { - private final ProductCategory category; - private final int discountAmount; - private boolean autoApply = true; - - public Coupon(ProductCategory category, int discountAmount) { - this.category = category; - this.discountAmount = discountAmount; - } - - public boolean autoApply() { - return autoApply; - } - - public void setAutoApply(boolean autoApply) { - this.autoApply = autoApply; - } - - public boolean isApplicableFor(Product product) { - return (product.getCategory() == category || category == null) && !product.isPremium(); - } - - public Double apply(Product product, Double price) { - if (!isApplicableFor(product)) { - throw new IllegalArgumentException(); - } - return price - discountAmount; - } -} diff --git a/src/main/java/victor/training/cleancode/fp/support/CouponRepo.java b/src/main/java/victor/training/cleancode/fp/support/CouponRepo.java deleted file mode 100644 index ea292d8f8..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/CouponRepo.java +++ /dev/null @@ -1,7 +0,0 @@ -package victor.training.cleancode.fp.support; - -import java.util.List; - -public interface CouponRepo { - void markUsedCoupons(long customerId, List usedCoupons); -} diff --git a/src/main/java/victor/training/cleancode/fp/support/Customer.java b/src/main/java/victor/training/cleancode/fp/support/Customer.java deleted file mode 100644 index c21d200e9..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/Customer.java +++ /dev/null @@ -1,8 +0,0 @@ -package victor.training.cleancode.fp.support; - -import lombok.Value; - -import java.util.List; - -public record Customer(List coupons) { -} diff --git a/src/main/java/victor/training/cleancode/fp/support/CustomerRepo.java b/src/main/java/victor/training/cleancode/fp/support/CustomerRepo.java deleted file mode 100644 index 7da50d922..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/CustomerRepo.java +++ /dev/null @@ -1,8 +0,0 @@ -package victor.training.cleancode.fp.support; - -public interface CustomerRepo { - Customer findById(long customerId); - int countByEmail(String email); - - Long save(Customer customer); -} diff --git a/src/main/java/victor/training/cleancode/fp/support/Order.java b/src/main/java/victor/training/cleancode/fp/support/Order.java deleted file mode 100644 index 887a6f318..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/Order.java +++ /dev/null @@ -1,69 +0,0 @@ -package victor.training.cleancode.fp.support; - -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; - -public class Order { - private Long id; - private List orderLines = List.of(); - private LocalDate creationDate; - private LocalDate shipDate; - private boolean active; - private int price; - - public Long id() { - return id; - } - - public List orderLines() { - return orderLines; - } - - public LocalDate creationDate() { - return creationDate; - } - - public Optional shipDate() { - return Optional.ofNullable(shipDate); - } - - public boolean isActive() { - return active; - } - - public int price() { - return price; - } - - public Order setId(Long id) { - this.id = id; - return this; - } - - public Order setOrderLines(List orderLines) { - this.orderLines = orderLines; - return this; - } - - public Order setCreationDate(LocalDate creationDate) { - this.creationDate = creationDate; - return this; - } - - public Order setShipDate(LocalDate shipDate) { - this.shipDate = shipDate; - return this; - } - - public Order setActive(boolean active) { - this.active = active; - return this; - } - - public Order setPrice(int price) { - this.price = price; - return this; - } - -} diff --git a/src/main/java/victor/training/cleancode/fp/support/OrderLine.java b/src/main/java/victor/training/cleancode/fp/support/OrderLine.java deleted file mode 100644 index 8258a48e9..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/OrderLine.java +++ /dev/null @@ -1,6 +0,0 @@ -package victor.training.cleancode.fp.support; - -import lombok.Value; - -public record OrderLine(Product product, int itemCount) { -} diff --git a/src/main/java/victor/training/cleancode/fp/support/OrderRepo.java b/src/main/java/victor/training/cleancode/fp/support/OrderRepo.java deleted file mode 100644 index cb9d34324..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/OrderRepo.java +++ /dev/null @@ -1,12 +0,0 @@ -package victor.training.cleancode.fp.support; - - -import java.time.LocalDate; -import java.util.List; -import java.util.stream.Stream; - -public interface OrderRepo { - List findAll(); - List findByActiveTrueAndCreationDateAfter(LocalDate date); - Stream findByActiveTrue(); -} diff --git a/src/main/java/victor/training/cleancode/fp/support/PaymentCard.java b/src/main/java/victor/training/cleancode/fp/support/PaymentCard.java deleted file mode 100644 index 275f93fc7..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/PaymentCard.java +++ /dev/null @@ -1,10 +0,0 @@ -package victor.training.cleancode.fp.support; - -import lombok.Data; - -@Data -public class PaymentCard { - long id; - String alias; - // more fields -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/support/PaymentCardDto.java b/src/main/java/victor/training/cleancode/fp/support/PaymentCardDto.java deleted file mode 100644 index c206197e7..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/PaymentCardDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package victor.training.cleancode.fp.support; - -public record PaymentCardDto(long id, String alias) { -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/support/PaymentCardMapper.java b/src/main/java/victor/training/cleancode/fp/support/PaymentCardMapper.java deleted file mode 100644 index a12fbf368..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/PaymentCardMapper.java +++ /dev/null @@ -1,7 +0,0 @@ -package victor.training.cleancode.fp.support; - -public class PaymentCardMapper { - public PaymentCardDto toDto(PaymentCard card) { - return new PaymentCardDto(card.getId(), card.getAlias()); - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/support/PaymentCardRepository.java b/src/main/java/victor/training/cleancode/fp/support/PaymentCardRepository.java deleted file mode 100644 index 470eb2fff..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/PaymentCardRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package victor.training.cleancode.fp.support; - -import java.util.Optional; - -public interface PaymentCardRepository { - Optional findById(long paymentCardId); - - PaymentCard save(PaymentCard card); -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/fp/support/Product.java b/src/main/java/victor/training/cleancode/fp/support/Product.java deleted file mode 100644 index adf68afeb..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/Product.java +++ /dev/null @@ -1,51 +0,0 @@ -package victor.training.cleancode.fp.support; - -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; - -import java.beans.Transient; -import java.time.LocalDateTime; - -@Getter -@Setter -@ToString -public -class Product { - - private Long id; - - private String name; - - private ProductCategory category; - - private LocalDateTime createDate; - private boolean premium; - private boolean deleted; - -// @Transient -// transient double tempraryPrice; - - - public Product(String name, ProductCategory category) { - this.name = name; - this.category = category; - } - - public Product(String name) { - this.name = name; - } - - public Product() { - } - - - public boolean isPremium() { - return premium; - } - - public Product setPremium(boolean premium) { - this.premium = premium; - return this; - } -} diff --git a/src/main/java/victor/training/cleancode/fp/support/ProductCategory.java b/src/main/java/victor/training/cleancode/fp/support/ProductCategory.java deleted file mode 100644 index 0a6acdc62..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/ProductCategory.java +++ /dev/null @@ -1,5 +0,0 @@ -package victor.training.cleancode.fp.support; - -public enum ProductCategory { - ELECTRONICS, KIDS, ME, HOME, UNCATEGORIZED -} diff --git a/src/main/java/victor/training/cleancode/fp/support/ProductRepo.java b/src/main/java/victor/training/cleancode/fp/support/ProductRepo.java deleted file mode 100644 index 8b5db53c9..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/ProductRepo.java +++ /dev/null @@ -1,9 +0,0 @@ -package victor.training.cleancode.fp.support; - - -import java.util.List; - -public interface ProductRepo { - List getHiddenProductIds(); - List findAllById(List productIds); -} diff --git a/src/main/java/victor/training/cleancode/fp/support/ThirdPartyPricesApi.java b/src/main/java/victor/training/cleancode/fp/support/ThirdPartyPricesApi.java deleted file mode 100644 index 38c972893..000000000 --- a/src/main/java/victor/training/cleancode/fp/support/ThirdPartyPricesApi.java +++ /dev/null @@ -1,5 +0,0 @@ -package victor.training.cleancode.fp.support; - -public interface ThirdPartyPricesApi { - double fetchPrice(Long id); -} diff --git a/src/main/java/victor/training/cleancode/immutable/LostInSet.java b/src/main/java/victor/training/cleancode/immutable/LostInSet.java deleted file mode 100644 index e0b103874..000000000 --- a/src/main/java/victor/training/cleancode/immutable/LostInSet.java +++ /dev/null @@ -1,47 +0,0 @@ -package victor.training.cleancode.immutable; - -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -public class LostInSet { - public static void main(String[] args) { - // UC-123: Loosing you child at the Mall - Set set = new HashSet<>(); - - Child childOne = new Child("Emma"); - set.add(childOne); - - System.out.println(set.contains(childOne)); - } -} - - -class Child { - private String name; - - public Child(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Child child = (Child) o; - return Objects.equals(name, child.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/immutable/RefactorToImmutable.java b/src/main/java/victor/training/cleancode/immutable/RefactorToImmutable.java deleted file mode 100644 index 818699d3c..000000000 --- a/src/main/java/victor/training/cleancode/immutable/RefactorToImmutable.java +++ /dev/null @@ -1,75 +0,0 @@ -package victor.training.cleancode.immutable; - -import java.math.BigDecimal; - - -class PriceService { - private final SupplierService supplierService; - private final LogisticsService logisticsService; - - PriceService(SupplierService supplierService, LogisticsService logisticsService) { - this.supplierService = supplierService; - this.logisticsService = logisticsService; - } - // see tests - public void computePrice(Product product) { - BigDecimal cost = supplierService.getCost(product.getSupplierId(), product.getId()); - BigDecimal deliveryCosts = logisticsService.estimateDeliveryCosts(product.getSupplierId()); - - product.setPrice(cost.add(deliveryCosts)); - - // @see PriceServiceTest - applySupplierDiscount(product); // -20% - applyDeliveryDiscount(product); // - 2 EUR - } - - private void applySupplierDiscount(Product product) { - System.out.println("200 lines of criminally complex logic using " + product.getSupplierId() + " " + product.getId() + " and " + product.getCategory()); - BigDecimal discountRate = BigDecimal.valueOf(0.2); - product.setPrice(product.getPrice().multiply(BigDecimal.ONE.subtract(discountRate))); - } - - private void applyDeliveryDiscount(Product product) { - System.out.println("40 bugs and changes over the past year here" + product.getSupplierId() + " " + product.getId()); - BigDecimal discount = BigDecimal.valueOf(2); - product.setPrice(product.getPrice().subtract(discount)); - } -} - -class Product { - private Long id; - private Long supplierId; - private BigDecimal price; - private Category category; - - public enum Category { - HOME, - ELECTRONICS - } - - public Long getId() { - return id; - } - - public Long getSupplierId() { - return supplierId; - } - - public Category getCategory() { - return category; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - public BigDecimal getPrice() { - return price; - } -} -interface SupplierService { - BigDecimal getCost(Long supplierId, Long productId); // out of scope -} -interface LogisticsService { - BigDecimal estimateDeliveryCosts(Long supplierId); -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/immutable/advanced/ImmutableAdvanced.java b/src/main/java/victor/training/cleancode/immutable/advanced/ImmutableAdvanced.java deleted file mode 100644 index caa7c992e..000000000 --- a/src/main/java/victor/training/cleancode/immutable/advanced/ImmutableAdvanced.java +++ /dev/null @@ -1,74 +0,0 @@ -package victor.training.cleancode.immutable.advanced; - -import java.util.List; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.toList; - -public class ImmutableAdvanced { - public static void main(String[] args) { - List list = Stream.of(1, 2, 3).collect(toList()); // ArrayList - - Immutable immutable = new Immutable(1, 2, list, new Other(15)); - System.out.println("Before: " + immutable); - - wilderness(immutable); - - System.out.println("After: " + immutable); - } - - private static void wilderness(Immutable immutable) { - // dark, deep logic not expected to change the immutable object x,y - } -} - -class Immutable { - private final Integer x; - private final Integer y; - private final List list; - private final Other other; - - Immutable(Integer x, Integer y, List list, Other other) { - this.x = x; - this.y = y; - this.list = list; - this.other = other; - } - - public List getList() { - return list; - } - - public Integer getX() { - return x; - } - - public Integer getY() { - return y; - } - - public Other getOther() { - return other; - } - - @Override - public String toString() { - return "Immutable{x=%d, y=%d, numbers=%s, other=%s}".formatted(x, y, list, other); - } -} - -class Other { - private int a; - - public Other(int a) { - this.a = a; - } - - public int getA() { - return a; - } - - public void setA(int a) { - this.a = a; - } -} diff --git a/src/main/java/victor/training/cleancode/immutable/basic/ImmutableBasic.java b/src/main/java/victor/training/cleancode/immutable/basic/ImmutableBasic.java deleted file mode 100644 index 4aba68f68..000000000 --- a/src/main/java/victor/training/cleancode/immutable/basic/ImmutableBasic.java +++ /dev/null @@ -1,51 +0,0 @@ -package victor.training.cleancode.immutable.basic; - -import java.util.List; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.toList; - -public class ImmutableBasic { - public static void main(String[] args) { - List list = Stream.of(1, 2, 3, 4, 5).collect(toList()); - - Immutable immutable = new Immutable(); - - immutable.x = 2; - immutable.list = list; - immutable.other = new Other(13); - - System.out.println(immutable); - - // LOTS OF BUSINESS LOGIC HERE - - System.out.println(immutable.list); - System.out.println(immutable); - } -} - -class Immutable { - public Integer x; - public List list; - public Other other; - - public String toString() { - return String.format("Immutable{x=%d, numbers=%s, other=%s}", x, list, other); - } -} - -class Other { - private int a; - - public Other(int a) { - this.a = a; - } - - public int getA() { - return a; - } - - public void setA(int a) { - this.a = a; - } -} diff --git a/src/main/java/victor/training/cleancode/immutable/tracing/ImmutableTracing.java b/src/main/java/victor/training/cleancode/immutable/tracing/ImmutableTracing.java deleted file mode 100644 index ec88ffa68..000000000 --- a/src/main/java/victor/training/cleancode/immutable/tracing/ImmutableTracing.java +++ /dev/null @@ -1,55 +0,0 @@ -package victor.training.cleancode.immutable.tracing; - -public class ImmutableTracing { - static class Data { - private final int x; - - public Data(int x) { - this.x = x; - } - - public int getX() { - return x; - } - - public Data withX(int newX) { - return new Data(newX); - } - } - - public static void main(String[] args) { - h(); - } - - public static void h() { - Data data = new Data(1); - // more code - g(data); - } - - public static void g(Data data) { - data = data.withX(2); - // more code - data = evil(data); - // more code - f(data); - } - - public static void f(Data data) { - if (data.getX() == 1) { - System.out.println("Launch missile"); - } - } - - private static Data evil(Data data) { - return deeperEvil(data); - } - - private static Data deeperEvil(Data data) { - return data.withX(3); - } - - - -} - diff --git a/src/main/java/victor/training/cleancode/immutable/tracing/MutableTracing.java b/src/main/java/victor/training/cleancode/immutable/tracing/MutableTracing.java deleted file mode 100644 index e5d58679b..000000000 --- a/src/main/java/victor/training/cleancode/immutable/tracing/MutableTracing.java +++ /dev/null @@ -1,52 +0,0 @@ -package victor.training.cleancode.immutable.tracing; - -public class MutableTracing { - static class Data { - private int x; - - public int getX() { - return x; - } - - public void setX(int x) { - this.x = x; - } - } - - public static void main(String[] args) { - h(); - } - - public static void h() { - Data data = new Data(); - data.setX(1); - // more code - g(data); - } - - public static void g(Data data) { - data.setX(2); - // more code - evil(data); - // more code - f(data); - } - - public static void f(Data data) { - if (data.getX() == 1) { - System.out.println("Launch missile"); - } - } - - private static void evil(Data data) { - deeperEvil(data); - } - - private static void deeperEvil(Data data) { - data.setX(3); - } - - - -} - diff --git a/src/main/java/victor/training/cleancode/kata/expense/Expense.java b/src/main/java/victor/training/cleancode/kata/expense/Expense.java deleted file mode 100644 index a7c13ad91..000000000 --- a/src/main/java/victor/training/cleancode/kata/expense/Expense.java +++ /dev/null @@ -1,10 +0,0 @@ -package victor.training.cleancode.kata.expense; - -public class Expense { - String type; - int amount; - public Expense(String type, int amount) { - this.type = type; - this.amount = amount; - } -} diff --git a/src/main/java/victor/training/cleancode/kata/expense/ExpenseReport.java b/src/main/java/victor/training/cleancode/kata/expense/ExpenseReport.java deleted file mode 100644 index b03de6436..000000000 --- a/src/main/java/victor/training/cleancode/kata/expense/ExpenseReport.java +++ /dev/null @@ -1,47 +0,0 @@ -package victor.training.cleancode.kata.expense; - -import java.util.Date; -import java.util.List; - -public class ExpenseReport { - public void printReport(List expenses) { - int total = 0; - int mealExpenses = 0; - boolean mealOver = false; - - System.out.println("Expenses Report"); - - for (Expense expense : expenses) { - if (expense.type.equals("DINNER") || expense.type.equals("BREAKFAST")) { - mealExpenses += expense.amount; - } - - String en = null; - switch (expense.type) { - case "DINNER": - en = "Dinner"; - break; - case "BREAKFAST": - en = "Breakfast"; - break; - case "CAR_RENTAL": - en = "Car Rental"; - break; - } - - // meal over expenses - String m = expense.type.equals("DINNER") && expense.amount > 5000 || expense.type.equals("BREAKFAST") && expense.amount > 1000 ? "X" : " "; - mealOver |= m.equals("X"); - - System.out.println(en + "\t" + expense.amount + "\t" + m); - - total += expense.amount; - } - - System.out.println("Meal expenses: " + mealExpenses); - System.out.println("Total expenses: " + total); - if (mealOver) { - System.out.println("Meal expenses exceed limit"); - } - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentFileService.java b/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentFileService.java deleted file mode 100644 index c2fe98ec8..000000000 --- a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentFileService.java +++ /dev/null @@ -1,41 +0,0 @@ -package victor.training.cleancode.kata.funcfusion; - -import io.vavr.control.Try; - -import java.io.*; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class PaymentFileService { - private final String folderPath; - - public PaymentFileService(String folderPath) { - this.folderPath = folderPath; - } - - private Try> fileNames() { - return Try.of(() -> new File(folderPath).listFiles()) - .map(files -> Set.of(files).stream().map(File::getName).collect(Collectors.toSet())); - } - - public Stream> streamFiles() { - return fileNames().get().stream() - .map(name -> openFile(name) - .of(is -> readFile(name, is) - .recoverWith(ex -> Try.failure(new RuntimeException("Throw some runtime exception here")))) - .flatMap(Function.identity())); - } - - private Try readFile(String fileName, InputStream inputStream) { - return Try.of (() -> { - Stream lines = new BufferedReader(new InputStreamReader(inputStream)).lines(); - return new PaymentsFile(fileName, lines.toList()); - }); - } - - private Try.WithResources1 openFile(final String fileName) { - return Try.withResources(() -> new FileInputStream(new File(folderPath + "/" + fileName))); - } -} diff --git a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentProcessor.java b/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentProcessor.java deleted file mode 100644 index b00777e11..000000000 --- a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentProcessor.java +++ /dev/null @@ -1,86 +0,0 @@ -package victor.training.cleancode.kata.funcfusion; - -import io.vavr.Tuple; -import io.vavr.control.Try; - -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class PaymentProcessor { - private final PaymentFileService paymentFileService; - private final ExecutorService executorService; - - public PaymentProcessor(PaymentFileService paymentFileService, ExecutorService executorService) { - this.paymentFileService = paymentFileService; - this.executorService = executorService; - } - - public void processAllFiles() { - paymentFileService.streamFiles() - .flatMap(t -> streamTryResult(t, throwable -> logError("Cannot parse file", throwable))) - .map(file -> Try.of(() -> loadMetadata(file))) - .flatMap(fm -> streamTryResult(fm, ex -> logError("Cannot read file metadata", ex))) - .map(wrapped -> Tuple.of(wrapped, process(wrapped))) - .filter(tuple -> tuple._2().isFailure()) - .forEach(tuple -> logError("Cannot process: %s".formatted(tuple._1.paymentsFile().fileName()), tuple._2.getCause())); - } - - private Stream streamTryResult(Try t, Consumer failure) { - return t.map(Stream::of).getOrElseGet(throwable -> { - failure.accept(throwable); - return Stream.empty(); - }); - } - - private Try process(FileWithMetadata wrapped) { - return Try.of(() -> { - System.out.println("Insert in DB: " + wrapped); - Set results = executorService.invokeAll(toCallable(wrapped)) - .stream() - .map(tFuture -> Try.of(tFuture::get) - .onFailure(throwable -> logError("Worker failed", throwable)) - .toJavaOptional()) - .flatMap(Optional::stream) - .collect(Collectors.toSet()); - - results.stream().map(Result::cleanup).forEach(Runnable::run); - - if (results.stream().allMatch(Result::success)) { - System.out.println("Payment file processed successfully: " + wrapped.paymentsFile().fileName()); - } - return wrapped.paymentsFile().fileName(); - }); - } - - private Set> toCallable(FileWithMetadata wrapped) { - return null; - } - - private FileWithMetadata loadMetadata(PaymentsFile paymentsFile) { - if (paymentsFile.payments().size() == 0) { - throw new IllegalArgumentException("Empty file"); - } - if (paymentsFile.payments().size() > 1000) { - throw new IllegalArgumentException("Too many payments"); - } - return new FileWithMetadata(paymentsFile, paymentsFile.payments().size()); - } - - record FileWithMetadata(PaymentsFile paymentsFile, int size) { - } - - - private void logError(String someErrorMessage, Throwable throwable) { - System.out.println(someErrorMessage + ": " + throwable); - } - - - record Result(boolean success, Runnable cleanup) { - } -} - diff --git a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentsFile.java b/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentsFile.java deleted file mode 100644 index 6bc3b6ffe..000000000 --- a/src/main/java/victor/training/cleancode/kata/funcfusion/PaymentsFile.java +++ /dev/null @@ -1,6 +0,0 @@ -package victor.training.cleancode.kata.funcfusion; - -import java.util.List; - -public record PaymentsFile(String fileName, List payments) { -} diff --git a/src/main/java/victor/training/cleancode/kata/povalidator/POValidator.java b/src/main/java/victor/training/cleancode/kata/povalidator/POValidator.java deleted file mode 100644 index 855eb70bd..000000000 --- a/src/main/java/victor/training/cleancode/kata/povalidator/POValidator.java +++ /dev/null @@ -1,108 +0,0 @@ -package victor.training.cleancode.kata.povalidator; - - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public class POValidator { - private List validators; - - public void setValidators(List validators) { - this.validators = validators; - } - - public boolean validatePurchaseOrderItem(POItem poItem) { - var result = new AtomicBoolean(Boolean.TRUE); - - validators.stream() - .takeWhile(v -> result.get()) - .forEach(v -> { - if (!v.validate(poItem)) { - result.set(Boolean.FALSE); - System.err.println("PO id=" + poItem.getId() + " failed " + v.getClass().getName()); - var message = new POItemMessage(); - message.setType(SAPMessageType.ERROR); - message.setMessageClass(v.getClass().getSimpleName()); - message.setText(v.message(poItem)); - poItem.addMessage(message); - poItem.setStatus(POItem.Status.ERROR); - } - }); - return result.get(); - } -} - -// ========= SUPPORT CODE ======= - -class POItem { - enum Status {SUCCESS, ERROR, NEW} - - private Long id; - private Status status = Status.NEW; - private final List messages = new ArrayList<>(); - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public void setStatus(Status status) { - this.status = status; - } - - public Status getStatus() { - return status; - } - - public void addMessage(POItemMessage message) { - messages.add(message); - } - - public List getMessages() { - return messages; - } -} - -enum SAPMessageType {ERROR, INFO, WARN, MESSAGE} - -class POItemMessage { - private String messageClass; - private String text; - private SAPMessageType type; - - public void setMessageClass(String messageClass) { - this.messageClass = messageClass; - } - - public String getMessageClass() { - return messageClass; - } - - public void setText(String text) { - this.text = text; - } - - public String getText() { - return text; - } - - public void setType(SAPMessageType type) { - this.type = type; - } - - public SAPMessageType getType() { - return type; - } -} - -interface Validator { - - boolean validate(POItem purchaseOrderItem); - - String message(POItem purchaseOrderItem); -} - diff --git a/src/main/java/victor/training/cleancode/kata/streams/Exercises.java b/src/main/java/victor/training/cleancode/kata/streams/Exercises.java deleted file mode 100644 index f3c382ee8..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/Exercises.java +++ /dev/null @@ -1,240 +0,0 @@ -package victor.training.cleancode.kata.streams; - -import victor.training.cleancode.kata.streams.Order.PaymentMethod; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.time.Month; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static victor.training.cleancode.kata.streams.Order.Status.COMPLETED; - -public class Exercises { - private final OrderMapper orderMapper = new OrderMapper(); - - public List p1_activeOrders(List orders) { - // TODO 1: simplify - // TODO 2: use the OrderDto constructor - // TODO 3: use the OrderMapper.toDto method - List dtos = new ArrayList<>(); - for (Order order : orders) { - if (order.status() == COMPLETED) { - OrderDto dto = new OrderDto( - order.total(), - order.createdOn(), - order.paymentMethod(), - order.status()); - dtos.add(dto); - } - } - return dtos; - } - - public Order p2_findOrderById(List orders, int orderId) { - // TODO 1: rewrite with streams - // TODO 2: return Optional<> and fix the tests - for (Order order : orders) { - if (order.id() == orderId) { - return order; - } - } - return null; - } - - // TODO all the following: rewrite with streams - public boolean p3_hasActiveOrders(List orders) { - for (Order order : orders) { - if (order.status() == COMPLETED) { - return true; - } - } - return false; - } - - /** - * @return order with the max total() that does NOT contain a special offer line - */ - public Order p4_maxPriceOrder(List orders) { - Order maxOrder = null; - for (Order order : orders) { - boolean hasSpecialOffer = false; - for (OrderLine orderLine : order.orderLines()) { - if (orderLine.isSpecialOffer()) { - hasSpecialOffer = true; - break; - } - } - if (hasSpecialOffer) { - continue; - } - if (maxOrder == null || order.total() > maxOrder.total()) { - maxOrder = order; - } - } - return maxOrder; - } - - /** - * @return last 3 returnReason()s sorted descending by Order.createdOn - */ - public List p5_last3Orders(List orders) { - List copy = new ArrayList<>(orders); - copy.sort(new LatestOrderComparator()); - List returnReasons = new ArrayList<>(); - for (Order order : copy) { - if (order.returnReason().isPresent()) { - returnReasons.add(order.returnReason().get()); - if (returnReasons.size() == 3) { - break; - } - } - } - return returnReasons; - // Hint: Optional#stream() - } - - /** - * @return sum of all Order.total(), truncated to int. - */ - public int p6_completedTotalSum(List orders) { - double sum = 0; - for (Order order : orders) { - if (order.status() == COMPLETED) { - sum += order.total(); - } - } - return (int) sum; - } - - /** - * @return the products bought by the customer, with no duplicates, sorted by Product.name - */ - public List p7_productsSorted(List orders) { // TODO simplify - Set products = new HashSet<>(); - for (Order order : orders) { - for (OrderLine line : order.orderLines()) { - products.add(line.product()); - } - } - List sorted = new ArrayList<>(products); - sorted.sort((o1, o2) -> o1.name().compareTo(o2.name())); - return sorted; - } - - /** - * see tests for an example - */ - public Map> p8_ordersGroupedByPaymentMethod(List orders) { - Map> map = new HashMap<>(); - for (Order order : orders) { - List list = map.get(order.paymentMethod()); - if (list == null) { - list = new ArrayList<>(); - map.put(order.paymentMethod(), list); - } - list.add(order); - } - return map; - } - - /** - * @return the total number of products purchased across all orders (see test) - */ - public Map p9_productCount(List orders) { - List allLines = new ArrayList<>(); - for (Order order : orders) { - allLines.addAll(order.orderLines()); - } - Map result = new HashMap<>(); - for (OrderLine line : allLines) { - int old; - if (!result.containsKey(line.product())) { - result.put(line.product(), 0); - old = 0; - } else { - old = result.get(line.product()); - } - result.put(line.product(), old + line.count()); - } - return result; - } - - /** - * @return the names of all products from previous exercise, joined with a "," - */ - public String pA_productNames(List orders) { - List products = p7_productsSorted(orders); - StringBuilder sb = new StringBuilder(); - for (Product product : products) { - sb.append(product.name()).append(","); - } - sb.deleteCharAt(sb.length() - 1); // remove the last comma - return sb.toString(); - } - - /** - * @return orders grouped by Month, and then by PaymentMethod - */ - public Map>> pB_ordersByPaymentPerMonth(List orders) { - Map>> result = new HashMap<>(); - for (Order order : orders) { - Map> map = result.get(order.createdOn().getMonth()); - if (map == null) { - map = new HashMap<>(); - result.put(order.createdOn().getMonth(), map); - } - List list = map.get(order.paymentMethod()); - if (list == null) { - list = new ArrayList<>(); - map.put(order.paymentMethod(), list); - } - list.add(order); - } - return result; - } - - /** - * @return the first cell of a semicolon-separated file, as integers - */ - public Set pC_csvLinesInAllFilesInFolder(File file) throws IOException { - try (Stream lines = Files.lines(file.toPath())) { - return lines - .filter(s -> !s.isBlank()) - .map(line -> Integer.parseInt(line.split(";")[0])) - .collect(Collectors.toSet()); - } - } - - /** - * @return the elements in Fibonacci sequence between startIndex and endIndex - */ - public List pD_fib(int startIndex, int endIndex) { - List result = new ArrayList<>(); - int a = 1; - int b = 1; - int c = a + b; - int index = 0; - while (index < endIndex) { - if (index >= startIndex) { - result.add(a); - } - a = b; - b = c; - c = a + b; - index++; - } - return result; - - } - - static class LatestOrderComparator implements Comparator { - @Override - public int compare(Order o1, Order o2) { - return o2.createdOn().compareTo(o1.createdOn()); - } - } - -} diff --git a/src/main/java/victor/training/cleancode/kata/streams/Order.java b/src/main/java/victor/training/cleancode/kata/streams/Order.java deleted file mode 100644 index ec870b7e7..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/Order.java +++ /dev/null @@ -1,105 +0,0 @@ -package victor.training.cleancode.kata.streams; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static java.util.Optional.ofNullable; - -// DON'T REFACTOR THIS -class Order { - - private final List orderLines = new ArrayList<>(); - private Integer id; - private Status status; - private LocalDate createdOn; - private double total; - private PaymentMethod paymentMethod; - private String returnReason; - public Order() { - } - public Order(Status status) { - this.status = status; - } - - public Order(Integer id) { - this.id = id; - } - - public List orderLines() { - return orderLines; - } - - public Integer id() { - return id; - } - - public Status status() { - return status; - } - - public LocalDate createdOn() { - return createdOn; - } - - public Order createdOn(LocalDate creationDate) { - this.createdOn = creationDate; - return this; - } - - public double total() { - return total; - } - - public Order total(double total) { - this.total = total; - return this; - } - - public PaymentMethod paymentMethod() { - return paymentMethod; - } - - public Order paymentMethod(PaymentMethod paymentMethod) { - this.paymentMethod = paymentMethod; - return this; - } - - public Order add(OrderLine orderLine) { - orderLines.add(orderLine); - return this; - } - - public Order returnReason(String returnReason) { - this.returnReason = returnReason; - return this; - } - - public Optional returnReason() { - return ofNullable(returnReason); - } - - @Override - public String toString() { - return "Order{" + - "id=" + id + - ", status=" + status + - ", orderLines=" + orderLines + - ", createdOn=" + createdOn + - ", total=" + total + - ", paymentMethod=" + paymentMethod + - ", returnReason='" + returnReason + '\'' + - '}'; - } - - public enum Status { - PLACED, COMPLETED, CANCELLED - } - - public enum PaymentMethod { - CARD, - CASH_ON_SITE, - CASH_ON_DELIVERY - } -} diff --git a/src/main/java/victor/training/cleancode/kata/streams/OrderDto.java b/src/main/java/victor/training/cleancode/kata/streams/OrderDto.java deleted file mode 100644 index 274d237f2..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/OrderDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package victor.training.cleancode.kata.streams; - -import victor.training.cleancode.kata.streams.Order.PaymentMethod; -import victor.training.cleancode.kata.streams.Order.Status; - -import java.time.LocalDate; - -// DON'T REFACTOR THIS -record OrderDto(double totalPrice, - LocalDate creationDate, - PaymentMethod paymentMethod, - Status status) { - - public OrderDto(Order order) { - this(order.total(), - order.createdOn(), - order.paymentMethod(), - order.status()); - } -} diff --git a/src/main/java/victor/training/cleancode/kata/streams/OrderLine.java b/src/main/java/victor/training/cleancode/kata/streams/OrderLine.java deleted file mode 100644 index 396040882..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/OrderLine.java +++ /dev/null @@ -1,16 +0,0 @@ -package victor.training.cleancode.kata.streams; - -// DON'T REFACTOR THIS -public record OrderLine(Product product, int count, boolean isSpecialOffer) { - public OrderLine() { - this(new Product("dummy"), 0); - } - - public OrderLine(Product product, int items) { - this(product, items, false); - } - - public OrderLine specialOffer(boolean specialOffer) { - return new OrderLine(product, count, specialOffer); - } -} diff --git a/src/main/java/victor/training/cleancode/kata/streams/OrderMapper.java b/src/main/java/victor/training/cleancode/kata/streams/OrderMapper.java deleted file mode 100644 index 7472c4186..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/OrderMapper.java +++ /dev/null @@ -1,12 +0,0 @@ -package victor.training.cleancode.kata.streams; - -// DON'T REFACTOR THIS -public class OrderMapper { - public OrderDto toDto(Order order) { - return new OrderDto( - order.total(), - order.createdOn(), - order.paymentMethod(), - order.status()); - } -} diff --git a/src/main/java/victor/training/cleancode/kata/streams/Product.java b/src/main/java/victor/training/cleancode/kata/streams/Product.java deleted file mode 100644 index 307b668ca..000000000 --- a/src/main/java/victor/training/cleancode/kata/streams/Product.java +++ /dev/null @@ -1,4 +0,0 @@ -package victor.training.cleancode.kata.streams; - -public record Product(String name) { -} diff --git a/src/main/java/victor/training/cleancode/mass/BaseService.java b/src/main/java/victor/training/cleancode/mass/BaseService.java deleted file mode 100644 index 9348045c3..000000000 --- a/src/main/java/victor/training/cleancode/mass/BaseService.java +++ /dev/null @@ -1,13 +0,0 @@ -package victor.training.cleancode.mass; - -public abstract class BaseService { - private D dao; - - public D getDao() { - return dao; - } - - public void setDao(D dao) { - this.dao = dao; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/Consultation.java b/src/main/java/victor/training/cleancode/mass/Consultation.java deleted file mode 100644 index 2e746f7f5..000000000 --- a/src/main/java/victor/training/cleancode/mass/Consultation.java +++ /dev/null @@ -1,25 +0,0 @@ -package victor.training.cleancode.mass; - -import org.w3c.dom.Document; - -import java.time.LocalDateTime; - -public class Consultation implements Data { - private Patient patient; - @OldAnnotation( - name = "Why \n??" - ) - private String notes; - private LocalDateTime dateTime; - private Medic medic; - - @Override - public void fromXml(Document pDocument) { - - } - - @Override - public Document toXml() { - return null; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/DAO.java b/src/main/java/victor/training/cleancode/mass/DAO.java deleted file mode 100644 index 6f251267b..000000000 --- a/src/main/java/victor/training/cleancode/mass/DAO.java +++ /dev/null @@ -1,4 +0,0 @@ -package victor.training.cleancode.mass; - -public interface DAO { -} diff --git a/src/main/java/victor/training/cleancode/mass/Data.java b/src/main/java/victor/training/cleancode/mass/Data.java deleted file mode 100644 index 31fe7c9db..000000000 --- a/src/main/java/victor/training/cleancode/mass/Data.java +++ /dev/null @@ -1,8 +0,0 @@ -package victor.training.cleancode.mass; - -import org.w3c.dom.Document; - -public interface Data { - void fromXml(Document pDocument); - Document toXml(); -} diff --git a/src/main/java/victor/training/cleancode/mass/Job.java b/src/main/java/victor/training/cleancode/mass/Job.java deleted file mode 100644 index be0deb9d8..000000000 --- a/src/main/java/victor/training/cleancode/mass/Job.java +++ /dev/null @@ -1,18 +0,0 @@ -package victor.training.cleancode.mass; - -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Component -public class Job { - private final PatientService patientService; - - public Job(PatientService patientService) { - this.patientService = patientService; - } - - @Scheduled(fixedRate = 10_000) - public void every10sec() { - patientService.updatePatient(new Patient(), new User("job")); - } -} diff --git a/src/main/java/victor/training/cleancode/mass/Medic.java b/src/main/java/victor/training/cleancode/mass/Medic.java deleted file mode 100644 index 89f31b729..000000000 --- a/src/main/java/victor/training/cleancode/mass/Medic.java +++ /dev/null @@ -1,41 +0,0 @@ -package victor.training.cleancode.mass; - -import org.w3c.dom.Document; - -import java.util.ArrayList; - -public class Medic implements Data { - @OldAnnotation - private String name; - @OldAnnotation(name = "consultationList") - private ArrayList consultations; - - public Medic() { - consultations = new ArrayList(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public ArrayList getConsultations() { - return consultations; - } - - public void setConsultations(ArrayList consultations) { - this.consultations = consultations; - } - - @Override - public void fromXml(Document pDocument) { - } - - @Override - public Document toXml() { - return null; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/OldAnnotation.java b/src/main/java/victor/training/cleancode/mass/OldAnnotation.java deleted file mode 100644 index dacfad8bd..000000000 --- a/src/main/java/victor/training/cleancode/mass/OldAnnotation.java +++ /dev/null @@ -1,10 +0,0 @@ -package victor.training.cleancode.mass; - -import java.lang.annotation.Retention; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Retention(RUNTIME) // stops javac from removing it at compilation -public @interface OldAnnotation { - String name() default ""; -} diff --git a/src/main/java/victor/training/cleancode/mass/Patient.java b/src/main/java/victor/training/cleancode/mass/Patient.java deleted file mode 100644 index e84d370b3..000000000 --- a/src/main/java/victor/training/cleancode/mass/Patient.java +++ /dev/null @@ -1,111 +0,0 @@ -package victor.training.cleancode.mass; - -import org.w3c.dom.Document; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class Patient implements Data { - private String id; - private String firstName; - private String lastName; - private String phoneNumber; - private String email; - private Long processCenterId; - - @OldAnnotation - private List consultations; - - public Patient() { - consultations = new ArrayList(); - email = null; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getPhonenumber() { - return phoneNumber; - } - - public void setPhonenumber(String phoneNumber) { - this.phoneNumber = phoneNumber; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public List getConsultations() { - return consultations; - } - - public void setConsultations(List consultations) { - this.consultations = consultations; - } - - public Long getProcessCenterId() { - return processCenterId; - } - - public void setProcessCenterId(Long processCenterId) { - this.processCenterId = processCenterId; - } - - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - Patient patient = (Patient) o; - return Objects.equals(id, patient.id) && Objects.equals(firstName, patient.firstName) && Objects.equals(lastName, patient.lastName) && Objects.equals(phoneNumber, patient.phoneNumber) && Objects.equals(email, patient.email); - } - - @Override - public int hashCode() { - return Objects.hash(id, firstName, lastName, phoneNumber, email); - } - - @Override - public String toString() { - return "Patient{" + - "id='" + id + '\'' + - ", firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - '}'; - } - - @Override - public void fromXml(Document pDocument) { - - } - - @Override - public Document toXml() { - return null; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/PatientController.java b/src/main/java/victor/training/cleancode/mass/PatientController.java deleted file mode 100644 index ccf8b75c4..000000000 --- a/src/main/java/victor/training/cleancode/mass/PatientController.java +++ /dev/null @@ -1,17 +0,0 @@ -package victor.training.cleancode.mass; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class PatientController { - @Autowired - private PatientService patientService; - - @GetMapping - public String update() { - patientService.createPatient(); - return "ok✅"; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/PatientDAO.java b/src/main/java/victor/training/cleancode/mass/PatientDAO.java deleted file mode 100644 index d3e77eee9..000000000 --- a/src/main/java/victor/training/cleancode/mass/PatientDAO.java +++ /dev/null @@ -1,23 +0,0 @@ -package victor.training.cleancode.mass; - -import org.springframework.stereotype.Repository; - -@Repository -public class PatientDAO implements DAO { - public void update(Patient patient, User user) { - System.out.println("UPDATE INTO .. LAST_MODIFIED_BY=" + user.getUsername()); - } - - public void create(Patient patient, User user) { - System.out.println("INSERT INTO PATIENT " + - "VALUES (CREATED_BY=?...)"); - System.out.println("Set param: " + user.getUsername()); - System.out.println("Set param: " + patient.getId()); - System.out.println("Set param: " + patient.getProcessCenterId()); - System.out.println("Set param: " + patient.getEmail()); - System.out.println("Set param: " + patient.getFirstName()); - System.out.println("Set param: " + patient.getLastName()); - System.out.println("Set param: " + patient.getConsultations()); - System.out.println("Set param: " + patient.getPhonenumber()); - } -} diff --git a/src/main/java/victor/training/cleancode/mass/PatientService.java b/src/main/java/victor/training/cleancode/mass/PatientService.java deleted file mode 100644 index 62a9bd238..000000000 --- a/src/main/java/victor/training/cleancode/mass/PatientService.java +++ /dev/null @@ -1,33 +0,0 @@ -package victor.training.cleancode.mass; - -import jakarta.annotation.PostConstruct; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -@Service -public class PatientService extends BaseService { - private static final Logger LOG = LoggerFactory.getLogger(PatientService.class); - - @PostConstruct - public void init() { - setDao(new PatientDAO()); - } - - public void createPatient() { - internalMethod("41"); - } - - public void updatePatient(Patient patient, User user) { - internalMethod("42"); - LOG.debug("Message " + patient); - getDao().update(patient, user); - } - - // Inspection: ⇧⇧ can be weaker - public void internalMethod(String id) { - if (new Long(id).longValue() == 42) { - System.out.println("Answer to life"); - } - } -} diff --git a/src/main/java/victor/training/cleancode/mass/SpringApp.java b/src/main/java/victor/training/cleancode/mass/SpringApp.java deleted file mode 100644 index 8ca90c8cc..000000000 --- a/src/main/java/victor/training/cleancode/mass/SpringApp.java +++ /dev/null @@ -1,13 +0,0 @@ -package victor.training.cleancode.mass; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.scheduling.annotation.EnableScheduling; - -@SpringBootApplication -@EnableScheduling -public class SpringApp { - public static void main(String[] args) { - SpringApplication.run(SpringApp.class, args); - } -} diff --git a/src/main/java/victor/training/cleancode/mass/User.java b/src/main/java/victor/training/cleancode/mass/User.java deleted file mode 100644 index 5add5d591..000000000 --- a/src/main/java/victor/training/cleancode/mass/User.java +++ /dev/null @@ -1,29 +0,0 @@ -package victor.training.cleancode.mass; - -public class User { - String username; - String fullName; - - public User() { - } - - public User(String username) { - this.username = username; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getFullName() { - return fullName; - } - - public void setFullName(String fullName) { - this.fullName = fullName; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/UserFilter.java b/src/main/java/victor/training/cleancode/mass/UserFilter.java deleted file mode 100644 index d49eb03a2..000000000 --- a/src/main/java/victor/training/cleancode/mass/UserFilter.java +++ /dev/null @@ -1,21 +0,0 @@ -package victor.training.cleancode.mass; - -import jakarta.servlet.*; - -import java.io.IOException; - -public class UserFilter implements Filter { - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - User user = fromHeaders(request); - UserHolder.setCurrentUser(user); - } - - private User fromHeaders(ServletRequest request) { - //pretend - User user = new User(); - user.setUsername("jdoe"); - user.setFullName("Jane Doe"); - return user; - } -} diff --git a/src/main/java/victor/training/cleancode/mass/UserHolder.java b/src/main/java/victor/training/cleancode/mass/UserHolder.java deleted file mode 100644 index a5c7ff84f..000000000 --- a/src/main/java/victor/training/cleancode/mass/UserHolder.java +++ /dev/null @@ -1,13 +0,0 @@ -package victor.training.cleancode.mass; - -public class UserHolder { - private static final ThreadLocal currentUser = new ThreadLocal<>(); - - public static User getCurrentUser() { - return currentUser.get(); - } - - public static void setCurrentUser(User user) { - currentUser.set(user); - } -} diff --git a/src/main/java/victor/training/cleancode/optional/NonNullByDefault.java b/src/main/java/victor/training/cleancode/optional/NonNullByDefault.java deleted file mode 100644 index 9b2b59340..000000000 --- a/src/main/java/victor/training/cleancode/optional/NonNullByDefault.java +++ /dev/null @@ -1,13 +0,0 @@ -package victor.training.cleancode.optional; - -import javax.annotation.Nonnull; -import javax.annotation.meta.TypeQualifierDefault; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Nonnull -@TypeQualifierDefault({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface NonNullByDefault { -} diff --git a/src/main/java/victor/training/cleancode/optional/Optional_Chain.java b/src/main/java/victor/training/cleancode/optional/Optional_Chain.java deleted file mode 100644 index 6353ac743..000000000 --- a/src/main/java/victor/training/cleancode/optional/Optional_Chain.java +++ /dev/null @@ -1,80 +0,0 @@ -package victor.training.cleancode.optional; - -public class Optional_Chain { - private static final MyMapper mapper = new MyMapper(); - - public static void main(String[] args) { - Parcel parcel = new Parcel(); - parcel.setDelivery(new Delivery(new Address(new ContactPerson("John")))); - // parcel.setDelivery(new Delivery(new Address(null))); - // parcel.setDelivery(null); - - DeliveryDto dto = mapper.convert(parcel); - System.out.println(dto); - } -} - -class MyMapper { - public DeliveryDto convert(Parcel parcel) { - DeliveryDto dto = new DeliveryDto(); - dto.recipientPerson = parcel.getDelivery().getAddress().getContactPerson().getName().toUpperCase(); - return dto; - } -} - -class DeliveryDto { - public String recipientPerson; -} - -class Parcel { - private Delivery delivery; // NULL until a delivery is scheduled - - public Delivery getDelivery() { - return delivery; - } - - public void setDelivery(Delivery delivery) { - this.delivery = delivery; - } -} - - -class Delivery { - private Address address; // NOT NULL IN DB - - public Delivery(Address address) { - this.address = address; - } - - public void setAddress(Address address) { - this.address = address; // TODO null safe - } - - public Address getAddress() { - return address; - } -} - -class Address { - private final ContactPerson contactPerson; // can be null if shipping to a company - - public Address(ContactPerson contactPerson) { - this.contactPerson = contactPerson; - } - - public ContactPerson getContactPerson() { - return contactPerson; - } -} - -class ContactPerson { - private final String name; // NOT NULL - - public ContactPerson(String name) { - this.name = name; - } - - public String getName() { - return name; - } -} diff --git a/src/main/java/victor/training/cleancode/optional/Optional_Intro.java b/src/main/java/victor/training/cleancode/optional/Optional_Intro.java deleted file mode 100644 index 6abf33c82..000000000 --- a/src/main/java/victor/training/cleancode/optional/Optional_Intro.java +++ /dev/null @@ -1,46 +0,0 @@ - -package victor.training.cleancode.optional; - -import victor.training.cleancode.exception.model.Customer; -import victor.training.cleancode.exception.model.MemberCard; - -import java.util.Map; -import java.util.Optional; - -@SuppressWarnings("ConstantConditions") -public class Optional_Intro { - public static void main(String[] args) { - // test with 10 points or no MemberCard - System.out.println(getDiscountLine(new Customer(new MemberCard("bar", 60)))); - System.out.println(getDiscountLine(new Customer(new MemberCard("bar", 10)))); - System.out.println(getDiscountLine(new Customer())); - } - - public static String getDiscountLine(Customer customer) { -// return customer.getMemberCard() -// .map(memberCard -> computeDiscount(memberCard) -// .map(value -> "You got a discount of %" + value.globalPercentage()) -// .orElse("Buy more!")).orElse("Paranoicule!"); - return customer.getMemberCard() - .flatMap(card -> computeDiscount(card)) - .map(value -> "You got a discount of %" + value.globalPercentage()) - .orElse("No Discount"); - } - - private static Optional computeDiscount(MemberCard card) { -// if (card == null) { // paranoia programming -// return Optional.empty(); -// } - if (card.getFidelityPoints() >= 100) { - return Optional.of(new Discount(5, Map.of())); - } - if (card.getFidelityPoints() >= 50) { - return Optional.of(new Discount(3, Map.of())); - } - return Optional.empty(); - } - - public record Discount(int globalPercentage, Map categoryDiscounts) { - } -} - diff --git a/src/main/java/victor/training/cleancode/optional/abuse/AllCallersFailOnEmpty.java b/src/main/java/victor/training/cleancode/optional/abuse/AllCallersFailOnEmpty.java deleted file mode 100644 index 5304cab81..000000000 --- a/src/main/java/victor/training/cleancode/optional/abuse/AllCallersFailOnEmpty.java +++ /dev/null @@ -1,44 +0,0 @@ -package victor.training.cleancode.optional.abuse; - - -import java.lang.reflect.ParameterizedType; -import java.util.NoSuchElementException; -import java.util.Optional; - -public class AllCallersFailOnEmpty { - //@Id - // Spring pretend - interface JpaRepository { - Optional findById(PK id); - } - private interface BaseRepo extends JpaRepository { - @SuppressWarnings("unchecked") - default T findOneById(PK id) { - return findById(id).orElseThrow(() -> { - Class persistentClass = (Class) ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - return new NoSuchElementException(persistentClass.getSimpleName() + " with id " + id + " not found "); - }); - } - } - - //@Entity // pretend - private static class Tenant { - Long id; - } -// private interface TenantRepo extends BaseRepo { - private interface TenantRepo extends JpaRepository { - } - - - private TenantRepo tenantRepo; - - public void flow1(long tenantId) { - Tenant tenant = tenantRepo.findById(tenantId).get(); // .get() throws if Optional is empty - System.out.println("Stuff1 with tenant: " + tenant); - } - - public void flow2(long tenantId) { - Tenant tenant = tenantRepo.findById(tenantId).get(); // + 30 more places in a typical project - System.out.println("Stuff2 with tenant: " + tenant); - } -} diff --git a/src/main/java/victor/training/cleancode/optional/abuse/OptionalCollections.java b/src/main/java/victor/training/cleancode/optional/abuse/OptionalCollections.java deleted file mode 100644 index 71a0dae52..000000000 --- a/src/main/java/victor/training/cleancode/optional/abuse/OptionalCollections.java +++ /dev/null @@ -1,39 +0,0 @@ -package victor.training.cleancode.optional.abuse; - - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class OptionalCollections { - private static class Product {} - private static class Coupon {} - private static class Customer {} - private interface CustomerRepo { - Optional findById(Long id); - } - - private CustomerRepo customerRepo; - - public Optional> findApplicableCoupons(Long customerId, List products) { - System.out.println("Retrieve customer coupons " + customerId); - Optional customerFound = customerRepo.findById(customerId); - if (customerFound.isEmpty()) { - return Optional.empty(); - } - List coupons = new ArrayList<>(); - System.out.println("Filter out not applicable coupons from " + coupons); - return Optional.of(coupons); - } - - public void caller(Long customerId) { - List products = List.of(new Product(), new Product()); - Optional> couponsOpt = findApplicableCoupons(customerId, products); - - if (couponsOpt.isPresent()) { - for (Coupon coupon : couponsOpt.get()) { - System.out.println("Apply coupon: " + coupon); - } - } - } -} diff --git a/src/main/java/victor/training/cleancode/optional/abuse/OptionalParameters.java b/src/main/java/victor/training/cleancode/optional/abuse/OptionalParameters.java deleted file mode 100644 index 591ae71d3..000000000 --- a/src/main/java/victor/training/cleancode/optional/abuse/OptionalParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package victor.training.cleancode.optional.abuse; - -import victor.training.cleancode.exception.model.MemberCard; -import victor.training.cleancode.optional.Optional_Intro.Discount; - -import java.util.Optional; - -public class OptionalParameters { - - public void callers() { - // without - sendMessage("jdoe", "message", Optional.empty()); - - // with - sendMessage("jdoe", "message", Optional.of("REGLISS")); - - } - - // ⬇⬇⬇⬇⬇⬇ utility / library code ⬇⬇⬇⬇⬇⬇ - public void sendMessage(String recipient, String message, Optional trackingRegistry) { - System.out.println("Resolve phone number for " + recipient); - System.out.println("Send message " + message); - - trackingRegistry.ifPresent(reg -> System.out.println("Also notify the tracking registry : " + reg)); - } -} diff --git a/src/main/java/victor/training/cleancode/optional/abuse/OrElseGetTrap.java b/src/main/java/victor/training/cleancode/optional/abuse/OrElseGetTrap.java deleted file mode 100644 index d7aec8081..000000000 --- a/src/main/java/victor/training/cleancode/optional/abuse/OrElseGetTrap.java +++ /dev/null @@ -1,24 +0,0 @@ -package victor.training.cleancode.optional.abuse; - -import java.util.Optional; - -public class OrElseGetTrap { - private record Transfer(String from, String to, int amount) { - } - - static Optional takeOwnMoney(String user) { - System.out.println("Taking money from " + user); - return Optional.of(new Transfer("Victor", "Vodafone", 100)); - } - - static Transfer takeCreditMoney(String user) { - System.out.println("Borrowing⚠️ money for " + user); - return new Transfer("Creditor", "Vodafone", 100); - } - - public static void main(String[] args) { - Transfer transfer = takeOwnMoney("user") - .orElse(takeCreditMoney("user")); - System.out.println("Transfer: " + transfer); - } -} diff --git a/src/main/java/victor/training/cleancode/optional/package-info.java b/src/main/java/victor/training/cleancode/optional/package-info.java deleted file mode 100644 index c680506c9..000000000 --- a/src/main/java/victor/training/cleancode/optional/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -//@NonNullByDefault -package victor.training.cleancode.optional; \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/CombineFunctionsIntoTransform.java b/src/main/java/victor/training/cleancode/refactoring/CombineFunctionsIntoTransform.java deleted file mode 100644 index 4f21bdccb..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/CombineFunctionsIntoTransform.java +++ /dev/null @@ -1,31 +0,0 @@ -package victor.training.cleancode.refactoring; - -import lombok.Data; - -public class CombineFunctionsIntoTransform { - public String generateQRCode(String code) { - // Call External Service - return "QR" + code; - } - - public String getAddress(long eventId) { - // Call Repository - return "Location Details of event " + eventId; - } - // ----------- a line ------------- - - // TODO go through preserve Whole Object - public String generateTicket(Ticket ticket) { - String invoice = "Invoice for " + ticket.customerName() + "\n"; - invoice += "QR Code: " + generateQRCode(ticket.code()) + "\n"; - invoice += "Address: " + getAddress(ticket.eventId()) + "\n"; - invoice += "Please arrive 20 minutes before the start of the event\n"; - invoice += "In case of emergency, call 0899898989\n"; - return invoice; - } -} - -record Ticket(String customerName, - String code, - long eventId) { -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/EncapsulateCollection.java b/src/main/java/victor/training/cleancode/refactoring/EncapsulateCollection.java deleted file mode 100644 index 2c36de11c..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/EncapsulateCollection.java +++ /dev/null @@ -1,44 +0,0 @@ -package victor.training.cleancode.refactoring; - -import lombok.Value; - -import java.util.ArrayList; -import java.util.List; - -public class EncapsulateCollection { - public static void main(String[] args) { - HotelCharges hotelCharges = new HotelCharges(); - HotelDayCharge dayCharge = new HotelDayCharge(100, true, 5); - - hotelCharges.days.add(dayCharge); - System.out.println("FEE: " + hotelCharges.totalFee + "\n"); - - // Never forget to do: - hotelCharges.computeTotal(); - System.out.println("FEE: " + hotelCharges.totalFee + "\n"); - - } -} - -class HotelCharges { - public List days = new ArrayList<>(); - public double totalFee; - - public void computeTotal() { - final double BREAKFAST_FEE = 10; - final double PARKING_HOUR_RATE = 2; - totalFee = 0; - for (HotelDayCharge day : days) { - totalFee += day.dayRate(); - if (day.breakfast()) { - totalFee += BREAKFAST_FEE; - } - totalFee += day.parkingHours() * PARKING_HOUR_RATE; - } - } -} - -record HotelDayCharge(double dayRate, - boolean breakfast, - int parkingHours) { -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/EncapsulateConditionals.java b/src/main/java/victor/training/cleancode/refactoring/EncapsulateConditionals.java deleted file mode 100644 index b058a4a6f..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/EncapsulateConditionals.java +++ /dev/null @@ -1,24 +0,0 @@ -package victor.training.cleancode.refactoring; - -import lombok.Data; - -import java.util.Date; - -public class EncapsulateConditionals { - public double getQuote(Date date, RatesPlan plan, int quantity, float clientFidelityFactor) { - double charge; - if (!(date.before(plan.summerStart())) && date.before(plan.summerEnd())) - charge = quantity * plan.summerRate(); - else - charge = quantity * plan.regularRate() + plan.regularServiceCharge(); - return charge - clientFidelityFactor; - } -} - - -record RatesPlan(Date summerStart, - Date summerEnd, - double summerRate, - double regularRate, - double regularServiceCharge) { -} diff --git a/src/main/java/victor/training/cleancode/refactoring/ExtractDelegate.java b/src/main/java/victor/training/cleancode/refactoring/ExtractDelegate.java deleted file mode 100644 index 8815006e2..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/ExtractDelegate.java +++ /dev/null @@ -1,43 +0,0 @@ -package victor.training.cleancode.refactoring; - -public class ExtractDelegate { - public static void main(String[] args) { - BigOne one = new BigOne(); - one.fa(); - one.fab(); - one.fcab(); - one.fc(); - } -} -class BigOne { - private A a = new A(); - private B b = new B(); - private C c = new C(); - - public void fa() { - a.f(); - } - public void fab() { - a.f(); - b.f(); - } - public void fcab() { - c.f(); - a.f(); - b.f(); - } - public void fc() { - c.f(); - } -} - -class A { - void f(){System.out.println("A.f");} -} -class B { - void f(){System.out.println("B.f");} -} -class C { - void f(){System.out.println("C.f");} -} - diff --git a/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject.java b/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject.java deleted file mode 100644 index 4986816db..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject.java +++ /dev/null @@ -1,41 +0,0 @@ -package victor.training.cleancode.refactoring; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; -import lombok.RequiredArgsConstructor; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@RequiredArgsConstructor -public class ExtractMethodObject { - private final EntityManager em; - - public List search(CustomerSearchCriteria criteria) { - String jpql = "SELECT c.id FROM Customer c WHERE 1=1 "; - Map params = new HashMap<>(); - - if (criteria.name != null) { - jpql += " AND UPPER(c.name) LIKE '%' || UPPER(:name) || '%' "; - params.put("name", criteria.name); - } - - if (criteria.countryId != null) { - jpql += " AND (c.residenceCountry.id = :countryId OR ..<5 lines of JPQL>..)"; - params.put("countryId", criteria.countryId); - } - - TypedQuery query = em.createQuery(jpql + " ", Long.class); - for (String param : params.keySet()) { - query.setParameter(param, params.get(param)); - } - return query.getResultList(); - } -} - -class CustomerSearchCriteria { - - public String name; - public Long countryId; -} diff --git a/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject_Validator.java b/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject_Validator.java deleted file mode 100644 index e5a4db71d..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/ExtractMethodObject_Validator.java +++ /dev/null @@ -1,57 +0,0 @@ -package victor.training.cleancode.refactoring; - - -import java.util.ArrayList; -import java.util.List; - -public class ExtractMethodObject_Validator { - private final Validator validator; - - public ExtractMethodObject_Validator(Validator validator) { - this.validator = validator; - } - - public void bizLogic() { - List errors = new ArrayList<>(); - validator.m1("a",1, errors); - validator.m2("b",1, errors); - validator.m3("file.txt", 1L,"ref", errors); - validator.m4("a", 1L,5L, "g", errors); - validator.m5(1, errors); - if (!errors.isEmpty()) { - throw new IllegalArgumentException(errors.toString()); - } - } -} -//@Service -class Validator { -// @Autowired - private OtherDependency dep; - - public void m1(String a, int b, List errors) { - if (a == null) { - errors.add("a must not be null"); - } - // stuff - } - public void m2(String s, int c, List errors) { - if (c < 0) { - errors.add("negative c"); - } - // stuff - } - public void m3(String fileName, long versionId, String reference, List errors) { - // stuff - } - public void m4(String a, long listId, long recordId, String g, List errors) { - // stuff - } - public void m5(int b, List errors) { - // stuff - } -} - -//@Service -class OtherDependency { - -} diff --git a/src/main/java/victor/training/cleancode/refactoring/ExtractVariable.java b/src/main/java/victor/training/cleancode/refactoring/ExtractVariable.java deleted file mode 100644 index 24d3cfbcd..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/ExtractVariable.java +++ /dev/null @@ -1,14 +0,0 @@ -package victor.training.cleancode.refactoring; - -import lombok.Value; - -public class ExtractVariable { - public double computeTotalPrice(Order order) { - return order.quantity() * order.itemPrice() - - Math.max(0, order.quantity() - 500) * order.itemPrice() * 0.05 + - Math.min(order.quantity() * order.itemPrice() * 0.1, 100); - } -} - -record Order(int quantity, int itemPrice) { -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/ReplaceTempWithQuery.java b/src/main/java/victor/training/cleancode/refactoring/ReplaceTempWithQuery.java deleted file mode 100644 index 28352c84f..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/ReplaceTempWithQuery.java +++ /dev/null @@ -1,30 +0,0 @@ -package victor.training.cleancode.refactoring; - -public class ReplaceTempWithQuery { - private final int quantity; - private final double itemPrice; - - public ReplaceTempWithQuery(int quantity, double itemPrice) { - this.quantity = quantity; - this.itemPrice = itemPrice; - } - - public double computePrice() { - double basePrice = quantity * itemPrice; - if (quantity > 10) - return basePrice * 0.95; - else - return computeNormalPrice(basePrice); - } - - private double computeNormalPrice(double basePrice) { - double factor = (basePrice > 1000) ? 0.95: 0.98; - return factor * basePrice; - } - - public int computeFidelityPoints() { - return (int) (quantity * itemPrice / 2); - } - - -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/SeparateQueryCommand.java b/src/main/java/victor/training/cleancode/refactoring/SeparateQueryCommand.java deleted file mode 100644 index bb48ee7f1..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/SeparateQueryCommand.java +++ /dev/null @@ -1,24 +0,0 @@ -package victor.training.cleancode.refactoring; - -import java.util.List; - -public class SeparateQueryCommand { - - public String alertForMiscreant(List people) { - for (String person : people) { - if (person.equals("Don")) { - setOffAlarms(); - return "Don"; - } - if (person.equals("John")) { - setOffAlarms(); - return "John"; - } - } - return ""; - } - - private void setOffAlarms() { - System.out.println("Side effects\n"); - } -} diff --git a/src/main/java/victor/training/cleancode/refactoring/SplitPhase.java b/src/main/java/victor/training/cleancode/refactoring/SplitPhase.java deleted file mode 100644 index c7fc05a30..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/SplitPhase.java +++ /dev/null @@ -1,16 +0,0 @@ -package victor.training.cleancode.refactoring; - -import java.util.Collections; -import java.util.Map; - -public class SplitPhase { - public float calculateOrderPrice(String orderString, Map priceList) { - String[] orderData = orderString.split("\\s+"); - Integer productPrice = priceList.get(orderData[0].split("-")[1]); - return Integer.parseInt(orderData[1]) * productPrice; - } - - public static void main(String[] args) { - System.out.println(new SplitPhase().calculateOrderPrice("Chair-CHR 4", Collections.singletonMap("CHR", 5))); - } -} diff --git a/src/main/java/victor/training/cleancode/refactoring/SplitVariable.java b/src/main/java/victor/training/cleancode/refactoring/SplitVariable.java deleted file mode 100644 index 742250b11..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/SplitVariable.java +++ /dev/null @@ -1,11 +0,0 @@ -package victor.training.cleancode.refactoring; - -public class SplitVariable { - - // @see test - public static int discount(int price, int quantity) { - if (price > 50) price = price - 2; - if (quantity > 100) price = price - 1; - return price; - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractInterface.java b/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractInterface.java deleted file mode 100644 index 4e4cb60f3..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractInterface.java +++ /dev/null @@ -1,31 +0,0 @@ -package victor.training.cleancode.refactoring.inheritance; - -class CsvWriter { - - public void writeLine() { - } - - public void writeCell(String value) { - } -} - -class SomeOtherClass { - public void writeFooter(CsvWriter writer) { - writer.writeCell("Generated with X SoftWare"); - writer.writeLine(); - } -} - -class AnotherDistantClass { - private final CsvWriter csvWriter; - - public AnotherDistantClass(CsvWriter csvWriter) { - this.csvWriter = csvWriter; - } - public void writeHeader() { - csvWriter.writeCell("Head1"); - csvWriter.writeCell("Head2"); - csvWriter.writeLine(); - } - -} diff --git a/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractSuperClass.java b/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractSuperClass.java deleted file mode 100644 index 3222c592c..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/inheritance/ExtractSuperClass.java +++ /dev/null @@ -1,21 +0,0 @@ -package victor.training.cleancode.refactoring.inheritance; - - -class S {} -class A { - private int x; - private int y; - void m() {System.out.println(x);} - void n() {x ++;} -} - -class B { - private int x; - private int y; - void m() {System.out.println(x);} -} -class C { - private int x; - void m() {System.out.println(x);} - void n() {x++;} -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/inheritance/SubclassToDelegate.java b/src/main/java/victor/training/cleancode/refactoring/inheritance/SubclassToDelegate.java deleted file mode 100644 index 74a0944ca..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/inheritance/SubclassToDelegate.java +++ /dev/null @@ -1,33 +0,0 @@ -package victor.training.cleancode.refactoring.inheritance; - -class Order -{ - private Warehouse warehouse; - - // TODO if delegate != null -> delegate.prioritityPlan... - public int daysToShip() { - return warehouse.getDaysToShip(); - } -} - -class PriorityOrder extends Order -{ - private PriorityPlan priorityPlan; - - public int daysToShip() { - return priorityPlan.getDaysToShip(); - } -} - -class PriorityPlan { - public int getDaysToShip() { - return 3; - } -} - -class Warehouse { - - public int getDaysToShip() { - return 5; - } -} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/inheritance/SuperclassToDelegate.java b/src/main/java/victor/training/cleancode/refactoring/inheritance/SuperclassToDelegate.java deleted file mode 100644 index 29e9ace31..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/inheritance/SuperclassToDelegate.java +++ /dev/null @@ -1,32 +0,0 @@ -package victor.training.cleancode.refactoring.inheritance; - -class Rectangle { - private int width; - private int height; - - public int area() { - return width * height; - } - public int perimeter() { - return 2 * (width + height); - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } -} - -// TODO -class Square {} \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/refactoring/inheritance/TypecodeToSubclass.java b/src/main/java/victor/training/cleancode/refactoring/inheritance/TypecodeToSubclass.java deleted file mode 100644 index d2b3df59a..000000000 --- a/src/main/java/victor/training/cleancode/refactoring/inheritance/TypecodeToSubclass.java +++ /dev/null @@ -1,47 +0,0 @@ -package victor.training.cleancode.refactoring.inheritance; - -class TheatreEvent { - enum Category { - TYPE_MUSICAL, - TYPE_DRAMA, - TYPE_COMEDY - } - - private String title; - private int duration; - private int weekDay; - private Category type; - private boolean adultComedy; - - public String getTitle() { - return title; - } - - public int minimumAge() { - switch (type) { - case TYPE_MUSICAL: - return 6; - case TYPE_DRAMA: - return 10; - case TYPE_COMEDY: - return adultComedy ? 18 : (duration > 120 ? 9 : 7); - } - return -1; - } - - public boolean isWeekend() { - return weekDay >= 6; - } - - public float basePrice() { - switch (type) { - case TYPE_MUSICAL: - return 60 + (isWeekend() ? 10 : 0); - case TYPE_DRAMA: - return 40 + (isWeekend() ? 5 : 0); - case TYPE_COMEDY: - return 50 - (adultComedy ? 5 : 0); - } - return 0; - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/BossTest.java b/src/test/java/victor/training/cleancode/BossTest.java deleted file mode 100644 index db2b99dbb..000000000 --- a/src/test/java/victor/training/cleancode/BossTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.CaptureSystemOutput.OutputCapture; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class BossTest { - - private final Boss target = new Boss(); - - @Test - @CaptureSystemOutput - void bossLevelFluff(OutputCapture outputCapture) { - target.bossLevel(true, List.of(new Task(5)), false); - - assertThat(outputCapture.toString()) - .isEqualToIgnoringNewLines("Logic1\n" + - "Logic3\n" + - "Starting Task(id=5, started=false)\n" + - "Audit task #1: Task(id=5, started=true)\n" + - "Logic6 1\n" + - "Task Ids: [5]\n" + - "Logic8\n"); - } - @Test - @CaptureSystemOutput - void bossLevelFluff_c323(OutputCapture outputCapture) { - target.bossLevel(true, List.of(new Task(5)), true); - - assertThat(outputCapture.toString()) - .isEqualToIgnoringNewLines("Logic1\n" + - "Logic3\n" + - "Starting Task(id=5, started=false)\n" + - "My Logic: Task(id=5, started=true)\n" + - "Audit task #1: Task(id=5, started=true)\n" + - "Logic6 1\n" + - "Task Ids: [5]\n" + - "Logic8"); - } - - @Test - @CaptureSystemOutput - void bossLevelFluff_emptyList(OutputCapture outputCapture) { - target.bossLevel(true, List.of(), false); - - assertThat(outputCapture.toString()) - .isEqualToIgnoringNewLines(""); - } - @Test - @CaptureSystemOutput - void bossLevelFalse(OutputCapture outputCapture) { - target.bossLevel(false, List.of(new Task(5)), false); - - assertThat(outputCapture.toString()) - .isEqualToIgnoringNewLines("Logic1\n" + - "Logic7 on fluff=false [Task(id=5, started=false)]\n" + - "Logic8\n"); - } - - @Test - @CaptureSystemOutput - void stuffForEachElement_inWateverOrder(OutputCapture outputCapture) { - target.bossLevel(true, List.of(new Task(5),new Task(6)), false); - - // we don't care in what order we validate or audit tasks - assertThat(outputCapture.toString()) - .contains("Starting Task(id=5, started=false)") - .contains("Starting Task(id=6, started=false)") - .contains("Audit task #1: Task(id=5, started=true)") - .contains("Audit task #2: Task(id=6, started=true)") - ; - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/CaptureSystemOutput.java b/src/test/java/victor/training/cleancode/CaptureSystemOutput.java deleted file mode 100644 index b1675436b..000000000 --- a/src/test/java/victor/training/cleancode/CaptureSystemOutput.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package victor.training.cleancode; - -import org.junit.jupiter.api.extension.*; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; -import org.junit.jupiter.api.extension.ExtensionContext.Store; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * {@code @CaptureSystemOutput} is a JUnit JUpiter extension for capturing - * output to {@code System.out} and {@code System.err} - * - * Example Usage - * - *
- * {@literal @}Test
- * {@literal @}CaptureSystemOutput
- * void systemOut(OutputCapture outputCapture) {
- *     System.out.println("Printed to System.out!");
- *     assertThat(outputCapture.toString()).contains("System.out!");
- * }
- * 
- * - *

Based on code from Spring Boot's - * OutputCapture - * rule for JUnit 4 by Phillip Webb and Andy Wilkinson. - */ -@Target({TYPE, METHOD}) -@Retention(RUNTIME) -@Documented -@ExtendWith(CaptureSystemOutput.Extension.class) -public @interface CaptureSystemOutput { - - class Extension implements BeforeEachCallback, AfterEachCallback, ParameterResolver { - @Override - public void beforeEach(ExtensionContext context) throws Exception { - getOutputCapture(context).captureOutput(); - } - - @Override - public void afterEach(ExtensionContext context) throws Exception { - OutputCapture outputCapture = getOutputCapture(context); - outputCapture.releaseOutput(); - } - - @Override - public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - boolean isTestMethodLevel = extensionContext.getTestMethod().isPresent(); - boolean isOutputCapture = parameterContext.getParameter().getType() == OutputCapture.class; - return isTestMethodLevel && isOutputCapture; - } - - @Override - public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - return getOutputCapture(extensionContext); - } - - private OutputCapture getOutputCapture(ExtensionContext context) { - Namespace namespace = Namespace.create(getClass(), context.getRequiredTestMethod()); - Store store = context.getStore(namespace); - return store.getOrComputeIfAbsent(OutputCapture.class); - } - } - - class OutputCapture { - private CaptureOutputStream captureOut; - private CaptureOutputStream captureErr; - private ByteArrayOutputStream copy; - - void captureOutput() { - this.copy = new ByteArrayOutputStream(); - this.captureOut = new CaptureOutputStream(System.out, this.copy); - this.captureErr = new CaptureOutputStream(System.err, this.copy); - System.setOut(new PrintStream(this.captureOut)); - System.setErr(new PrintStream(this.captureErr)); - } - - void releaseOutput() { - System.setOut(this.captureOut.getOriginal()); - System.setErr(this.captureErr.getOriginal()); - this.copy = null; - } - - private void flush() { - try { - this.captureOut.flush(); - this.captureErr.flush(); - } catch (IOException ex) { - // ignore - } - } - - /** - * Return all captured output to {@code System.out} and {@code System.err} - * as a single string. - */ - @Override - public String toString() { - flush(); - return this.copy.toString(); - } - - private static class CaptureOutputStream extends OutputStream { - private final PrintStream original; - private final OutputStream copy; - - CaptureOutputStream(PrintStream original, OutputStream copy) { - this.original = original; - this.copy = copy; - } - - PrintStream getOriginal() { - return this.original; - } - - @Override - public void write(int b) throws IOException { - this.copy.write(b); - this.original.write(b); - this.original.flush(); - } - - @Override - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - this.copy.write(b, off, len); - this.original.write(b, off, len); - } - - @Override - public void flush() throws IOException { - this.copy.flush(); - this.original.flush(); - } - } - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/CarSearchTest.java b/src/test/java/victor/training/cleancode/CarSearchTest.java deleted file mode 100644 index 23d659832..000000000 --- a/src/test/java/victor/training/cleancode/CarSearchTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class CarSearchTest { - - CarSearch searchEngine = new CarSearch(); - - CarModel fordFocusMk2 = new CarModel("Ford", "Focus", 2012, 2016); - - // Ford Focus: [2012 ---- 2016] - // Search: [2014 ---- 2018] - // can't afford a 2021 car - @Test - void byYear_match() { - CarSearchCriteria criteria = new CarSearchCriteria(2014, 2018, "Ford"); - - List models = searchEngine.filterCarModels(criteria, List.of(fordFocusMk2)); - - assertThat(models).hasSize(1); - } - @Test - void byYear_no_match() { - CarSearchCriteria criteria = new CarSearchCriteria(2017, 2018, "Ford"); - - List models = searchEngine.filterCarModels(criteria, List.of(fordFocusMk2)); - - assertThat(models).isEmpty(); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/GuardsTest.java b/src/test/java/victor/training/cleancode/GuardsTest.java deleted file mode 100644 index d087894df..000000000 --- a/src/test/java/victor/training/cleancode/GuardsTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -class GuardsTest { - - private final Guards guards = new Guards(); - - // generated via a 10 minutes chat with GitHub Copilot - @Test - void throwsExceptionForBonusPackageValueLessThan10() { - Marine marine = new Marine(false, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(9); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Not applicable!"); - } - - @Test - void throwsExceptionForInvalidBonusPackageValueTooLarge() { - Marine marine = new Marine(false, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(101); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Not applicable!"); - } - - @Test - void throwsExceptionForNullMarine() { - Marine marine = null; - BonusPackage bonusPackage = new BonusPackage(50); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Not applicable!"); - } - - @Test - void throwsExceptionForInvalidBonusPackageValue() { - Marine marine = new Marine(false, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(200); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)); - } - - @Test - void calculatesPayAmountForActiveMarine() { - Marine marine = new Marine(false, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(50); - - int payAmount = guards.getPayAmount(marine, bonusPackage); - - assertThat(payAmount).isEqualTo(1050); - } - - - @Test - void calculatesPayAmountForMarineWithThreeAwards() { - Award award = new Award(); - Marine marine = new Marine(false, false, 10, List.of(award, award, award)); - BonusPackage bonusPackage = new BonusPackage(50); - - int payAmount = guards.getPayAmount(marine, bonusPackage); - - assertThat(payAmount).isEqualTo(4050); - } - - @Test - void calculatesPayAmountForRetiredMarine() { - Marine marine = new Marine(false, true, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(50); - - int payAmount = guards.getPayAmount(marine, bonusPackage); - - assertThat(payAmount).isEqualTo(2); - } - - @Test - void calculatesPayAmountForMarineWithAwards() { - Award award = new Award(); - Marine marine = new Marine(false, false, 10, List.of(award)); - BonusPackage bonusPackage = new BonusPackage(50); - - int payAmount = guards.getPayAmount(marine, bonusPackage); - - assertThat(payAmount).isEqualTo(2050); - } - - @Test - void calculatesPayAmountForDeadMarine() { - Marine marine = new Marine(true, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(50); - - int payAmount = guards.getPayAmount(marine, bonusPackage); - - assertThat(payAmount).isEqualTo(Guards.DEAD_PAY_AMOUNT); - } - - @Test - void throwsExceptionForMarineWithNullYearsService() { - Marine marine = new Marine(false, false, null, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(50); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Any marine should have the years of service set"); - } - - @Test - void throwsExceptionForInvalidBonusPackage() { - Marine marine = new Marine(false, false, 10, Collections.emptyList()); - BonusPackage bonusPackage = new BonusPackage(200); - - assertThatThrownBy(() -> guards.getPayAmount(marine, bonusPackage)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Not applicable!"); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/SomeServiceTest.java b/src/test/java/victor/training/cleancode/SomeServiceTest.java deleted file mode 100644 index 7e26815b1..000000000 --- a/src/test/java/victor/training/cleancode/SomeServiceTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class SomeServiceTest { - - @Test - void greenMethodTest() { // bad test (evergreen) - new SomeService().greenMethod(1, new Task(5)); - } - - @Test - void yellowMethodTest() { - new SomeService().yellowMethod(1, new Task(5)); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/SplitLoopHardTest.java b/src/test/java/victor/training/cleancode/SplitLoopHardTest.java deleted file mode 100644 index 2e656921b..000000000 --- a/src/test/java/victor/training/cleancode/SplitLoopHardTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package victor.training.cleancode; - -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 victor.training.cleancode.SplitLoop.Employee; -import victor.training.cleancode.SplitLoopHard.EmployeeService; - -import java.util.Collections; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class SplitLoopHardTest { - @Mock - EmployeeService employeeService; - @InjectMocks - SplitLoopHard splitLoopHard; - - Employee consultant = new Employee(1, 24, 2000, true); - Employee employee = new Employee(2, 30, 4000, false); - - @Test - void consultantIdNull() { - consultant = consultant.toBuilder().id(null).build(); - - String actual = splitLoopHard.computeStatsHard(Collections.singletonList(consultant)); - - assertThat(actual).isEqualTo("Employee(s) not persisted"); - } - - @Test - void throws_consultantSalaryNull_retrieveNull() { - consultant = consultant.toBuilder().salary(null).build(); - when(employeeService.retrieveSalary(consultant.id())).thenReturn(null); - - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> - splitLoopHard.computeStatsHard(Collections.singletonList(consultant))); - } - - @Test - void consultantSalaryNull_retrieveSalary_avg() { - consultant = consultant.toBuilder().salary(null).build(); - when(employeeService.retrieveSalary(consultant.id())).thenReturn(3000); - Employee consultant2 = new Employee(15, 56, 5000, true); - - String actual = splitLoopHard.computeStatsHard(asList(consultant, consultant2)); - - assertThat(actual).isEqualTo("Average employee age = 0; Average consultant salary = 4000.0"); - } - - @Test - void employeeAgeAverage() { - Employee employee2 = new Employee(15, 56, 2000, false); - - String actual = splitLoopHard.computeStatsHard(asList(employee, employee2)); - - assertThat(actual).isEqualTo("Average employee age = 43; Average consultant salary = 0.0"); - } -} diff --git a/src/test/java/victor/training/cleancode/SplitLoopTest.java b/src/test/java/victor/training/cleancode/SplitLoopTest.java deleted file mode 100644 index 2ae857ce5..000000000 --- a/src/test/java/victor/training/cleancode/SplitLoopTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.SplitLoop.Employee; - -import java.util.ArrayList; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class SplitLoopTest { - - @Test - void computesCorrectAverageSalaryAndTotalConsultantSalary() { - List employees = List.of( - Employee.builder().id(1).age(24).salary(2000).consultant(false).build(), - Employee.builder().id(2).age(27).salary(2000).consultant(false).build(), - Employee.builder().id(3).age(28).salary(1500).consultant(true).build(), - Employee.builder().id(4).age(30).salary(2500).consultant(true).build() - ); - - String result = new SplitLoop().computeStats(employees); - - assertThat(result).isEqualTo("Total consultant salary: 4000.0; ids: [1, 2, 3, 4]"); - } - - @Test - void returnsZeroForEmptyEmployeeList() { - List employees = new ArrayList<>(); - - String result = new SplitLoop().computeStats(employees); - - assertThat(result).isEqualTo("Total consultant salary: 0.0; ids: []"); - } - - @Test - void computesCorrectlyWithAllConsultants() { - List employees = List.of( - Employee.builder().id(1).age(24).salary(3000).consultant(true).build(), - Employee.builder().id(2).age(27).salary(4000).consultant(true).build() - ); - - String result = new SplitLoop().computeStats(employees); - - assertThat(result).isEqualTo("Total consultant salary: 7000.0; ids: [1, 2]"); - } - - @Test - void computesCorrectlyWithNoConsultants() { - List employees = List.of( - Employee.builder().id(1).age(24).salary(2000).consultant(false).build(), - Employee.builder().id(2).age(27).salary(2500).consultant(false).build() - ); - - String result = new SplitLoop().computeStats(employees); - - assertThat(result).isEqualTo("Total consultant salary: 0.0; ids: [1, 2]"); - } - -} diff --git a/src/test/java/victor/training/cleancode/SwitchTest.java b/src/test/java/victor/training/cleancode/SwitchTest.java deleted file mode 100644 index 5d64840e6..000000000 --- a/src/test/java/victor/training/cleancode/SwitchTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package victor.training.cleancode; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import victor.training.cleancode.CaptureSystemOutput.OutputCapture; -import victor.training.cleancode.Switch.Movie; -import victor.training.cleancode.Switch.Movie.Category; - -import static org.assertj.core.api.Assertions.assertThat; - -class SwitchTest { - - private Switch target = new Switch(); - - @ParameterizedTest - @CsvSource({ - "REGULAR,4,5", - "NEW_RELEASE,3,6", - "CHILDREN,100,5"}) - void computePrice(Movie.Category category, int days, int expectedPrice) { - assertThat(target.computePrice(new Movie(category, "noop"), days)).isEqualTo(expectedPrice); - } - - @Test - @CaptureSystemOutput - void processMovie_regular(OutputCapture outputCapture) { - target.processMovie(new Movie(Category.REGULAR, "MMM")); - assertThat(outputCapture.toString()).isEqualToNormalizingNewlines(""" - Some repo calls - Some shared initial stuff - Process regular movie: Movie{category=REGULAR, title='MMM'} - More common code after - """); - } - @Test - @CaptureSystemOutput - void processMovie_new_release(OutputCapture outputCapture) { - target.processMovie(new Movie(Category.NEW_RELEASE, "MMM")); - assertThat(outputCapture.toString()).isEqualToNormalizingNewlines(""" - Some repo calls - Some shared initial stuff - Process new release movie: Movie{category=NEW_RELEASE, title='MMM'} - More common code after - """); - } - @Test - @CaptureSystemOutput - void processMovie_children(OutputCapture outputCapture) { - target.processMovie(new Movie(Category.CHILDREN, "MMM")); - assertThat(outputCapture.toString()).isEqualToNormalizingNewlines(""" - Some repo calls - Some shared initial stuff - Process children movie: Movie{category=CHILDREN, title='MMM'} - More common code after - """); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/extra/ReplaceTempWithQueryTest.java b/src/test/java/victor/training/cleancode/extra/ReplaceTempWithQueryTest.java deleted file mode 100644 index 9fc57c09d..000000000 --- a/src/test/java/victor/training/cleancode/extra/ReplaceTempWithQueryTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package victor.training.cleancode.extra; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.refactoring.ReplaceTempWithQuery; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.within; - -class ReplaceTempWithQueryTest { - @Test - void basePrice() { - ReplaceTempWithQuery pc = new ReplaceTempWithQuery(1, 5); - assertThat(pc.computePrice()).isCloseTo(4.9, within(0.001)); - assertThat(pc.computeFidelityPoints()).isEqualTo(2); - } - - @Test - void quantityDiscount() { - ReplaceTempWithQuery pc = new ReplaceTempWithQuery(10, 5); - assertThat(pc.computePrice()).isCloseTo(49, within(0.001)); - assertThat(pc.computeFidelityPoints()).isEqualTo(25); - } - - @Test - void amountDiscount() { - ReplaceTempWithQuery pc = new ReplaceTempWithQuery(1, 1001); - assertThat(pc.computePrice()).isCloseTo(950.95, within(0.01)); - assertThat(pc.computeFidelityPoints()).isEqualTo(500); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/extra/SplitVariableTest.java b/src/test/java/victor/training/cleancode/extra/SplitVariableTest.java deleted file mode 100644 index dc01c263b..000000000 --- a/src/test/java/victor/training/cleancode/extra/SplitVariableTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package victor.training.cleancode.extra; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static victor.training.cleancode.refactoring.SplitVariable.discount; - -class SplitVariableTest { - @Test - void test() { - assertThat(discount(1, 1)).isEqualTo(1); - assertThat(discount(50, 1)).isEqualTo(50); - assertThat(discount(51, 1)).isEqualTo(49); - assertThat(discount(1, 101)).isEqualTo(0); - assertThat(discount(50, 101)).isEqualTo(49); - assertThat(discount(51, 101)).isEqualTo(48); - } -} diff --git a/src/test/java/victor/training/cleancode/fp/FunctionalChainsawTest.java b/src/test/java/victor/training/cleancode/fp/FunctionalChainsawTest.java deleted file mode 100644 index ef6ea198c..000000000 --- a/src/test/java/victor/training/cleancode/fp/FunctionalChainsawTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package victor.training.cleancode.fp; - -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.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -import victor.training.cleancode.fp.support.*; - -import java.time.LocalDate; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; -import static victor.training.cleancode.fp.support.ProductCategory.HOME; - -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) -class FunctionalChainsawTest { - - @Mock - private ProductRepo productRepo; - - @Mock - private OrderRepo orderRepo; - - @InjectMocks - private FunctionalChainsaw functionalChainsaw; - - private Product product = new Product("Chair", HOME) - .setId(7L) - .setDeleted(false); - - private Order anOrder() { - return new Order() - .setActive(true) - .setCreationDate(LocalDate.now().minusDays(15)) - .setOrderLines(List.of(new OrderLine(product, 11))); - } - - @Test - void allInOneOrder() { - when(orderRepo.findAll()).thenReturn(List.of(anOrder())); - when(productRepo.getHiddenProductIds()).thenReturn(List.of()); - - assertThat(functionalChainsaw.getHotProducts()).containsExactly(product); - } - - @Test - void inTwoOrders() { - Order order1 = anOrder().setOrderLines(List.of(new OrderLine(product, 5))); - Order order2 = anOrder().setOrderLines(List.of(new OrderLine(product, 6))); - - when(orderRepo.findAll()).thenReturn(List.of(order1, order2)); - when(productRepo.getHiddenProductIds()).thenReturn(List.of()); - - assertThat(functionalChainsaw.getHotProducts()).containsExactly(product); - } - - @Test - void excludesDeletedProducts() { - product.setDeleted(true); - when(orderRepo.findAll()).thenReturn(List.of(anOrder())); - when(productRepo.getHiddenProductIds()).thenReturn(List.of()); - - assertThat(functionalChainsaw.getHotProducts()).isEmpty(); - } - - @Test - void excludesHiddenProducts() { - when(orderRepo.findAll()).thenReturn(List.of(anOrder())); - when(productRepo.getHiddenProductIds()).thenReturn(List.of(product.getId())); - - assertThat(functionalChainsaw.getHotProducts()).isEmpty(); - } - - @Test - void excludesOldOrders() { - when(orderRepo.findAll()).thenReturn(List.of(anOrder().setCreationDate(LocalDate.now().minusYears(1)))); - when(productRepo.getHiddenProductIds()).thenReturn(List.of()); - - assertThat(functionalChainsaw.getHotProducts()).isEmpty(); - } - - @Test - void excludesInactiveOrders() { - when(orderRepo.findAll()).thenReturn(List.of(anOrder().setActive(false))); - when(productRepo.getHiddenProductIds()).thenReturn(List.of()); - - assertThat(functionalChainsaw.getHotProducts()).isEmpty(); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/fp/LoanPatternTest.java b/src/test/java/victor/training/cleancode/fp/LoanPatternTest.java deleted file mode 100644 index f62269038..000000000 --- a/src/test/java/victor/training/cleancode/fp/LoanPatternTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package victor.training.cleancode.fp; - -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 victor.training.cleancode.fp.support.Order; -import victor.training.cleancode.fp.support.OrderRepo; - -import java.io.IOException; -import java.util.stream.Stream; - -import static java.time.LocalDate.parse; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class LoanPatternTest { - @Mock - private OrderRepo orderRepo; - @InjectMocks - private FileExportService exporter; - - - @Test - void exportOrders() throws IOException { - Order order = new Order(); - order.setId(1L); - order.setCreationDate(parse("2021-01-07")); - when(orderRepo.findByActiveTrue()).thenReturn(Stream.of(order)); - - new LoanPattern(exporter).exportOrders(); - - // NOW read the file from the disk ... Yuck! - -// assertEquals("OrderID;Date\n1;2021-01-07", sw.toString()); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/fp/MutantPipelineTest.java b/src/test/java/victor/training/cleancode/fp/MutantPipelineTest.java deleted file mode 100644 index 9828329a7..000000000 --- a/src/test/java/victor/training/cleancode/fp/MutantPipelineTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package victor.training.cleancode.fp; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.fp.support.*; - -import java.util.List; - -import static java.time.LocalDate.now; -import static java.util.Optional.empty; -import static java.util.Optional.of; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class MutantPipelineTest { - - - public static final long SSO_ID = 1L; - public static final long PAYMENT_CARD_ID = 123L; - PaymentCardRepository repository = mock(PaymentCardRepository.class); - MutantPipeline mutantPipeline = new MutantPipeline(repository, new PaymentCardMapper()); - - @Test - void totalOrderPrice() { - var orders = List.of( - new Order().setPrice(10).setActive(true), - new Order().setPrice(5).setActive(true), - new Order().setPrice(3).setActive(false) - ); - int result = mutantPipeline.totalActiveOrderPrice(orders); - assertThat(result).isEqualTo(15); - } - - @Test - void getShipDates() { - var orders = List.of( - new Order().setShipDate(now()).setActive(true), - new Order().setShipDate(null).setActive(true), - new Order().setShipDate(now()).setActive(false) - ); - var result = mutantPipeline.getShipDates(orders); - assertThat(result).containsExactly(now()); - } - - @Test - void updateCardAlias_success() { - when(repository.findById(PAYMENT_CARD_ID)).thenReturn(of(new PaymentCard().setId(SSO_ID))); - when(repository.save(any())).thenAnswer(i -> i.getArgument(0)); - - var result = mutantPipeline.updateCardAlias(PAYMENT_CARD_ID, SSO_ID, "UpdatedAlias"); - - assertThat(result).isEqualTo(new PaymentCardDto(SSO_ID, "UpdatedAlias")); - } - - @Test - void updateCardAlias_notFound_throwsException() { - when(repository.findById(PAYMENT_CARD_ID)).thenReturn(empty()); - - assertThatThrownBy(() -> mutantPipeline.updateCardAlias(PAYMENT_CARD_ID, SSO_ID, "UpdatedAlias")) - .isInstanceOf(IllegalArgumentException.class); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/fp/OptionalAbuseTest.java b/src/test/java/victor/training/cleancode/fp/OptionalAbuseTest.java deleted file mode 100644 index f23c57df5..000000000 --- a/src/test/java/victor/training/cleancode/fp/OptionalAbuseTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package victor.training.cleancode.fp; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import victor.training.cleancode.fp.OptionalAbuse.Entity; - -import static org.assertj.core.api.Assertions.assertThat; -import static victor.training.cleancode.fp.OptionalAbuse.Dto; - -@ExtendWith(MockitoExtension.class) -class OptionalAbuseTest { - - private final OptionalAbuse optionalAbuse = new OptionalAbuse(); - - @Test - void setsRecipientEmailWhenDtoHasValidRecipientPerson() { - Dto dto = new Dto(" JohnDoe ", 30); - - Entity result = optionalAbuse.trappedOptional(dto); - - assertThat(result.getRecipient()).isEqualTo("johndoe@example.com"); - } - - @Test - void setsAnonymousEmailWhenRecipientPersonIsBlank() { - Dto dto = new Dto(" ", 30); - - Entity result = optionalAbuse.trappedOptional(dto); - - assertThat(result.getRecipient()).isEqualTo("anonymous@example.com"); - } - - @Test - void setsAnonymousEmailWhenRecipientPersonIsNull() { - Dto dto = new Dto(null, 30); - - Entity result = optionalAbuse.trappedOptional(dto); - - assertThat(result.getRecipient()).isEqualTo("anonymous@example.com"); - } - -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/fp/PureFunctionsTest.java b/src/test/java/victor/training/cleancode/fp/PureFunctionsTest.java deleted file mode 100644 index c04cb7a76..000000000 --- a/src/test/java/victor/training/cleancode/fp/PureFunctionsTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package victor.training.cleancode.fp; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import victor.training.cleancode.fp.support.*; - -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class PureFunctionsTest { - @Mock - CustomerRepo customerRepo; - @Mock - ThirdPartyPricesApi thirdPartyPrices; - @Mock - CouponRepo couponRepo; - @Mock - ProductRepo productRepo; - @InjectMocks - PureFunction priceService; - @Captor - ArgumentCaptor> couponCaptor; - - @Test - void computePrices() { - Coupon coupon1 = new Coupon(ProductCategory.HOME, 2); - Coupon coupon2 = new Coupon(ProductCategory.ELECTRONICS, 4); - Customer customer = new Customer(List.of(coupon1, coupon2)); - when(customerRepo.findById(13L)).thenReturn(customer); - Product p1 = new Product().setId(1L).setCategory(ProductCategory.HOME); - Product p2 = new Product().setId(2L).setCategory(ProductCategory.KIDS); - when(productRepo.findAllById(List.of(1L, 2L))).thenReturn(List.of(p1, p2)); - when(thirdPartyPrices.fetchPrice(2L)).thenReturn(5d); - - Map result = priceService.computePrices(13L, List.of(1L, 2L), Map.of(1L, 10d)); - - verify(couponRepo).markUsedCoupons(eq(13L), couponCaptor.capture()); - assertThat(couponCaptor.getValue()).containsExactly(coupon1); - - assertThat(result) - .containsEntry(1L, 8d) - .containsEntry(2L, 5d); - } - -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/fp/ReduceAbuseTest.java b/src/test/java/victor/training/cleancode/fp/ReduceAbuseTest.java deleted file mode 100644 index 71d8e0df0..000000000 --- a/src/test/java/victor/training/cleancode/fp/ReduceAbuseTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package victor.training.cleancode.fp; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.fp.support.Order; -import victor.training.cleancode.fp.support.OrderLine; -import victor.training.cleancode.fp.support.Product; - -import java.time.LocalDate; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class ReduceAbuseTest { - - private final ReduceAbuse sut = new ReduceAbuse(); - - @Test - void noPremiumOrders() { - Order normalOrder = new Order().setPrice(100); - List orderList = List.of(normalOrder); - - var result = sut.getLastPremiumOrder(orderList); - - assertThat(result).isNull(); - } - - @Test - void onePremiumOrder() { - Order premiumOrder = new Order() - .setOrderLines(List.of(new OrderLine(new Product().setPremium(true), 1))) - .setCreationDate(LocalDate.of(2023, 3, 5)); - - List orderList = List.of(premiumOrder); - - var result = sut.getLastPremiumOrder(orderList); - - assertThat(result).isEqualTo(premiumOrder); - } - - @Test - void multiplePremiumOrders() { - Order premiumOrder1 = new Order() - .setOrderLines(List.of(new OrderLine(new Product().setPremium(true), 1))) - .setCreationDate(LocalDate.of(2023, 3, 4)); - - Order premiumOrder2 = new Order() - .setOrderLines(List.of(new OrderLine(new Product().setPremium(true), 1))) - .setCreationDate(LocalDate.of(2023, 3, 5)); - - List orderList = List.of(premiumOrder1, premiumOrder2); - - var result = sut.getLastPremiumOrder(orderList); - - assertThat(result).isEqualTo(premiumOrder2); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/immutable/PriceServiceTest.java b/src/test/java/victor/training/cleancode/immutable/PriceServiceTest.java deleted file mode 100644 index 59965985e..000000000 --- a/src/test/java/victor/training/cleancode/immutable/PriceServiceTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package victor.training.cleancode.immutable; - -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 java.math.BigDecimal.valueOf; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.when; - - -@ExtendWith(MockitoExtension.class) -class PriceServiceTest { - @Mock - private SupplierService supplierService; - @Mock - private LogisticsService logisticsService; - @InjectMocks - private PriceService priceService; - - @Test - void computePrice() { - when(supplierService.getCost(any(), any())).thenReturn(valueOf(80)); - when(logisticsService.estimateDeliveryCosts(any())).thenReturn(valueOf(20)); - - Product product = new Product(); - priceService.computePrice(product); - - assertThat(product.getPrice()).isEqualByComparingTo(valueOf(78)); - - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/kata/expense/ExpenseReportTest.java b/src/test/java/victor/training/cleancode/kata/expense/ExpenseReportTest.java deleted file mode 100644 index c5a78b9a3..000000000 --- a/src/test/java/victor/training/cleancode/kata/expense/ExpenseReportTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package victor.training.cleancode.kata.expense; - -import org.junit.jupiter.api.Test; -import victor.training.cleancode.CaptureSystemOutput; -import victor.training.cleancode.CaptureSystemOutput.OutputCapture; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class ExpenseReportTest { - - private ExpenseReport report = new ExpenseReport(); - - @Test - @CaptureSystemOutput - void decent(OutputCapture outputCapture) { - report.printReport(List.of( - new Expense("DINNER", 100), - new Expense("DINNER", 100), - new Expense("BREAKFAST", 50), - new Expense("CAR_RENTAL", 200) - )); - - assertThat(outputCapture.toString()).isEqualToIgnoringWhitespace( - """ - Expenses Report - Dinner 100 \s - Dinner 100 \s - Breakfast 50 \s - Car Rental 200 \s - Meal expenses: 250 - Total expenses: 450 - """); - } - - @Test - @CaptureSystemOutput - void bigBreakfast(OutputCapture outputCapture) { - report.printReport(List.of( - new Expense("BREAKFAST", 1200) - )); - - assertThat(outputCapture.toString()).isEqualToIgnoringWhitespace( - """ - Expenses Report - Breakfast 1200 X - Meal expenses: 1200 - Total expenses: 1200 - Meal expenses exceed limit - """); - } - - @Test - @CaptureSystemOutput - void bigDinner(OutputCapture outputCapture) { - report.printReport(List.of( - new Expense("DINNER", 5200) - )); - - assertThat(outputCapture.toString()).isEqualToIgnoringWhitespace( - """ - Expenses Report - Dinner 5200 X - Meal expenses: 5200 - Total expenses: 5200 - Meal expenses exceed limit - """); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/kata/povalidator/POValidatorTest.java b/src/test/java/victor/training/cleancode/kata/povalidator/POValidatorTest.java deleted file mode 100644 index b8e68b4be..000000000 --- a/src/test/java/victor/training/cleancode/kata/povalidator/POValidatorTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package victor.training.cleancode.kata.povalidator; - -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; - -class POValidatorTest { - POItem item = new POItem(); - - @Test - void validatePurchaseOrderItem_ItemValid_ReturnsTrue() { - var validator = new POValidator(); - validator.setValidators(Collections.emptyList()); - - var result = validator.validatePurchaseOrderItem(item); - - assertThat(result).isTrue(); - assertThat(item.getStatus()).isEqualTo(POItem.Status.NEW); - assertThat(item.getMessages()).isEmpty(); - } - - @Test - void validatePurchaseOrderItem_ItemInvalid_ReturnsFalseAndSetsStatus() { - Validator failingValidator = mock(Validator.class); - when(failingValidator.validate(any())).thenReturn(false); - when(failingValidator.message(any())).thenReturn("Validation failed"); - var validator = new POValidator(); - validator.setValidators(List.of(failingValidator)); - - var result = validator.validatePurchaseOrderItem(item); - - assertThat(result).isFalse(); - assertThat(item.getStatus()).isEqualTo(POItem.Status.ERROR); - assertThat(item.getMessages()).hasSize(1); - assertThat(item.getMessages().get(0).getText()).isEqualTo("Validation failed"); - } - - @Test - void validatePurchaseOrderItem_whenItemFails_midway_through() { - Validator failingValidator = mock(Validator.class); - when(failingValidator.validate(item)).thenReturn(Boolean.FALSE); - Validator uncalledValidator = mock(Validator.class); - POValidator validator = new POValidator(); - validator.setValidators(List.of(failingValidator, uncalledValidator)); - - assertThat(validator.validatePurchaseOrderItem(item)).isFalse(); - - verify(uncalledValidator, never()).validate(any()); - } -} \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/kata/streams/ExercisesTest.java b/src/test/java/victor/training/cleancode/kata/streams/ExercisesTest.java deleted file mode 100644 index 019504826..000000000 --- a/src/test/java/victor/training/cleancode/kata/streams/ExercisesTest.java +++ /dev/null @@ -1,254 +0,0 @@ -package victor.training.cleancode.kata.streams; - -import org.junit.jupiter.api.MethodOrderer.MethodName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import victor.training.cleancode.kata.streams.Order.PaymentMethod; -import victor.training.cleancode.kata.streams.Order.Status; - -import java.io.File; -import java.io.IOException; -import java.time.LocalDate; -import java.time.Month; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static java.time.LocalDate.now; -import static java.time.LocalDate.parse; -import static java.time.Month.FEBRUARY; -import static java.time.Month.JANUARY; -import static org.assertj.core.api.Assertions.assertThat; -import static victor.training.cleancode.kata.streams.Order.PaymentMethod.CARD; -import static victor.training.cleancode.kata.streams.Order.PaymentMethod.CASH_ON_DELIVERY; -import static victor.training.cleancode.kata.streams.Order.Status.CANCELLED; -import static victor.training.cleancode.kata.streams.Order.Status.COMPLETED; - -@TestMethodOrder(MethodName.class) -class ExercisesTest { - public static final LocalDate YESTERDAY = now().minusDays(1); - private static final LocalDate TODAY = LocalDate.now(); - private final Exercises sut = new Exercises(); - - @Test - void p1_activeOrders() { - Order order1 = new Order(COMPLETED) - .total(10) - .createdOn(TODAY) - .paymentMethod(CARD); - Order order2 = new Order(Status.PLACED); - - List dtos = sut.p1_activeOrders(List.of(order1, order2)); - - assertThat(dtos).hasSize(1); - assertThat(dtos.get(0).status()).isEqualTo(COMPLETED); - assertThat(dtos.get(0).totalPrice()).isEqualTo(10.0); - assertThat(dtos.get(0).creationDate()).isEqualTo(TODAY); - assertThat(dtos.get(0).paymentMethod()).isEqualTo(CARD); - } - - @Test - void p2_findOrderById_found() { - Order o = new Order(1); - List orders = List.of(o, new Order(2)); - // Note: AssertJ is preferred over JUnit assertions today - Order actual = sut.p2_findOrderById(orders, 1); - assertThat(actual).isEqualTo(o); - } - - @Test - void p2_findOrderById_notFound() { - Order actual = sut.p2_findOrderById(List.of(new Order(7)), 9999); - assertThat(actual).isNull(); - } - - @Test - void p3_hasActiveOrders_returnsTrue() { - boolean actual = sut.p3_hasActiveOrders(List.of(new Order(CANCELLED), new Order(COMPLETED))); - assertThat(actual).isTrue(); - } - - @Test - void p3_hasActiveOrders_returnsFalse() { - boolean actual = sut.p3_hasActiveOrders(List.of(new Order(CANCELLED))); - assertThat(actual).isFalse(); - } - - @Test - void p4_maxPriceOrder_doesMax() { - Order one = new Order().total(1); - Order ten = new Order().total(10); - Order actual = sut.p4_maxPriceOrder(List.of(one, ten)); - assertThat(actual).isEqualTo(ten); - } - - @Test - void p4_maxPriceOrder_returnsNullForNoOrders() { - assertThat(sut.p4_maxPriceOrder(List.of())).isNull(); - } - - @Test - void p4_maxPriceOrder_ignoresSpecialOffers() { - Order order = new Order().total(1) - .add(new OrderLine().specialOffer(true)); - assertThat(sut.p4_maxPriceOrder(List.of(order))).isNull(); - } - - @Test - void p5_last3Orders() { - Order a = new Order().createdOn(parse("2024-01-01")).returnReason("a"); - Order b = new Order().createdOn(parse("2024-01-02")).returnReason("b"); - Order c = new Order().createdOn(parse("2024-01-03")).returnReason("c"); - Order d = new Order().createdOn(parse("2024-01-04")).returnReason("d"); - - List actual = sut.p5_last3Orders(List.of(a, b, c, d)); - - assertThat(actual).containsExactly("d", "c", "b"); - } - - @Test - void p5_getLast3Orders_whenOnlyTwoOrders() { - Order a = new Order().createdOn(parse("2024-01-01")).returnReason("a"); - Order b = new Order().createdOn(parse("2024-01-02")).returnReason("b"); - - List actual = sut.p5_last3Orders(List.of(a, b)); - - assertThat(actual).containsExactly("b", "a"); - } - - @Test - void p5_getLast3Orders_skipsMissingReasons() { - Order a = new Order().createdOn(parse("2024-01-01")); - Order b = new Order().createdOn(parse("2024-01-02")).returnReason("b"); - - List actual = sut.p5_last3Orders(List.of(a, b)); - - assertThat(actual).containsExactly("b"); - } - - @Test - void p5_getLast3Orders_whenNoOrders() { - assertThat(sut.p5_last3Orders(List.of())).isEmpty(); - } - - @Test - void p6_completedTotalSum() { - Order a = new Order(COMPLETED).total(10); - Order b = new Order(COMPLETED).total(1); - Order c = new Order(CANCELLED).total(1); - - long actual = sut.p6_completedTotalSum(List.of(a, b, c)); - - assertThat(actual).isEqualTo(11); - } - - @Test - void p6_completedTotalSum_rounding() { - Order a = new Order(COMPLETED).total(10.5); - Order b = new Order(COMPLETED).total(10.5); - - long actual = sut.p6_completedTotalSum(List.of(a, b)); - - assertThat(actual).isEqualTo(21); - } - - @Test - void p7_productsSorted() { - Product chair = new Product("Chair"); - Product table = new Product("Table"); - Order order1 = new Order() - .add(new OrderLine(chair, 3)); - Order order2 = new Order() - .add(new OrderLine(table, 1)) - .add(new OrderLine(chair, 1)); - - List actual = sut.p7_productsSorted(List.of(order1, order2)); - - assertThat(actual).containsExactly(chair, table); - } - - @Test - void p8_ordersGroupedByPaymentMethod() { - Order a_card = new Order().paymentMethod(CARD); - Order b_cash = new Order().paymentMethod(CASH_ON_DELIVERY); - Order c_card = new Order().paymentMethod(CARD); - - Map> actual = sut.p8_ordersGroupedByPaymentMethod(List.of(a_card, b_cash, c_card)); - - assertThat(actual.get(CASH_ON_DELIVERY)).containsExactly(b_cash); - assertThat(actual.get(CARD)).containsExactly(a_card, c_card); - } - - @Test - void p9_productCount() { - Product chair = new Product("Chair"); - Product table = new Product("Table"); - Order order1 = new Order() - .add(new OrderLine(chair, 3)); - Order order2 = new Order() - .add(new OrderLine(table, 1)) - .add(new OrderLine(chair, 1)); - - Map actual = sut.p9_productCount(List.of(order1, order2)); - - Map expected = Map.of( - chair, 4, - table, 1); - assertThat(actual).isEqualTo(expected); - } - - @Test - void pA_productNames() { - Product armchair = new Product("Armchair"); - Product chair = new Product("Chair"); - Product table = new Product("Table"); - - Order order1 = new Order() - .add(new OrderLine(chair, 3)); - Order order2 = new Order() - .add(new OrderLine(armchair, 1)) - .add(new OrderLine(table, 1)) - .add(new OrderLine(chair, 1)); - - String actual = sut.pA_productNames(List.of(order1, order2)); - assertThat(actual).isEqualTo("Armchair,Chair,Table"); - } - - - @Test - void pB_ordersByPaymentPerMonth_should_return_correct_grouping() { - Order a = new Order().paymentMethod(CARD).createdOn(parse("2024-01-15")); - Order b = new Order().paymentMethod(CASH_ON_DELIVERY).createdOn(parse("2024-01-07")); - Order c = new Order().paymentMethod(CARD).createdOn(parse("2024-02-17")); - List orders = List.of(a, b, c); - - Map>> result = sut.pB_ordersByPaymentPerMonth(orders); - - var expected = Map.of( - JANUARY, Map.of( - CARD, List.of(a), - CASH_ON_DELIVERY, List.of(b) - ), - FEBRUARY, Map.of( - CARD, List.of(c) - ) - ); - assertThat(result).isEqualTo(expected); - } - - @Test - void blankLinesInFile() throws IOException { - File file = new File("src/test/java/victor/training/cleancode/kata/streams/sample.csv"); - - Set actual = sut.pC_csvLinesInAllFilesInFolder(file); - - Set expected = Set.of(1, 2, 3); - assertThat(actual).isEqualTo(expected); - } - - @Test - void pDFib() { - assertThat(sut.pD_fib(0, 6)).containsExactly(1, 1, 2, 3, 5, 8); - assertThat(sut.pD_fib(5, 9)).containsExactly(8, 13, 21, 34); - } -} diff --git a/src/test/java/victor/training/cleancode/kata/streams/sample.csv b/src/test/java/victor/training/cleancode/kata/streams/sample.csv deleted file mode 100644 index 7c21815a4..000000000 --- a/src/test/java/victor/training/cleancode/kata/streams/sample.csv +++ /dev/null @@ -1,4 +0,0 @@ -1;abc -2;ads - -3;stuff \ No newline at end of file diff --git a/src/test/java/victor/training/cleancode/openrewrite/AssertJAd.java b/src/test/java/victor/training/cleancode/openrewrite/AssertJAd.java deleted file mode 100644 index 639002abf..000000000 --- a/src/test/java/victor/training/cleancode/openrewrite/AssertJAd.java +++ /dev/null @@ -1,297 +0,0 @@ -package victor.training.cleancode.openrewrite; - - -import org.assertj.core.api.AbstractAssert; -import org.assertj.core.api.Assertions; -import org.assertj.core.api.AutoCloseableSoftAssertions; -import org.assertj.core.api.SoftAssertions; -import org.assertj.core.api.junit.jupiter.InjectSoftAssertions; -import org.assertj.core.api.junit.jupiter.SoftlyExtension; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.MethodOrderer.MethodName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Set; - -import static java.time.LocalDateTime.now; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; - - -@Disabled("enable on demand and compare failures of JUnit❌ and AssertJ💖") -public class AssertJAd { // from org.assertj:assertj-core, or via spring-boot-starter-test - - @Nested - @TestMethodOrder(MethodName.class) - public class CollectionsPrimitives { - List aList = List.of(100, 200, 300, 300); - - @Test - public void size1_JUnit() { - org.junit.jupiter.api.Assertions.assertEquals(1, aList.size()); - } - - @Test - public void size1_AssertJ() { - assertThat(aList).hasSize(1); - } - - @Test - public void onceInAnyOrder_JUnit() { - org.junit.jupiter.api.Assertions.assertTrue(aList.containsAll(List.of(100, 200, 700))); - assertEquals(3, aList.size()); - } - - @Test - public void onceInAnyOrder_AssertJ() { - assertThat(aList).containsExactlyInAnyOrder(100, 200, 300); - } - - @Test - public void contains_JUnit() { - assertTrue(aList.containsAll(List.of(100, 200, 400))); - assertFalse(aList.contains(500)); - } - - @Test - public void contains_AssertJ() { - assertThat(aList) - .contains(100, 200, 400) - .doesNotContain(500); - } - - } - - @Nested - @TestMethodOrder(MethodName.class) - public class CollectionsElements { - record Character(String name, int age, Race race) { - } - - record Race(String name) { - } - - private final List fellowship = List.of( - new Character("Frodo", 20, new Race("Hobbit")), - new Character("Sam", 18, new Race("Hobbit")), - new Character("Legolas", 1000, new Race("Elf")), - new Character("Boromir", 37, new Race("Man")), - new Character("Gandalf the Gray", 120, new Race("Man")), - new Character("Aragorn", 39, new Race("Man")), - new Character("Gimli", 40, new Race("Dwarf")) - ); - - @Test - public void oneAttribute_JUnit() { - // preprocess the collection before the assertion: - Set races = fellowship.stream() - .map(Character::race) - .map(Race::name) - .collect(toSet()); - - assertEquals(Set.of("Man", "Dwarf", "Elf", "Hobbit", "Orc"), races); - } - - @Test - public void oneAttribute_AssertJ() { - assertThat(fellowship) - .map(Character::race) - .map(Race::name) - .containsOnly("Man", "Dwarf", "Elf", "Hobbit", "Orc"); - } - - @Test - public void multipleAttributes_JUnit() { - assertTrue(fellowship.stream().anyMatch(c -> - c.name().equals("Frodo") && - c.age() == 20 && - c.race().name().equals("Hobbit"))); - assertTrue(fellowship.stream().anyMatch(c -> - c.name().equals("Aragorn") && - c.age() == 39 && - c.race().name().equals("Man"))); - assertTrue(fellowship.stream().anyMatch(c -> - c.name().equals("Legolas") && - c.age() == 100 && // ❌ -// c.age() == 1000 && // ✅ - c.race().name().equals("Elf"))); - } - - @Test - public void multipleAttributes_AssertJ() { - assertThat(fellowship) - // .extracting("name", "age", "race.name") // alternative - .extracting(Character::name, Character::age, c -> c.race().name()) - .contains( - tuple("Frodo", 20, "Hobbit"), - tuple("Legolas", 100, "Elf"), // ❌ -// tuple("Legolas", 1000, "Elf"), // ✅ - tuple("Aragorn", 39, "Man") - ); - } - } - - @Nested - @TestMethodOrder(MethodName.class) - public class Strings { - private final String string = "abcdef"; - - @Test - public void startsWith_JUnit() { - assertTrue(string.startsWith("bcd")); // see the failure message - } - - @Test - public void startsWith_AssertJ() { - assertThat(string).startsWith("bcd"); // see the failure message - } - - @Test - public void ignoreCase_JUnit() { - assertEquals("ABCDE", string.toUpperCase()); // looses the original case - } - - @Test - public void ignoreCase_AssertJ() { - assertThat(string).isEqualToIgnoringCase("AbCdE"); - } - - @Test - public void regex_JUnit() { - assertTrue(string.matches(".*bd.*")); - } - - @Test - public void regex_AssertJ() { - assertThat(string).matches(".*bd.*"); - } - } - - @Nested - @TestMethodOrder(MethodName.class) - public class Time { - private final LocalDateTime oneMinAgo = now().minusMinutes(1); - - @Test - public void deltaTime_JUnit() { - assertTrue(oneMinAgo.isAfter(now().minusSeconds(1))); - } - - @Test - public void deltaTime_AssertJ() { - assertThat(oneMinAgo).isCloseTo(now(), byLessThan(1, SECONDS)); - } - } - - - record Villa(int guests, String kitchen, String library) { - } - - static Villa testedCode() { - return new Villa(6, "dirty", "clean"); - } - - @Nested - @TestMethodOrder(MethodName.class) - public class CustomAssertions { - @Test - void extendingAssertJ() { - Villa villa = testedCode(); - - assertThat(villa) - .hasGuests(7) // "extension methods" (java style👴🏻) - .hasKitchen("clean") - .hasLibrary("clean"); - } - - public static VillaAssert assertThat(Villa actual) { - return new VillaAssert(actual); - } - - static class VillaAssert extends AbstractAssert { - protected VillaAssert(Villa actual) { - super(actual, VillaAssert.class); - } - - public VillaAssert hasGuests(int guests) { - Assertions.assertThat(actual.guests()).as("Living Guests") - .isEqualTo(guests); - return this; - } - - public VillaAssert hasKitchen(String kitchen) { - Assertions.assertThat(actual.kitchen()).as("Kitchen") - .isEqualTo(kitchen); - return this; - } - - public VillaAssert hasLibrary(String library) { - Assertions.assertThat(actual.library()).as("Library") - .isEqualTo(library); - return this; - } - } - - } - - @Nested - class SoftAssert { - - interface EventSender { - void send(String event); - - } - - EventSender eventSender = Mockito.mock(EventSender.class); - - @Test - void failsOnFirst_BAD() { - Villa villa = testedCode(); - - assertThat(villa.guests()).as("Living Guests").isEqualTo(7); - assertThat(villa.kitchen()).as("Kitchen").isEqualTo("clean"); - assertThat(villa.library()).as("Library").isEqualTo("clean"); - Mockito.verify(eventSender).send("mansion-cleaned"); - } - - @Test - void trySoftly() { - Villa villa = testedCode(); - - try (var softly = new AutoCloseableSoftAssertions()) { - softly.assertThat(villa.guests()).as("Living Guests").isEqualTo(7); - softly.assertThat(villa.kitchen()).as("Kitchen").isEqualTo("clean"); - softly.assertThat(villa.library()).as("Library").isEqualTo("clean"); - softly.assertThatCode(() -> Mockito.verify(eventSender).send("mansion-cleaned")) - .as("event published").doesNotThrowAnyException(); - } - } - - @Nested - @ExtendWith(SoftlyExtension.class) - class WithExtension { - @InjectSoftAssertions - SoftAssertions soft; - - @Test - void usingExtension() { - Villa villa = testedCode(); - - soft.assertThat(villa.guests()).as("Living Guests").isEqualTo(7); - soft.assertThat(villa.kitchen()).as("Kitchen").isEqualTo("clean"); - soft.assertThat(villa.library()).as("Library").isEqualTo("clean"); - soft.assertThatCode(() -> Mockito.verify(eventSender).send("mansion-cleaned")) - .as("event published").doesNotThrowAnyException(); - } - } - } -} - diff --git a/src/test/java/victor/training/cleancode/openrewrite/JUnitToAssertJTestDemo.java b/src/test/java/victor/training/cleancode/openrewrite/JUnitToAssertJTestDemo.java deleted file mode 100644 index d7dbb40c5..000000000 --- a/src/test/java/victor/training/cleancode/openrewrite/JUnitToAssertJTestDemo.java +++ /dev/null @@ -1,33 +0,0 @@ -package victor.training.cleancode.openrewrite; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class JUnitToAssertJTestDemo { - @Test - void test() { - assertTrue(testedCode().contains("eS")); - assertTrue(testedCode().startsWith("re")); - } - - private String testedCode() { - return notification(false); - } - - - @Test - void testExceptions() { - assertThrows(IllegalArgumentException.class, () -> notification(true)); - } - - private String notification(boolean shouldThrow) { - if (shouldThrow) throw new IllegalArgumentException("Boom"); - return "result"; - } - // 1) run openrewrite-assertj.yaml in IntelliJ, or - // 2) mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-testing-frameworks:RELEASE -Drewrite.activeRecipes=org.openrewrite.java.testing.assertj.JUnitAssertEqualsToAssertThat -Drewrite.exportDatatables=true - -} - From 4682adaf332317951fa25ea08fa79485f81fcc13 Mon Sep 17 00:00:00 2001 From: Victor Rentea Date: Fri, 17 Oct 2025 14:26:25 +0300 Subject: [PATCH 02/16] works on my machine --- pom.xml | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 0c59f5d70..ab1049cb5 100644 --- a/pom.xml +++ b/pom.xml @@ -67,16 +67,22 @@ org.junit.jupiter - junit-jupiter-engine - 5.10.0 + junit-jupiter test - org.junit.jupiter - junit-jupiter-params - 5.10.0 + org.mockito + mockito-junit-jupiter + 5.14.2 + test + + + org.mockito + mockito-core + 5.14.2 test + org.assertj @@ -84,13 +90,19 @@ 3.24.2 test - - org.mockito - mockito-junit-jupiter - 5.10.0 - test - + + + + + org.junit + junit-bom + 5.10.3 + pom + import + + + From 5ec6121a06bcc182c79224f7c26444cd415823c6 Mon Sep 17 00:00:00 2001 From: nlecroar Date: Fri, 17 Oct 2025 13:31:53 +0200 Subject: [PATCH 03/16] Test push --- todo | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/todo b/todo index 941462b2b..c908024ca 100644 --- a/todo +++ b/todo @@ -1,2 +1,4 @@ Function Frenzy example -Redo Videostore another real world example \ No newline at end of file +Redo Videostore another real world example + +Nico \ No newline at end of file From 16077596da9a7a146ab73b7f1187e351265b546f Mon Sep 17 00:00:00 2001 From: Corrado Pacelli Date: Fri, 17 Oct 2025 13:35:17 +0200 Subject: [PATCH 04/16] first commit from me --- first_commit.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 first_commit.txt diff --git a/first_commit.txt b/first_commit.txt new file mode 100644 index 000000000..76e0ec49e --- /dev/null +++ b/first_commit.txt @@ -0,0 +1,3 @@ +Montale + +Mi illumino di immenso \ No newline at end of file From 2633a5cdf318a2c4309bc66825fc62b062fe4da9 Mon Sep 17 00:00:00 2001 From: Beatriz Avila Date: Fri, 17 Oct 2025 13:32:48 +0200 Subject: [PATCH 05/16] Test commit --- .../training/cleancode/kata/projectservice/ExerciseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/victor/training/cleancode/kata/projectservice/ExerciseTest.java b/src/test/java/victor/training/cleancode/kata/projectservice/ExerciseTest.java index cb61f3112..a5237d574 100644 --- a/src/test/java/victor/training/cleancode/kata/projectservice/ExerciseTest.java +++ b/src/test/java/victor/training/cleancode/kata/projectservice/ExerciseTest.java @@ -13,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; - +// Test commit (Beatriz) @ExtendWith(MockitoExtension.class) class ExerciseTest { @Mock From 8835d0408e4b60675445c176f019a71f22ee113e Mon Sep 17 00:00:00 2001 From: Beatriz Avila Date: Fri, 17 Oct 2025 13:57:24 +0200 Subject: [PATCH 06/16] Created enum for PriceCode --- .../cleancode/kata/videostore/Customer.java | 114 +++++++++--------- .../cleancode/kata/videostore/Movie.java | 36 +++--- .../cleancode/kata/videostore/PriceCode.java | 5 + .../kata/videostore/CustomerTest.java | 11 +- 4 files changed, 87 insertions(+), 79 deletions(-) create mode 100644 src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index f0be4e0f5..046cef65a 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -3,60 +3,64 @@ import java.util.LinkedHashMap; import java.util.Map; +import static victor.training.cleancode.kata.videostore.PriceCode.*; + class Customer { - private final String name; - private final Map rentals = new LinkedHashMap<>(); // preserves order of elements TODO find a better way to store this - - public Customer(String name) { - this.name = name; - }; - - public void addRental(Movie m, int d) { - rentals.put(m, d); - } - - public String getName() { - return name; - } - - public String statement() { - double totalAmount = 0; - int frequentRenterPoints = 0; - String result = "Rental Record for " + getName() + "\n"; - // loop over each movie rental - for (Movie each : rentals.keySet()) { - double thisAmount = 0; - // determine amounts for every line - int dr = rentals.get(each); - switch (each.getPriceCode()) { - case Movie.REGULAR: - thisAmount += 2; - if (dr > 2) - thisAmount += (dr - 2) * 1.5; - break; - case Movie.NEW_RELEASE: - thisAmount += dr * 3; - break; - case Movie.CHILDRENS: - thisAmount += 1.5; - if (dr > 3) - thisAmount += (dr - 3) * 1.5; - break; - } - // add frequent renter points - frequentRenterPoints++; - // add bonus for a two day new release rental - if (each.getPriceCode() != null && - (each.getPriceCode() == Movie.NEW_RELEASE) - && dr > 1) - frequentRenterPoints++; - // show figures line for this rental - result += "\t" + each.getTitle() + "\t" + thisAmount + "\n"; - totalAmount += thisAmount; - } - // add footer lines - result += "Amount owed is " + totalAmount + "\n"; - result += "You earned " + frequentRenterPoints + " frequent renter points"; - return result; - } + private final String name; + private final Map rentals = new LinkedHashMap<>(); // preserves order of elements TODO find a better way to store this + + public Customer(String name) { + this.name = name; + } + + ; + + public void addRental(Movie m, int d) { + rentals.put(m, d); + } + + public String getName() { + return name; + } + + public String statement() { + double totalAmount = 0; + int frequentRenterPoints = 0; + String result = "Rental Record for " + getName() + "\n"; + // loop over each movie rental + for (Movie each : rentals.keySet()) { + double thisAmount = 0; + // determine amounts for every line + int dr = rentals.get(each); + switch (each.getPriceCode()) { + case REGULAR: + thisAmount += 2; + if (dr > 2) + thisAmount += (dr - 2) * 1.5; + break; + case NEW_RELEASE: + thisAmount += dr * 3; + break; + case CHILDRENS: + thisAmount += 1.5; + if (dr > 3) + thisAmount += (dr - 3) * 1.5; + break; + } + // add frequent renter points + frequentRenterPoints++; + // add bonus for a two day new release rental + if (each.getPriceCode() != null && + (each.getPriceCode() == NEW_RELEASE) + && dr > 1) + frequentRenterPoints++; + // show figures line for this rental + result += "\t" + each.getTitle() + "\t" + thisAmount + "\n"; + totalAmount += thisAmount; + } + // add footer lines + result += "Amount owed is " + totalAmount + "\n"; + result += "You earned " + frequentRenterPoints + " frequent renter points"; + return result; + } } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java index b4ccfab0c..c9267030d 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java @@ -1,25 +1,25 @@ package victor.training.cleancode.kata.videostore; + public class Movie { - public static final int CHILDRENS = 2; - public static final int REGULAR = 0; - public static final int NEW_RELEASE = 1; - private String _title; - Integer _priceCode; + private final String _title; + private PriceCode _priceCode; + + public Movie(String title, PriceCode priceCode) { + _title = title; + _priceCode = priceCode; + } - public Movie(String title, Integer priceCode) { - _title = title; - _priceCode = priceCode; - } + public PriceCode getPriceCode() { + return _priceCode; + } - public Integer getPriceCode() { - return _priceCode; - } + public void setPriceCode(PriceCode arg) { + _priceCode = arg; + } - public void setPriceCode(Integer arg) { - _priceCode = arg; - } + public String getTitle() { + return _title; + } - public String getTitle() { - return _title; - }; + ; } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java new file mode 100644 index 000000000..079186263 --- /dev/null +++ b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java @@ -0,0 +1,5 @@ +package victor.training.cleancode.kata.videostore; + +public enum PriceCode { + REGULAR, NEW_RELEASE, CHILDRENS; +} diff --git a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java index c45c22467..238aecf91 100644 --- a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java +++ b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java @@ -1,10 +1,9 @@ package victor.training.cleancode.kata.videostore; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static victor.training.cleancode.kata.videostore.PriceCode.*; class CustomerTest { @@ -13,10 +12,10 @@ class CustomerTest { void characterizationTest() { Customer customer = new Customer("John Doe"); // customer.addRental(new Movie("Star Wars", Movie.BABACI), 6); - customer.addRental(new Movie("Star Wars", Movie.NEW_RELEASE), 6); - customer.addRental(new Movie("Sofia", Movie.CHILDRENS), 7); - customer.addRental(new Movie("Inception", Movie.REGULAR), 5); - customer.addRental(new Movie("Wicked", Movie.CHILDRENS), 3); + customer.addRental(new Movie("Star Wars", NEW_RELEASE), 6); + customer.addRental(new Movie("Sofia", CHILDRENS), 7); + customer.addRental(new Movie("Inception", REGULAR), 5); + customer.addRental(new Movie("Wicked", CHILDRENS), 3); String expected = """ Rental Record for John Doe From eddf29fb5e6a4e38538a903f284203d48c11844b Mon Sep 17 00:00:00 2001 From: nlecroar Date: Fri, 17 Oct 2025 14:04:57 +0200 Subject: [PATCH 07/16] Renaming, remove dead code, final --- .../cleancode/kata/videostore/Movie.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java index c9267030d..a3a8e13b9 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java @@ -1,25 +1,20 @@ package victor.training.cleancode.kata.videostore; public class Movie { - private final String _title; - private PriceCode _priceCode; + private final String title; + private final PriceCode priceCode; public Movie(String title, PriceCode priceCode) { - _title = title; - _priceCode = priceCode; + this.title = title; + this.priceCode = priceCode; } public PriceCode getPriceCode() { - return _priceCode; - } - - public void setPriceCode(PriceCode arg) { - _priceCode = arg; + return priceCode; } public String getTitle() { - return _title; + return title; } - ; } \ No newline at end of file From 149f249d377d6bd66e88e85c32c4f8e064c26c56 Mon Sep 17 00:00:00 2001 From: nlecroar Date: Fri, 17 Oct 2025 14:14:14 +0200 Subject: [PATCH 08/16] Renaming + introduce record for Movie --- .../cleancode/kata/videostore/Customer.java | 27 +++++++++---------- .../cleancode/kata/videostore/Movie.java | 17 +----------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index 046cef65a..2cc185b87 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -13,10 +13,9 @@ public Customer(String name) { this.name = name; } - ; - public void addRental(Movie m, int d) { - rentals.put(m, d); + public void addRental(Movie m, int price) { + rentals.put(m, price); } public String getName() { @@ -31,31 +30,31 @@ public String statement() { for (Movie each : rentals.keySet()) { double thisAmount = 0; // determine amounts for every line - int dr = rentals.get(each); - switch (each.getPriceCode()) { + int price = rentals.get(each); + switch (each.priceCode()) { case REGULAR: thisAmount += 2; - if (dr > 2) - thisAmount += (dr - 2) * 1.5; + if (price > 2) + thisAmount += (price - 2) * 1.5; break; case NEW_RELEASE: - thisAmount += dr * 3; + thisAmount += price * 3; break; case CHILDRENS: thisAmount += 1.5; - if (dr > 3) - thisAmount += (dr - 3) * 1.5; + if (price > 3) + thisAmount += (price - 3) * 1.5; break; } // add frequent renter points frequentRenterPoints++; // add bonus for a two day new release rental - if (each.getPriceCode() != null && - (each.getPriceCode() == NEW_RELEASE) - && dr > 1) + if (each.priceCode() != null && + (each.priceCode() == NEW_RELEASE) + && price > 1) frequentRenterPoints++; // show figures line for this rental - result += "\t" + each.getTitle() + "\t" + thisAmount + "\n"; + result += "\t" + each.title() + "\t" + thisAmount + "\n"; totalAmount += thisAmount; } // add footer lines diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java index a3a8e13b9..37c174367 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Movie.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Movie.java @@ -1,20 +1,5 @@ package victor.training.cleancode.kata.videostore; -public class Movie { - private final String title; - private final PriceCode priceCode; - - public Movie(String title, PriceCode priceCode) { - this.title = title; - this.priceCode = priceCode; - } - - public PriceCode getPriceCode() { - return priceCode; - } - - public String getTitle() { - return title; - } +public record Movie(String title, PriceCode priceCode) { } \ No newline at end of file From 3ee5f871a7e61d171099ee4f28711bcb337e8d39 Mon Sep 17 00:00:00 2001 From: Corrado Pacelli Date: Fri, 17 Oct 2025 14:34:12 +0200 Subject: [PATCH 09/16] in between a refactor of Customer.Statement --- .../cleancode/kata/videostore/Customer.java | 20 ++++++++++--------- .../cleancode/kata/videostore/Statement.java | 4 ++++ 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 src/main/java/victor/training/cleancode/kata/videostore/Statement.java diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index 2cc185b87..8a43f1857 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -22,16 +22,17 @@ public String getName() { return name; } - public String statement() { + public Statement statement() { double totalAmount = 0; int frequentRenterPoints = 0; String result = "Rental Record for " + getName() + "\n"; - // loop over each movie rental - for (Movie each : rentals.keySet()) { + // loop over movie rental + Map finalPricePerMovie = new LinkedHashMap<>(); + for (Movie movie : rentals.keySet()) { double thisAmount = 0; // determine amounts for every line - int price = rentals.get(each); - switch (each.priceCode()) { + int price = rentals.get(movie); + switch (movie.priceCode()) { case REGULAR: thisAmount += 2; if (price > 2) @@ -49,17 +50,18 @@ public String statement() { // add frequent renter points frequentRenterPoints++; // add bonus for a two day new release rental - if (each.priceCode() != null && - (each.priceCode() == NEW_RELEASE) + if (movie.priceCode() != null && + (movie.priceCode() == NEW_RELEASE) && price > 1) frequentRenterPoints++; // show figures line for this rental - result += "\t" + each.title() + "\t" + thisAmount + "\n"; + result += "\t" + movie.title() + "\t" + thisAmount + "\n"; totalAmount += thisAmount; + finalPricePerMovie.put(movie, totalAmount); } // add footer lines result += "Amount owed is " + totalAmount + "\n"; result += "You earned " + frequentRenterPoints + " frequent renter points"; - return result; + return new Statement(totalAmount, points, movieAndPrice); } } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java new file mode 100644 index 000000000..ec43e7820 --- /dev/null +++ b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java @@ -0,0 +1,4 @@ +package victor.training.cleancode.kata.videostore; + +public record Statement(double totalAmount, int frequentRenterPoints, Map rentalAmounts) { +} From cf394e848dfc14a0389bb237d5ea3e0eb705192d Mon Sep 17 00:00:00 2001 From: Beatriz Avila Date: Fri, 17 Oct 2025 14:48:24 +0200 Subject: [PATCH 10/16] Pause this refactoring of the return type for the test --- .../cleancode/kata/videostore/Customer.java | 19 ++++++++++--------- .../cleancode/kata/videostore/Statement.java | 4 +++- .../kata/videostore/CustomerTest.java | 8 +++++++- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index 8a43f1857..ea3e8b3e9 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -26,25 +26,26 @@ public Statement statement() { double totalAmount = 0; int frequentRenterPoints = 0; String result = "Rental Record for " + getName() + "\n"; + // loop over movie rental Map finalPricePerMovie = new LinkedHashMap<>(); for (Movie movie : rentals.keySet()) { double thisAmount = 0; // determine amounts for every line - int price = rentals.get(movie); + int days = rentals.get(movie); switch (movie.priceCode()) { case REGULAR: thisAmount += 2; - if (price > 2) - thisAmount += (price - 2) * 1.5; + if (days > 2) + thisAmount += (days - 2) * 1.5; break; case NEW_RELEASE: - thisAmount += price * 3; + thisAmount += days * 3; break; case CHILDRENS: thisAmount += 1.5; - if (price > 3) - thisAmount += (price - 3) * 1.5; + if (days > 3) + thisAmount += (days - 3) * 1.5; break; } // add frequent renter points @@ -52,16 +53,16 @@ public Statement statement() { // add bonus for a two day new release rental if (movie.priceCode() != null && (movie.priceCode() == NEW_RELEASE) - && price > 1) + && days > 1) frequentRenterPoints++; // show figures line for this rental result += "\t" + movie.title() + "\t" + thisAmount + "\n"; + finalPricePerMovie.put(movie, totalAmount); totalAmount += thisAmount; - finalPricePerMovie.put(movie, totalAmount); } // add footer lines result += "Amount owed is " + totalAmount + "\n"; result += "You earned " + frequentRenterPoints + " frequent renter points"; - return new Statement(totalAmount, points, movieAndPrice); + return new Statement(totalAmount, frequentRenterPoints, finalPricePerMovie, result); } } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java index ec43e7820..f0761b5ae 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java @@ -1,4 +1,6 @@ package victor.training.cleancode.kata.videostore; -public record Statement(double totalAmount, int frequentRenterPoints, Map rentalAmounts) { +import java.util.Map; + +public record Statement(double totalAmount, int frequentRenterPoints, Map rentalAmounts, String sorryTemp) { } diff --git a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java index 238aecf91..b2eaddc7c 100644 --- a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java +++ b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Test; +import java.util.Map; + import static org.junit.jupiter.api.Assertions.assertEquals; import static victor.training.cleancode.kata.videostore.PriceCode.*; @@ -28,7 +30,11 @@ void characterizationTest() { // assertThat(customer.statement()).isEqualToIgnoringNewLines(expected); // if above line fails to compile, uncomment the next line: - assertEquals(normalizeNewLines(expected), normalizeNewLines(customer.statement())); + Statement statement = customer.statement(); + assertEquals(33.5, statement.totalAmount()); + assertEquals(5, statement.frequentRenterPoints()); + Map expectedRealAmounts = statement.rentalAmounts(); + assertEquals(normalizeNewLines(expected), normalizeNewLines(statement.sorryTemp())); } private String normalizeNewLines(String expected) { From 7fa8d831de3515204f1ac8ae75c5abc14681cb70 Mon Sep 17 00:00:00 2001 From: Beatriz Avila Date: Fri, 17 Oct 2025 14:53:54 +0200 Subject: [PATCH 11/16] Created Rental class with Movie and days --- .../cleancode/kata/videostore/Customer.java | 18 +++++++++--------- .../cleancode/kata/videostore/Rental.java | 4 ++++ 2 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 src/main/java/victor/training/cleancode/kata/videostore/Rental.java diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index ea3e8b3e9..d5e82484f 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -1,21 +1,22 @@ package victor.training.cleancode.kata.videostore; import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; -import static victor.training.cleancode.kata.videostore.PriceCode.*; +import static victor.training.cleancode.kata.videostore.PriceCode.NEW_RELEASE; class Customer { private final String name; - private final Map rentals = new LinkedHashMap<>(); // preserves order of elements TODO find a better way to store this + private final List rentals = new LinkedList<>(); // preserves order of elements TODO find a better way to store this public Customer(String name) { this.name = name; } - public void addRental(Movie m, int price) { - rentals.put(m, price); + rentals.add(new Rental(m, price)); } public String getName() { @@ -29,10 +30,11 @@ public Statement statement() { // loop over movie rental Map finalPricePerMovie = new LinkedHashMap<>(); - for (Movie movie : rentals.keySet()) { + for (Rental rental : rentals) { double thisAmount = 0; // determine amounts for every line - int days = rentals.get(movie); + int days = rental.days(); + Movie movie = rental.movie(); switch (movie.priceCode()) { case REGULAR: thisAmount += 2; @@ -51,9 +53,7 @@ public Statement statement() { // add frequent renter points frequentRenterPoints++; // add bonus for a two day new release rental - if (movie.priceCode() != null && - (movie.priceCode() == NEW_RELEASE) - && days > 1) + if (movie.priceCode() == NEW_RELEASE && days > 1) frequentRenterPoints++; // show figures line for this rental result += "\t" + movie.title() + "\t" + thisAmount + "\n"; diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Rental.java b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java new file mode 100644 index 000000000..e2bf8d608 --- /dev/null +++ b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java @@ -0,0 +1,4 @@ +package victor.training.cleancode.kata.videostore; + +public record Rental(Movie movie, Integer days) { +} From 7eba4199298e9d9d76f69313d196355f33ed69e9 Mon Sep 17 00:00:00 2001 From: nlecroar Date: Fri, 17 Oct 2025 15:14:25 +0200 Subject: [PATCH 12/16] Move price computation to Rental --- .../cleancode/kata/videostore/Customer.java | 22 ++++--------------- .../cleancode/kata/videostore/PriceCode.java | 3 ++- .../cleancode/kata/videostore/Rental.java | 22 ++++++++++++++++++- .../kata/videostore/CustomerTest.java | 4 ++-- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index d5e82484f..d4294ca54 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -15,8 +15,8 @@ public Customer(String name) { this.name = name; } - public void addRental(Movie m, int price) { - rentals.add(new Rental(m, price)); + public void addRental(Movie movie, int days) { + rentals.add(new Rental(movie, days)); } public String getName() { @@ -31,25 +31,10 @@ public Statement statement() { // loop over movie rental Map finalPricePerMovie = new LinkedHashMap<>(); for (Rental rental : rentals) { - double thisAmount = 0; // determine amounts for every line int days = rental.days(); Movie movie = rental.movie(); - switch (movie.priceCode()) { - case REGULAR: - thisAmount += 2; - if (days > 2) - thisAmount += (days - 2) * 1.5; - break; - case NEW_RELEASE: - thisAmount += days * 3; - break; - case CHILDRENS: - thisAmount += 1.5; - if (days > 3) - thisAmount += (days - 3) * 1.5; - break; - } + double thisAmount = rental.computeRentalPrice(); // add frequent renter points frequentRenterPoints++; // add bonus for a two day new release rental @@ -65,4 +50,5 @@ public Statement statement() { result += "You earned " + frequentRenterPoints + " frequent renter points"; return new Statement(totalAmount, frequentRenterPoints, finalPricePerMovie, result); } + } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java index 079186263..b4a5d8eb6 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java @@ -1,5 +1,6 @@ package victor.training.cleancode.kata.videostore; public enum PriceCode { - REGULAR, NEW_RELEASE, CHILDRENS; + REGULAR, NEW_RELEASE, CHILDREN; + } diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Rental.java b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java index e2bf8d608..7be1b21c8 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Rental.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java @@ -1,4 +1,24 @@ package victor.training.cleancode.kata.videostore; -public record Rental(Movie movie, Integer days) { +public record Rental(Movie movie, int days) { + + double computeRentalPrice() { + double thisAmount = 0; + switch (movie.priceCode()) { + case REGULAR: + thisAmount += 2; + if (days > 2) + thisAmount += (days - 2) * 1.5; + return thisAmount; + case NEW_RELEASE: + thisAmount += days * 3; + return thisAmount; + case CHILDREN: + thisAmount += 1.5; + if (days > 3) + thisAmount += (days - 3) * 1.5; + return thisAmount; + } + return thisAmount; + } } diff --git a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java index b2eaddc7c..fa52785a8 100644 --- a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java +++ b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java @@ -15,9 +15,9 @@ void characterizationTest() { Customer customer = new Customer("John Doe"); // customer.addRental(new Movie("Star Wars", Movie.BABACI), 6); customer.addRental(new Movie("Star Wars", NEW_RELEASE), 6); - customer.addRental(new Movie("Sofia", CHILDRENS), 7); + customer.addRental(new Movie("Sofia", CHILDREN), 7); customer.addRental(new Movie("Inception", REGULAR), 5); - customer.addRental(new Movie("Wicked", CHILDRENS), 3); + customer.addRental(new Movie("Wicked", CHILDREN), 3); String expected = """ Rental Record for John Doe From e2ce5e2506fe484d5c83c58d74a1c2992aee5ab7 Mon Sep 17 00:00:00 2001 From: Corrado Pacelli Date: Fri, 17 Oct 2025 15:24:03 +0200 Subject: [PATCH 13/16] extract computation of renter points --- .../cleancode/kata/videostore/Customer.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index d4294ca54..45f6d16d2 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -25,30 +25,35 @@ public String getName() { public Statement statement() { double totalAmount = 0; - int frequentRenterPoints = 0; String result = "Rental Record for " + getName() + "\n"; - // loop over movie rental Map finalPricePerMovie = new LinkedHashMap<>(); for (Rental rental : rentals) { // determine amounts for every line - int days = rental.days(); Movie movie = rental.movie(); double thisAmount = rental.computeRentalPrice(); - // add frequent renter points - frequentRenterPoints++; - // add bonus for a two day new release rental - if (movie.priceCode() == NEW_RELEASE && days > 1) - frequentRenterPoints++; // show figures line for this rental result += "\t" + movie.title() + "\t" + thisAmount + "\n"; finalPricePerMovie.put(movie, totalAmount); totalAmount += thisAmount; } + int frequentRenterPoints = computeFrequentRenterPoints(); // add footer lines result += "Amount owed is " + totalAmount + "\n"; result += "You earned " + frequentRenterPoints + " frequent renter points"; return new Statement(totalAmount, frequentRenterPoints, finalPricePerMovie, result); } + private int computeFrequentRenterPoints() { + int frequentRenterPoints = 0; + for (Rental rental : rentals) { + // add frequent renter points + frequentRenterPoints++; + // add bonus for a two day new release rental + if (rental.movie().priceCode() == NEW_RELEASE && rental.days() > 1) + frequentRenterPoints++; + } + return frequentRenterPoints; + } + } \ No newline at end of file From fe7bcd14e2ac73622afc79430b8f32158fcdf79e Mon Sep 17 00:00:00 2001 From: Beatriz Avila Date: Fri, 17 Oct 2025 15:47:47 +0200 Subject: [PATCH 14/16] toString in the Statement class and fix tests --- .../cleancode/kata/videostore/Customer.java | 26 +++++++------------ .../cleancode/kata/videostore/Statement.java | 17 +++++++++++- .../kata/videostore/CustomerTest.java | 6 ++--- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index 45f6d16d2..d2421da0c 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -1,5 +1,7 @@ package victor.training.cleancode.kata.videostore; +import lombok.Getter; + import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -8,6 +10,7 @@ import static victor.training.cleancode.kata.videostore.PriceCode.NEW_RELEASE; class Customer { + @Getter private final String name; private final List rentals = new LinkedList<>(); // preserves order of elements TODO find a better way to store this @@ -19,29 +22,18 @@ public void addRental(Movie movie, int days) { rentals.add(new Rental(movie, days)); } - public String getName() { - return name; - } - public Statement statement() { - double totalAmount = 0; - String result = "Rental Record for " + getName() + "\n"; - // loop over movie rental - Map finalPricePerMovie = new LinkedHashMap<>(); + double totalAmount = rentals.stream().mapToDouble(Rental::computeRentalPrice).sum(); + + Map finalPricePerMovie = new LinkedHashMap<>(); for (Rental rental : rentals) { // determine amounts for every line - Movie movie = rental.movie(); double thisAmount = rental.computeRentalPrice(); - // show figures line for this rental - result += "\t" + movie.title() + "\t" + thisAmount + "\n"; - finalPricePerMovie.put(movie, totalAmount); - totalAmount += thisAmount; + finalPricePerMovie.put(rental.movie(), thisAmount); } + int frequentRenterPoints = computeFrequentRenterPoints(); - // add footer lines - result += "Amount owed is " + totalAmount + "\n"; - result += "You earned " + frequentRenterPoints + " frequent renter points"; - return new Statement(totalAmount, frequentRenterPoints, finalPricePerMovie, result); + return new Statement(this, totalAmount, frequentRenterPoints, finalPricePerMovie); } private int computeFrequentRenterPoints() { diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java index f0761b5ae..8c41afeb4 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java @@ -1,6 +1,21 @@ package victor.training.cleancode.kata.videostore; import java.util.Map; +import java.util.stream.Collectors; -public record Statement(double totalAmount, int frequentRenterPoints, Map rentalAmounts, String sorryTemp) { +public record Statement(Customer customer, double totalAmount, int frequentRenterPoints, + Map rentalAmounts) { + + @Override + public String toString() { + String result = "Rental Record for " + customer.getName() + "\n"; + + result += rentalAmounts.entrySet().stream().map(movieDoubleEntry -> + "\t" + movieDoubleEntry.getKey().title() + "\t" + movieDoubleEntry.getValue() + "\n" + ).collect(Collectors.joining()); + + result += "Amount owed is " + totalAmount + "\n"; + result += "You earned " + frequentRenterPoints + " frequent renter points"; + return result; + } } diff --git a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java index fa52785a8..6fbd48600 100644 --- a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java +++ b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java @@ -31,10 +31,8 @@ void characterizationTest() { // assertThat(customer.statement()).isEqualToIgnoringNewLines(expected); // if above line fails to compile, uncomment the next line: Statement statement = customer.statement(); - assertEquals(33.5, statement.totalAmount()); - assertEquals(5, statement.frequentRenterPoints()); - Map expectedRealAmounts = statement.rentalAmounts(); - assertEquals(normalizeNewLines(expected), normalizeNewLines(statement.sorryTemp())); + + assertEquals(normalizeNewLines(expected), normalizeNewLines(statement.toString())); } private String normalizeNewLines(String expected) { From 7d6b39ff2a3de202ba7bd951171969a521aaab27 Mon Sep 17 00:00:00 2001 From: nlecroar Date: Fri, 17 Oct 2025 16:01:10 +0200 Subject: [PATCH 15/16] Use streams --- .../cleancode/kata/videostore/Customer.java | 18 ++++++++---------- .../kata/videostore/RentalAmount.java | 4 ++++ .../cleancode/kata/videostore/Statement.java | 8 ++++---- 3 files changed, 16 insertions(+), 14 deletions(-) create mode 100644 src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index d2421da0c..223523916 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -6,11 +6,11 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static victor.training.cleancode.kata.videostore.PriceCode.NEW_RELEASE; class Customer { - @Getter private final String name; private final List rentals = new LinkedList<>(); // preserves order of elements TODO find a better way to store this @@ -18,22 +18,20 @@ public Customer(String name) { this.name = name; } + public String getName() { + return name; + } + public void addRental(Movie movie, int days) { rentals.add(new Rental(movie, days)); } public Statement statement() { - double totalAmount = rentals.stream().mapToDouble(Rental::computeRentalPrice).sum(); - - Map finalPricePerMovie = new LinkedHashMap<>(); - for (Rental rental : rentals) { - // determine amounts for every line - double thisAmount = rental.computeRentalPrice(); - finalPricePerMovie.put(rental.movie(), thisAmount); - } + List rentalAmounts = rentals.stream().map(entry -> new RentalAmount(entry.movie(), entry.computeRentalPrice())).toList(); + double totalRentalAmount = rentalAmounts.stream().mapToDouble(RentalAmount::amount).sum(); int frequentRenterPoints = computeFrequentRenterPoints(); - return new Statement(this, totalAmount, frequentRenterPoints, finalPricePerMovie); + return new Statement(this, totalRentalAmount, frequentRenterPoints, rentalAmounts); } private int computeFrequentRenterPoints() { diff --git a/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java b/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java new file mode 100644 index 000000000..50f0039d3 --- /dev/null +++ b/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java @@ -0,0 +1,4 @@ +package victor.training.cleancode.kata.videostore; + +public record RentalAmount(Movie movie, double amount) { +} diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java index 8c41afeb4..5a683edb9 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java @@ -1,17 +1,17 @@ package victor.training.cleancode.kata.videostore; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; public record Statement(Customer customer, double totalAmount, int frequentRenterPoints, - Map rentalAmounts) { + List rentalAmounts) { @Override public String toString() { String result = "Rental Record for " + customer.getName() + "\n"; - result += rentalAmounts.entrySet().stream().map(movieDoubleEntry -> - "\t" + movieDoubleEntry.getKey().title() + "\t" + movieDoubleEntry.getValue() + "\n" + result += rentalAmounts.stream().map(rentalAmount -> + "\t" + rentalAmount.movie().title() + "\t" + rentalAmount.amount() + "\n" ).collect(Collectors.joining()); result += "Amount owed is " + totalAmount + "\n"; From 8d0e1f43a1853c9155ebfa9a972cf921fcfd0026 Mon Sep 17 00:00:00 2001 From: Victor Rentea Date: Fri, 17 Oct 2025 17:10:38 +0300 Subject: [PATCH 16/16] good --- .../cleancode/kata/videostore/Customer.java | 72 +++++++++---------- .../cleancode/kata/videostore/PriceCode.java | 2 +- .../cleancode/kata/videostore/Rental.java | 2 +- .../kata/videostore/RentalAmount.java | 4 -- .../cleancode/kata/videostore/Statement.java | 28 ++++---- .../kata/videostore/CustomerTest.java | 2 +- 6 files changed, 52 insertions(+), 58 deletions(-) delete mode 100644 src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java index 223523916..27e462270 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Customer.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Customer.java @@ -1,49 +1,45 @@ package victor.training.cleancode.kata.videostore; -import lombok.Getter; - -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import static victor.training.cleancode.kata.videostore.PriceCode.NEW_RELEASE; class Customer { - private final String name; - private final List rentals = new LinkedList<>(); // preserves order of elements TODO find a better way to store this - - public Customer(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void addRental(Movie movie, int days) { - rentals.add(new Rental(movie, days)); - } - - public Statement statement() { - List rentalAmounts = rentals.stream().map(entry -> new RentalAmount(entry.movie(), entry.computeRentalPrice())).toList(); - double totalRentalAmount = rentalAmounts.stream().mapToDouble(RentalAmount::amount).sum(); - - int frequentRenterPoints = computeFrequentRenterPoints(); - return new Statement(this, totalRentalAmount, frequentRenterPoints, rentalAmounts); - } - - private int computeFrequentRenterPoints() { - int frequentRenterPoints = 0; - for (Rental rental : rentals) { - // add frequent renter points - frequentRenterPoints++; - // add bonus for a two day new release rental - if (rental.movie().priceCode() == NEW_RELEASE && rental.days() > 1) - frequentRenterPoints++; - } - return frequentRenterPoints; + private final String name; + private final List rentals = new LinkedList<>(); + + public Customer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void addRental(Movie movie, int days) { + rentals.add(new Rental(movie, days)); + } + + public Statement statement() { + double totalRentalAmount = computeTotalAmount(); + int frequentRenterPoints = computeFrequentRenterPoints(); + return new Statement(name, totalRentalAmount, frequentRenterPoints, rentals); + } + + private double computeTotalAmount() { + return rentals.stream().mapToDouble(Rental::computePrice).sum(); + } + + private int computeFrequentRenterPoints() { + int frequentRenterPoints = 0; + for (Rental rental : rentals) { + frequentRenterPoints++; + // add bonus for a two day new release rental + if (rental.movie().priceCode() == NEW_RELEASE && rental.days() > 1) + frequentRenterPoints++; } + return frequentRenterPoints; + } } \ No newline at end of file diff --git a/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java index b4a5d8eb6..95d14b80f 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/PriceCode.java @@ -1,6 +1,6 @@ package victor.training.cleancode.kata.videostore; public enum PriceCode { - REGULAR, NEW_RELEASE, CHILDREN; + REGULAR, NEW_RELEASE, CHILDREN } diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Rental.java b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java index 7be1b21c8..9f95f4979 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Rental.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Rental.java @@ -2,7 +2,7 @@ public record Rental(Movie movie, int days) { - double computeRentalPrice() { + double computePrice() { double thisAmount = 0; switch (movie.priceCode()) { case REGULAR: diff --git a/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java b/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java deleted file mode 100644 index 50f0039d3..000000000 --- a/src/main/java/victor/training/cleancode/kata/videostore/RentalAmount.java +++ /dev/null @@ -1,4 +0,0 @@ -package victor.training.cleancode.kata.videostore; - -public record RentalAmount(Movie movie, double amount) { -} diff --git a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java index 5a683edb9..407da24e8 100644 --- a/src/main/java/victor/training/cleancode/kata/videostore/Statement.java +++ b/src/main/java/victor/training/cleancode/kata/videostore/Statement.java @@ -3,19 +3,21 @@ import java.util.List; import java.util.stream.Collectors; -public record Statement(Customer customer, double totalAmount, int frequentRenterPoints, - List rentalAmounts) { +public record Statement( + String customerName, + double totalAmount, + int frequentRenterPoints, + List rentals) { - @Override - public String toString() { - String result = "Rental Record for " + customer.getName() + "\n"; + public String format() { + String result = "Rental Record for " + customerName + "\n"; + result += rentals.stream().map(this::formatRental).collect(Collectors.joining()); + result += "Amount owed is " + totalAmount + "\n"; + result += "You earned " + frequentRenterPoints + " frequent renter points"; + return result; + } - result += rentalAmounts.stream().map(rentalAmount -> - "\t" + rentalAmount.movie().title() + "\t" + rentalAmount.amount() + "\n" - ).collect(Collectors.joining()); - - result += "Amount owed is " + totalAmount + "\n"; - result += "You earned " + frequentRenterPoints + " frequent renter points"; - return result; - } + private String formatRental(Rental rentalAmount) { + return "\t" + rentalAmount.movie().title() + "\t" + rentalAmount.computePrice() + "\n"; + } } diff --git a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java index 6fbd48600..9ce913000 100644 --- a/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java +++ b/src/test/java/victor/training/cleancode/kata/videostore/CustomerTest.java @@ -32,7 +32,7 @@ void characterizationTest() { // if above line fails to compile, uncomment the next line: Statement statement = customer.statement(); - assertEquals(normalizeNewLines(expected), normalizeNewLines(statement.toString())); + assertEquals(normalizeNewLines(expected), normalizeNewLines(statement.format())); } private String normalizeNewLines(String expected) {