From 839a40f1f86319c204f35ef85f8887058c1b677b Mon Sep 17 00:00:00 2001 From: aitestmate Date: Thu, 21 May 2026 10:20:15 +0000 Subject: [PATCH 1/2] [chore] [mod-orders] unit tests --- .../orders/utils/PoLineCommonUtilTest.java | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) diff --git a/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java b/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java index f84d542ff..810f962f4 100644 --- a/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java +++ b/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java @@ -21,6 +21,25 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import static org.folio.rest.core.exceptions.ErrorCodes.PROHIBITED_FIELD_CHANGING; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.Collection; +import java.util.Map; +import org.folio.rest.jaxrs.model.Error; +import static org.hamcrest.Matchers.contains; +import io.vertx.core.json.JsonArray; +import org.folio.orders.utils.PoLineCommonUtil; +import org.folio.rest.core.exceptions.ErrorCodes; +import java.util.Collections; +import org.folio.rest.jaxrs.model.Ongoing; +import java.util.Date; +import java.time.Instant; +import org.folio.rest.jaxrs.model.Parameter; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import org.junit.jupiter.params.provider.ValueSource; @CopilotGenerated(partiallyGenerated = true) public class PoLineCommonUtilTest { @@ -247,6 +266,296 @@ void testExtractUnaffiliatedLocationsHandleNullLocationTenantId() { assertTrue(result.contains(locations.get(1))); } + @Test + void testVerifyProtectedFieldsChangedShouldDetectScalarFieldChange() { + // TestMate-fcee0817e0fb477dda0345cf59133ea1 + // Given + List protectedFields = List.of("poLineNumber", "isPackage"); + JsonObject objectFromStorage = new JsonObject() + .put("poLineNumber", "1000-1") + .put("isPackage", true); + JsonObject requestObject = new JsonObject() + .put("poLineNumber", "1000-2") + .put("isPackage", false); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject) + ); + // Then + assertEquals(400, exception.getCode()); + Error error = exception.getError(); + assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); + Map additionalProperties = error.getAdditionalProperties(); + Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); + + assertThat((Collection) modifiedFields, containsInAnyOrder("poLineNumber", "isPackage")); + } + + @Test + void testVerifyProtectedFieldsChangedShouldDetectArraySizeDecrease() { + // TestMate-7c59c6e9741685700ad64171c7f676d6 + // Given + String protectedField = "details.productIds"; + List protectedFields = List.of(protectedField); + String productIdType = UUID.randomUUID().toString(); + + ProductId firstProductId = new ProductId() + .withProductId("9780735245341") + .withProductIdType(productIdType); + ProductId secondProductId = new ProductId() + .withProductId("9780593492543") + .withProductIdType(productIdType); + String poLineId = UUID.randomUUID().toString(); + PoLine lineFromStorage = new PoLine() + .withId(poLineId) + .withDetails(new Details().withProductIds(List.of(firstProductId, secondProductId))); + + PoLine requestObject = new PoLine() + .withId(poLineId) + .withDetails(new Details().withProductIds(List.of(firstProductId))); + JsonObject lineFromStorageJson = JsonObject.mapFrom(lineFromStorage); + JsonObject requestObjectJson = JsonObject.mapFrom(requestObject); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, lineFromStorageJson, requestObjectJson) + ); + // Then + assertEquals(400, exception.getCode()); + Error error = exception.getError(); + assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); + + Map additionalProperties = error.getAdditionalProperties(); + Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); + assertThat((Collection) modifiedFields, contains(protectedField)); + } + + @Test + void testVerifyProtectedFieldsChangedShouldDetectArrayContentMismatchSameSize() { + // TestMate-557f9017f8ed07ba36247fa5b6b84c6b + // Given + String protectedField = "tags.tagList"; + List protectedFields = List.of(protectedField); + JsonObject objectFromStorage = new JsonObject() + .put("tags", new JsonObject() + .put("tagList", new JsonArray().add("urgent"))); + JsonObject requestObject = new JsonObject() + .put("tags", new JsonObject() + .put("tagList", new JsonArray().add("normal"))); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject) + ); + // Then + assertEquals(400, exception.getCode()); + Error error = exception.getError(); + assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); + Map additionalProperties = error.getAdditionalProperties(); + Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); + assertThat((Collection) modifiedFields, contains(protectedField)); + } + + @Test + void testVerifyProtectedFieldsChangedShouldIgnoreUnprotectedFieldChanges() { + // TestMate-2cf9247ee4f691a5aa390dbf1d481c14 + // Given + List protectedFields = List.of("id"); + String id = "11111111-1111-1111-1111-111111111111"; + JsonObject objectFromStorage = new JsonObject() + .put("id", id) + .put("description", "Old Description"); + JsonObject requestObject = new JsonObject() + .put("id", id) + .put("description", "New Description"); + // When + JsonObject result = PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject); + // Then + assertEquals(objectFromStorage, result); + } + + @Test + void testVerifyProtectedFieldsChangedShouldHandleNestedFieldPaths() { + // TestMate-defcd112d0e57c836878823cedcaef6c + // Given + String protectedFieldPath = "cost.currency"; + List protectedFields = List.of(protectedFieldPath); + JsonObject objectFromStorage = new JsonObject() + .put("cost", new JsonObject() + .put("currency", "USD") + .put("listUnitPrice", 10.0)); + JsonObject requestObject = new JsonObject() + .put("cost", new JsonObject() + .put("currency", "EUR") + .put("listUnitPrice", 10.0)); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject) + ); + // Then + assertEquals(400, exception.getCode()); + Error error = exception.getError(); + assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); + Map additionalProperties = error.getAdditionalProperties(); + Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); + assertThat((Collection) modifiedFields, contains(protectedFieldPath)); + } + + @Test + void testVerifyProtectedFieldsChangedShouldHandleEmptyProtectedFieldsList() { + // TestMate-69d03db6b9de005e4433ca20ca1445ee + // Given + List protectedFields = Collections.emptyList(); + String id = "00000000-0000-0000-0000-000000000001"; + + JsonObject objectFromStorage = new JsonObject() + .put("id", id) + .put("name", "Original Name") + .put("status", "Pending"); + + JsonObject requestObject = new JsonObject() + .put("id", UUID.fromString("00000000-0000-0000-0000-000000000002").toString()) + .put("name", "Changed Name") + .put("status", "Active"); + // When + JsonObject result = PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject); + // Then + assertEquals(objectFromStorage, result); + } + + @Test + void testVerifyProtectedFieldsChangedShouldDetectChangesInMultipleProtectedFields() { + // TestMate-a9add8ed0d1f7a0fe476f740af1ee27e + // Given + List protectedFields = List.of("id", "source"); + JsonObject objectFromStorage = new JsonObject() + .put("id", "1") + .put("source", "FOLIO") + .put("description", "Old Description"); + JsonObject requestObject = new JsonObject() + .put("id", "2") + .put("source", "MARC") + .put("description", "New Description"); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, objectFromStorage, requestObject) + ); + // Then + assertEquals(400, exception.getCode()); + Error error = exception.getError(); + assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); + Map additionalProperties = error.getAdditionalProperties(); + Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); + assertThat((Collection) modifiedFields, containsInAnyOrder("id", "source")); + } + + @ParameterizedTest + @CsvSource(value = { + "reviewDate|2024-01-01T00:00:00Z", + "manualRenewal|true" + }, delimiter = '|') + void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenSubscriptionFieldsModified(String fieldName, String newValue) { + // TestMate-1e7f8d73471208534f55a8712f35d569 + // Given + JsonObject ongoingStorage = new JsonObject() + .put("isSubscription", true) + .put("reviewDate", "2023-01-01T00:00:00Z") + .put("manualRenewal", false); + JsonObject storageJson = new JsonObject().put("ongoing", ongoingStorage); + // Map from storage to request to ensure fields not under test remain identical during comparison + Ongoing ongoingRequest = ongoingStorage.mapTo(Ongoing.class); + if ("reviewDate".equals(fieldName)) { + ongoingRequest.setReviewDate(Date.from(Instant.parse(newValue))); + } else if ("manualRenewal".equals(fieldName)) { + ongoingRequest.setManualRenewal(Boolean.valueOf(newValue)); + } + CompositePurchaseOrder requestCompPO = new CompositePurchaseOrder().withOngoing(ongoingRequest); + // When + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyOngoingFieldsChanged(storageJson, requestCompPO) + ); + // Then + assertEquals(400, exception.getCode()); + assertEquals(ErrorCodes.WRONG_ONGOING_SUBSCRIPTION_FIELDS_CHANGED.getCode(), exception.getError().getCode()); + // Find the specific parameter related to the field being tested to avoid index-based failures + Parameter parameter = exception.getErrors().getErrors().get(0).getParameters().stream() + .filter(p -> p.getKey().equals(fieldName)) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected parameter not found: " + fieldName)); + String expectedValue = newValue; + if ("reviewDate".equals(fieldName)) { + // Vert.x JsonObject serializes java.util.Date to epoch milliseconds by default. + // The method under test uses newObject.getValueAt(field).toString(), which results in the string of that long value. + expectedValue = String.valueOf(Instant.parse(newValue).toEpochMilli()); + } + assertEquals(fieldName, parameter.getKey()); + assertEquals(expectedValue, parameter.getValue()); + } + + @ParameterizedTest + @CsvSource(value = { + "interval|10", + "renewalDate|2024-01-15T10:30:00Z", + "reviewPeriod|5", + "manualRenewal|true" + }, delimiter = '|') + void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenNonSubscriptionFieldsModified(String fieldName, String newValue) { + // TestMate-6800fce4f0684e383b323eea15366367 + //given + JsonObject ongoingStorage = new JsonObject() + .put("isSubscription", false) + .put("interval", 1) + .put("renewalDate", "2023-01-15T10:30:00Z") + .put("reviewPeriod", 1) + .put("manualRenewal", false); + JsonObject storageJson = new JsonObject().put("ongoing", ongoingStorage); + Ongoing ongoingRequest = ongoingStorage.mapTo(Ongoing.class); + if ("interval".equals(fieldName)) { + ongoingRequest.setInterval(Integer.valueOf(newValue)); + } else if ("renewalDate".equals(fieldName)) { + ongoingRequest.setRenewalDate(Date.from(Instant.parse(newValue))); + } else if ("reviewPeriod".equals(fieldName)) { + ongoingRequest.setReviewPeriod(Integer.valueOf(newValue)); + } else if ("manualRenewal".equals(fieldName)) { + ongoingRequest.setManualRenewal(Boolean.valueOf(newValue)); + } + CompositePurchaseOrder requestCompPO = new CompositePurchaseOrder().withOngoing(ongoingRequest); + //when + HttpException exception = assertThrows(HttpException.class, () -> + PoLineCommonUtil.verifyOngoingFieldsChanged(storageJson, requestCompPO) + ); + //then + assertEquals(400, exception.getCode()); + assertEquals(ErrorCodes.WRONG_ONGOING_NOT_SUBSCRIPTION_FIELDS_CHANGED.getCode(), exception.getError().getCode()); + Parameter parameter = exception.getErrors().getErrors().get(0).getParameters().stream() + .filter(p -> p.getKey().equals(fieldName)) + .findFirst() + .orElseThrow(() -> new AssertionError("Expected parameter not found: " + fieldName)); + String expectedValue = newValue; + if ("renewalDate".equals(fieldName)) { + expectedValue = String.valueOf(Instant.parse(newValue).toEpochMilli()); + } + assertEquals(fieldName, parameter.getKey()); + assertEquals(expectedValue, parameter.getValue()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testVerifyOngoingFieldsChangedShouldSucceedWhenAllowedFieldsModified(boolean isSubscription) { + // TestMate-495401ee096d3b81e566755f6a634940 + // Given + JsonObject ongoingStorage = new JsonObject() + .put("isSubscription", isSubscription) + .put("notes", "Original Note") + .put("manualRenewal", false); + JsonObject storageJson = new JsonObject().put("ongoing", ongoingStorage); + Ongoing ongoingRequest = new Ongoing() + .withIsSubscription(isSubscription) + .withNotes("Updated Note") + .withManualRenewal(false); + CompositePurchaseOrder requestCompPO = new CompositePurchaseOrder().withOngoing(ongoingRequest); + // When & Then + assertDoesNotThrow(() -> PoLineCommonUtil.verifyOngoingFieldsChanged(storageJson, requestCompPO)); + } + private static Location createLocation(String tenantId) { return new Location().withTenantId(tenantId); } From 35f20f47e0a82639bcec423b4b40e84cf9680094 Mon Sep 17 00:00:00 2001 From: Viachaslau Khandramai Date: Wed, 27 May 2026 15:35:24 +0200 Subject: [PATCH 2/2] Code optimization, refactoring --- .../orders/utils/PoLineCommonUtilTest.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java b/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java index 810f962f4..628162de6 100644 --- a/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java +++ b/src/test/java/org/folio/orders/utils/PoLineCommonUtilTest.java @@ -6,6 +6,7 @@ import io.vertx.core.json.JsonObject; import org.folio.CopilotGenerated; +import org.folio.TestMate; import org.folio.rest.core.exceptions.HttpException; import org.folio.rest.jaxrs.model.CompositePurchaseOrder; import org.folio.rest.jaxrs.model.Details; @@ -31,7 +32,6 @@ import org.folio.rest.jaxrs.model.Error; import static org.hamcrest.Matchers.contains; import io.vertx.core.json.JsonArray; -import org.folio.orders.utils.PoLineCommonUtil; import org.folio.rest.core.exceptions.ErrorCodes; import java.util.Collections; import org.folio.rest.jaxrs.model.Ongoing; @@ -266,9 +266,9 @@ void testExtractUnaffiliatedLocationsHandleNullLocationTenantId() { assertTrue(result.contains(locations.get(1))); } - @Test + @Test + @TestMate(name = "TestMate-fcee0817e0fb477dda0345cf59133ea1") void testVerifyProtectedFieldsChangedShouldDetectScalarFieldChange() { - // TestMate-fcee0817e0fb477dda0345cf59133ea1 // Given List protectedFields = List.of("poLineNumber", "isPackage"); JsonObject objectFromStorage = new JsonObject() @@ -287,18 +287,18 @@ void testVerifyProtectedFieldsChangedShouldDetectScalarFieldChange() { assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); Map additionalProperties = error.getAdditionalProperties(); Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); - + assertThat((Collection) modifiedFields, containsInAnyOrder("poLineNumber", "isPackage")); } - @Test + @Test + @TestMate(name = "TestMate-7c59c6e9741685700ad64171c7f676d6") void testVerifyProtectedFieldsChangedShouldDetectArraySizeDecrease() { - // TestMate-7c59c6e9741685700ad64171c7f676d6 // Given String protectedField = "details.productIds"; List protectedFields = List.of(protectedField); String productIdType = UUID.randomUUID().toString(); - + ProductId firstProductId = new ProductId() .withProductId("9780735245341") .withProductIdType(productIdType); @@ -309,29 +309,29 @@ void testVerifyProtectedFieldsChangedShouldDetectArraySizeDecrease() { PoLine lineFromStorage = new PoLine() .withId(poLineId) .withDetails(new Details().withProductIds(List.of(firstProductId, secondProductId))); - + PoLine requestObject = new PoLine() .withId(poLineId) .withDetails(new Details().withProductIds(List.of(firstProductId))); JsonObject lineFromStorageJson = JsonObject.mapFrom(lineFromStorage); JsonObject requestObjectJson = JsonObject.mapFrom(requestObject); // When - HttpException exception = assertThrows(HttpException.class, () -> + HttpException exception = assertThrows(HttpException.class, () -> PoLineCommonUtil.verifyProtectedFieldsChanged(protectedFields, lineFromStorageJson, requestObjectJson) ); // Then assertEquals(400, exception.getCode()); Error error = exception.getError(); assertEquals(PROHIBITED_FIELD_CHANGING.getCode(), error.getCode()); - + Map additionalProperties = error.getAdditionalProperties(); Object modifiedFields = additionalProperties.get("protectedAndModifiedFields"); assertThat((Collection) modifiedFields, contains(protectedField)); } - @Test + @Test + @TestMate(name = "TestMate-557f9017f8ed07ba36247fa5b6b84c6b") void testVerifyProtectedFieldsChangedShouldDetectArrayContentMismatchSameSize() { - // TestMate-557f9017f8ed07ba36247fa5b6b84c6b // Given String protectedField = "tags.tagList"; List protectedFields = List.of(protectedField); @@ -354,9 +354,9 @@ void testVerifyProtectedFieldsChangedShouldDetectArrayContentMismatchSameSize() assertThat((Collection) modifiedFields, contains(protectedField)); } - @Test + @Test + @TestMate(name = "TestMate-2cf9247ee4f691a5aa390dbf1d481c14") void testVerifyProtectedFieldsChangedShouldIgnoreUnprotectedFieldChanges() { - // TestMate-2cf9247ee4f691a5aa390dbf1d481c14 // Given List protectedFields = List.of("id"); String id = "11111111-1111-1111-1111-111111111111"; @@ -372,9 +372,9 @@ void testVerifyProtectedFieldsChangedShouldIgnoreUnprotectedFieldChanges() { assertEquals(objectFromStorage, result); } - @Test + @Test + @TestMate(name = "TestMate-defcd112d0e57c836878823cedcaef6c") void testVerifyProtectedFieldsChangedShouldHandleNestedFieldPaths() { - // TestMate-defcd112d0e57c836878823cedcaef6c // Given String protectedFieldPath = "cost.currency"; List protectedFields = List.of(protectedFieldPath); @@ -399,18 +399,18 @@ void testVerifyProtectedFieldsChangedShouldHandleNestedFieldPaths() { assertThat((Collection) modifiedFields, contains(protectedFieldPath)); } - @Test + @Test + @TestMate(name = "TestMate-69d03db6b9de005e4433ca20ca1445ee") void testVerifyProtectedFieldsChangedShouldHandleEmptyProtectedFieldsList() { - // TestMate-69d03db6b9de005e4433ca20ca1445ee // Given List protectedFields = Collections.emptyList(); String id = "00000000-0000-0000-0000-000000000001"; - + JsonObject objectFromStorage = new JsonObject() .put("id", id) .put("name", "Original Name") .put("status", "Pending"); - + JsonObject requestObject = new JsonObject() .put("id", UUID.fromString("00000000-0000-0000-0000-000000000002").toString()) .put("name", "Changed Name") @@ -421,9 +421,9 @@ void testVerifyProtectedFieldsChangedShouldHandleEmptyProtectedFieldsList() { assertEquals(objectFromStorage, result); } - @Test + @Test + @TestMate(name = "TestMate-a9add8ed0d1f7a0fe476f740af1ee27e") void testVerifyProtectedFieldsChangedShouldDetectChangesInMultipleProtectedFields() { - // TestMate-a9add8ed0d1f7a0fe476f740af1ee27e // Given List protectedFields = List.of("id", "source"); JsonObject objectFromStorage = new JsonObject() @@ -447,13 +447,13 @@ void testVerifyProtectedFieldsChangedShouldDetectChangesInMultipleProtectedField assertThat((Collection) modifiedFields, containsInAnyOrder("id", "source")); } - @ParameterizedTest + @ParameterizedTest + @TestMate(name = "TestMate-1e7f8d73471208534f55a8712f35d569") @CsvSource(value = { "reviewDate|2024-01-01T00:00:00Z", "manualRenewal|true" }, delimiter = '|') void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenSubscriptionFieldsModified(String fieldName, String newValue) { - // TestMate-1e7f8d73471208534f55a8712f35d569 // Given JsonObject ongoingStorage = new JsonObject() .put("isSubscription", true) @@ -490,7 +490,8 @@ void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenSubscriptionFieldsMod assertEquals(expectedValue, parameter.getValue()); } - @ParameterizedTest + @ParameterizedTest + @TestMate(name = "TestMate-6800fce4f0684e383b323eea15366367") @CsvSource(value = { "interval|10", "renewalDate|2024-01-15T10:30:00Z", @@ -498,7 +499,6 @@ void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenSubscriptionFieldsMod "manualRenewal|true" }, delimiter = '|') void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenNonSubscriptionFieldsModified(String fieldName, String newValue) { - // TestMate-6800fce4f0684e383b323eea15366367 //given JsonObject ongoingStorage = new JsonObject() .put("isSubscription", false) @@ -537,10 +537,10 @@ void testVerifyOngoingFieldsChangedShouldThrowExceptionWhenNonSubscriptionFields assertEquals(expectedValue, parameter.getValue()); } - @ParameterizedTest + @ParameterizedTest + @TestMate(name = "TestMate-495401ee096d3b81e566755f6a634940") @ValueSource(booleans = {true, false}) void testVerifyOngoingFieldsChangedShouldSucceedWhenAllowedFieldsModified(boolean isSubscription) { - // TestMate-495401ee096d3b81e566755f6a634940 // Given JsonObject ongoingStorage = new JsonObject() .put("isSubscription", isSubscription)