Add test cases for patch replace/remove with filter
diff --git a/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java b/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java index eb1a408..f52c8b8 100644 --- a/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java +++ b/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java
@@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Collectors; @SuppressWarnings("unchecked") @@ -206,17 +207,45 @@ } // apply expression filter Collection<Object> items = (Collection<Object>) attributeObject; - return items.stream().map(item -> { - Map<String, Object> resourceAsMap = objectAsMap(item); - if (FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema).test(item)) { - String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName(); - resourceAsMap.put(subAttributeName, patchOperation.getValue()); - return resourceAsMap; - } else { - // filter does not apply - return item; + String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName(); + Predicate<Object> filterPredicate = FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema); + + switch (patchOperation.getOperation()) { + case ADD: + case REPLACE: + return items.stream().map(item -> { + if (filterPredicate.test(item)) { + if (subAttributeName != null) { + Map<String, Object> resourceAsMap = objectAsMap(item); + resourceAsMap.put(subAttributeName, patchOperation.getValue()); + return resourceAsMap; + } else { + return patchOperation.getValue(); + } + } else { + return item; + } + }) + .collect(Collectors.toList()); + case REMOVE: + // if sub-attribute is null remove the item from the list + if (subAttributeName != null) { + return items.stream().map(item -> { + Map<String, Object> resourceAsMap = objectAsMap(item); + if (filterPredicate.test(item)) { + resourceAsMap.remove(subAttributeName); + } + return resourceAsMap; + }) + .collect(Collectors.toList()); + } else { + return items.stream() + // filter out any items that match + .filter(item -> !filterPredicate.test(item)) + .collect(Collectors.toList()); + } } - }).collect(Collectors.toList()); + return items; } private PatchOperationPath tryGetOperationPath(String key) { try {
diff --git a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java index 705716f..824a39a 100644 --- a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java +++ b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java
@@ -26,6 +26,7 @@ import org.apache.directory.scim.spec.patch.PatchOperation.Type; import org.apache.directory.scim.spec.patch.PatchOperationPath; import org.apache.directory.scim.spec.phonenumber.PhoneNumberParseException; +import org.apache.directory.scim.spec.resources.Address; import org.apache.directory.scim.spec.resources.Name; import org.apache.directory.scim.spec.resources.PhoneNumber; import org.apache.directory.scim.spec.resources.ScimUser; @@ -123,6 +124,121 @@ } @Test + public void applyRemoveItemWithFilter() { + this.user.setAddresses(List.of( + new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield") + .setPostalCode("01234"), + new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Otherton") + .setPostalCode("43210") + )); + + PatchOperation op = patchOperation(Type.REMOVE, "addresses[type eq \"work\"]", null); + ScimUser updatedUser = patchHandler.apply(this.user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(1); + assertThat(updatedUser.getAddresses().get(0).getType()).isEqualTo("home"); + assertThat(updatedUser.getAddresses().get(0).getPostalCode()).isEqualTo("43210"); + } + + @Test + public void applyRemoveAttributeWithFilter() { + Address workAddress = new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield") + .setPostalCode("01234"); + + Address homeAddress = new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Otherton") + .setPostalCode("43210"); + + Address updatedWorkAddress = new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield"); + + this.user.setAddresses(List.of(workAddress, homeAddress)); + + PatchOperation op = patchOperation(Type.REMOVE, "addresses[type eq \"work\"].postalCode", null); + ScimUser updatedUser = patchHandler.apply(this.user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0)).isEqualTo(updatedWorkAddress); + } + + @Test + public void applyReplaceItemWithFilter() { + Address workAddress = new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield") + .setPostalCode("01234"); + + Address homeAddress = new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Othertown") + .setPostalCode("43210"); + + Address otherAddress = new Address() + .setType("other") + .setStreetAddress("303 Loop Road") + .setRegion("Thirdtown") + .setPostalCode("11223") + .setPrimary(true); + + Map<String, Object> newAddress = Map.of( + "type", otherAddress.getType(), + "streetAddress", otherAddress.getStreetAddress(), + "region", otherAddress.getRegion(), + "postalCode", otherAddress.getPostalCode(), + "primary", otherAddress.getPrimary() + ); + + this.user.setAddresses(List.of(workAddress, homeAddress)); + PatchOperation op = patchOperation(Type.REPLACE, "addresses[type eq \"work\"]", newAddress); + ScimUser updatedUser = patchHandler.apply(this.user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0)).isEqualTo(otherAddress); + assertThat(updatedUser.getAddresses().get(1)).isEqualTo(homeAddress); + } + + @Test + public void applyReplaceItemAttributeWithFilter() { + Address workAddress = new Address() + .setType("work") + .setStreetAddress("101 Main Street") + .setRegion("Springfield") + .setPostalCode("01234"); + + Address homeAddress = new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Othertown") + .setPostalCode("43210"); + + Address updatedHome = new Address() + .setType("home") + .setStreetAddress("202 Maple Street") + .setRegion("Othertown") + .setPostalCode("43210") + .setPrimary(true); + + this.user.setAddresses(List.of(workAddress, homeAddress)); + PatchOperation op = patchOperation(Type.REPLACE, "addresses[type eq \"home\"].primary", true); + ScimUser updatedUser = patchHandler.apply(this.user, List.of(op)); + assertThat(updatedUser.getAddresses().size()).isEqualTo(2); + assertThat(updatedUser.getAddresses().get(0)).isEqualTo(workAddress); + assertThat(updatedUser.getAddresses().get(1)).isEqualTo(updatedHome); + } + + @Test public void applyReplaceEnterpriseExtension() { String employeeNumberUrn = "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber"; String employeeNumber = "NCIR48XM6D84";