Add tests and fixes for PATCH scenarios
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 aa10e27..80b7c32 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
@@ -32,6 +32,7 @@
 
 import java.util.*;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 @SuppressWarnings("unchecked")
 @Slf4j
@@ -84,25 +85,43 @@
     Schema baseSchema = this.schemaRegistry.getSchema(source.getBaseUrn());
     Attribute attribute = baseSchema.getAttribute(attributeReference.getAttributeName());
 
-    Object attributeObject = attribute.getAccessor().get(source);
-    if (attributeObject == null && patchOperation.getOperation().equals(PatchOperation.Type.REPLACE)) {
+    Schema.AttributeAccessor attributeAccessor = attribute.getAccessor();
+    Object attributeObject = attributeAccessor.get(source);
+    if (attributeObject == null && PatchOperation.Type.REPLACE.equals(patchOperation.getOperation())) {
       throw new IllegalArgumentException("Cannot apply patch replace on missing property: " + attribute.getName());
     }
 
-    if (valuePathExpression.getAttributeExpression() != null && attributeObject instanceof Collection<?>) {
-      // apply expression filter
+    // Add item to list
+    if (PatchOperation.Type.ADD.equals(patchOperation.getOperation()) && attributeObject instanceof List<?>) {
+        List<Object> newItems = new ArrayList<>((Collection<Object>) attributeObject);
+        newItems.add(patchOperation.getValue());
+        attributeAccessor.set(source, newItems);
+    } else if (valuePathExpression.getAttributeExpression() != null && attributeObject instanceof List<?>) {
+      // change list
+      Predicate<Object> pred = FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema);
+      String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName();
+
       Collection<Object> items = (Collection<Object>) attributeObject;
-      items.forEach(item -> {
-        Predicate<Object> pred = FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema);
-        if (pred.test(item)) {
-          String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName();
-          Schema.AttributeAccessor subAttributeAccessor = attribute.getAttribute(subAttributeName).getAccessor();
-          subAttributeAccessor.set(item, patchOperation.getValue());
-        }
-      });
+
+      // remove item from list
+      if (PatchOperation.Type.REMOVE.equals(patchOperation.getOperation()) && subAttributeName == null) {
+        Object newItems = items.stream()
+          .filter(item -> !pred.test(item))
+          .collect(Collectors.toList());
+        attributeAccessor.set(source, newItems);
+      } else {
+      // update item in list
+        items.stream()
+          .filter(pred)
+          .findFirst()
+          .ifPresent(item -> {
+            Schema.AttributeAccessor subAttributeAccessor = attribute.getAttribute(subAttributeName).getAccessor();
+            subAttributeAccessor.set(item, patchOperation.getValue());
+          });
+      }
     } else {
-      // no filter expression, just set the value
-      attribute.getAccessor().set(source, patchOperation.getValue());
+      // just set the value
+      attributeAccessor.set(source, patchOperation.getValue());
     }
     return source;
   }
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 4d8d8d6..7de8b8c 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
@@ -78,6 +78,46 @@
     ));
   }
 
+  @Test
+  public void deleteItemWithFilter() throws FilterParseException {
+    PatchOperation op = new PatchOperation();
+    op.setOperation(PatchOperation.Type.REMOVE);
+    op.setPath(new PatchOperationPath("emails[type EQ \"home\"]"));
+    ScimUser updatedUser = performPatch(op);
+    List<Email> emails = updatedUser.getEmails();
+    assertThat(emails).isEqualTo(List.of(
+      new Email()
+        .setPrimary(true)
+        .setType("work")
+        .setValue("work@example.com")
+    ));
+  }
+
+  @Test
+  public void addItem() throws FilterParseException {
+    PatchOperation op = new PatchOperation();
+    op.setOperation(PatchOperation.Type.ADD);
+    op.setPath(new PatchOperationPath("emails"));
+    op.setValue(new Email()
+      .setType("other")
+      .setValue("other@example.com"));
+
+    ScimUser updatedUser = performPatch(op);
+    List<Email> emails = updatedUser.getEmails();
+    assertThat(emails).isEqualTo(List.of(
+        new Email()
+          .setPrimary(true)
+          .setType("work")
+          .setValue("work@example.com"),
+        new Email()
+          .setType("home")
+          .setValue("home@example.com"),
+        new Email()
+          .setType("other")
+          .setValue("other@example.com")
+      ));
+  }
+
   private ScimUser performPatch(PatchOperation op) {
     when(mockSchemaRegistry.getSchema(ScimUser.SCHEMA_URI)).thenReturn(Schemas.schemaFor(ScimUser.class));
     PatchHandler patchHandler = new PatchHandlerImpl(mockSchemaRegistry);