Repository: primefaces/primefaces (java)

Issue:
Avatar: Problem with non-US chars
**Describe the defect**
There are two defects
1. Thrown `StringIndexOutOfBoundsException` when using non-US chars in surname initial.
2. No exception thrown but the initial not shown when non-US chars in first name initial.

Tried with Ş,Ö,Ç,İ,Ü

**Reproducer**
[issuereport.zip](https://github.com/primefaces/primefaces/files/7262144/issuereport.zip)

**Expected behavior**
Expected to see the original chars.

**Example XHTML**
```xhtml
<p:panelGrid columns="2">
    <h:outputText value="PrimeFaces Rocks"/>
    <p:avatar label="PrimeFaces Rocks"/><!-- works -->

    <h:outputText value="ŞPrimeFaces Rocks"/>
    <p:avatar label="ŞPrimeFaces Rocks"/><!-- does not work as expected -->

    <h:outputText value="PrimeFaces ŞRocks"/>
    <p:avatar label="PrimeFaces ŞRocks"/><!-- does not work as expected -->

    <h:outputText value="ŞPrimeFaces ŞRocks"/>
    <p:avatar label="ŞPrimeFaces ŞRocks"/><!-- thrown error -->
</p:panelGrid>

<p:panelGrid columns="2">
    <h:outputText value="#{testView.name1}"/>
    <p:avatar label="#{testView.name1}"/><!-- works -->
    
    <h:outputText value="#{testView.name2}"/>
    <p:avatar label="#{testView.name2}"/><!-- does not work as expected -->
    
    <h:outputText value="#{testView.name3}"/>
    <p:avatar label="#{testView.name3}"/><!-- does not work as expected -->
    
    <h:outputText value="#{testView.name4}"/>
    <p:avatar label="#{testView.name4}"/><!-- thrown error -->
</p:panelGrid>
```

**Example Bean**
```java
@Named
@ViewScoped
public class TestView implements Serializable {
    private String name1 = "PrimeFaces Rocks";
    private String name2 = "ŞPrimeFaces Rocks";
    private String name3 = "PrimeFaces ŞRocks";
    private String name4 = "ŞPrimeFaces ŞRocks";
    
    // getters
}
```


Pull request description:
Fix #7900: Avatar proper Unicode decoding for letter avatar
Bad regex and added unit tests for all cases to prove its fixed.

Patch:
diff --git a/primefaces/src/main/java/org/primefaces/component/avatar/AvatarRenderer.java b/primefaces/src/main/java/org/primefaces/component/avatar/AvatarRenderer.java
index 7613e840da..ea9b5f15cd 100644
--- a/primefaces/src/main/java/org/primefaces/component/avatar/AvatarRenderer.java
+++ b/primefaces/src/main/java/org/primefaces/component/avatar/AvatarRenderer.java
@@ -23,15 +23,6 @@
  */
 package org.primefaces.component.avatar;
 
-import org.primefaces.renderkit.CoreRenderer;
-import org.primefaces.util.LangUtils;
-import org.primefaces.util.SharedStringBuilder;
-
-import javax.faces.FacesException;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
@@ -39,9 +30,18 @@ import java.security.NoSuchAlgorithmException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.primefaces.renderkit.CoreRenderer;
+import org.primefaces.util.LangUtils;
+import org.primefaces.util.SharedStringBuilder;
+
 public class AvatarRenderer extends CoreRenderer {
 
-    private static final Pattern LETTER_PATTTERN = Pattern.compile("\\b[a-zA-Z]");
+    private static final Pattern LETTER_PATTTERN = Pattern.compile("\\b[\\p{L}\\p{M}]");
     private static final String GRAVATAR_URL = "https://www.gravatar.com/avatar/";
     private static final String SB_AVATAR = AvatarRenderer.class.getName() + "#avatar";
 


Test patch:
diff --git a/primefaces/src/test/java/org/primefaces/component/avatar/AvatarRendererTest.java b/primefaces/src/test/java/org/primefaces/component/avatar/AvatarRendererTest.java
new file mode 100644
index 0000000000..490e9987ee
--- /dev/null
+++ b/primefaces/src/test/java/org/primefaces/component/avatar/AvatarRendererTest.java
@@ -0,0 +1,147 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009-2021 PrimeTek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.primefaces.component.avatar;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+
+import javax.faces.context.FacesContext;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class AvatarRendererTest {
+
+    private AvatarRenderer renderer;
+    private Avatar avatar;
+    private FacesContext context;
+
+    @BeforeEach
+    public void setup() {
+        renderer = new AvatarRenderer();
+        avatar = mock(Avatar.class);
+        context = mock(FacesContext.class);
+        when(context.getAttributes()).thenReturn(new HashMap<>());
+    }
+
+    @Test
+    void testCalculateLabelSingleLetter() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("G");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("G", result);
+    }
+
+    @Test
+    void testCalculateLabelAlreadyInitials() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("BD");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("BD", result);
+    }
+
+    @Test
+    void testCalculateLabelThreeWords() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("Wolfgang Amadeus Mozart");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("WM", result);
+    }
+
+    @Test
+    void testCalculateLabelIssue7900X1() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("PrimeFaces Rocks");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("PR", result);
+    }
+
+    @Test
+    void testCalculateLabelIssue7900X2() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("ŞPrimeFaces Rocks");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("ŞR", result);
+    }
+
+    @Test
+    void testCalculateLabelIssue7900X3() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("PrimeFaces ŞRocks");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("PŞ", result);
+    }
+
+    @Test
+    void testCalculateLabelIssue7900X4() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("ŞPrimeFaces ŞRocks");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("ŞŞ", result);
+    }
+
+    @Test
+    void testCalculateLabelIssue7900Unicode() {
+        // Arrange
+        when(avatar.getLabel()).thenReturn("Àlbert Ñunes");
+
+        // Act
+        String result = renderer.calculateLabel(context, avatar);
+
+        // Assert
+        assertEquals("ÀÑ", result);
+    }
+
+}