(5);
diff --git a/impl/src/test/java/com/sun/faces/util/TestUtil_local.java b/impl/src/test/java/com/sun/faces/util/TestUtil_local.java
index 8e6987494e..404bad4b68 100644
--- a/impl/src/test/java/com/sun/faces/util/TestUtil_local.java
+++ b/impl/src/test/java/com/sun/faces/util/TestUtil_local.java
@@ -17,46 +17,23 @@
// TestUtil_local.java
package com.sun.faces.util;
-import junit.framework.TestCase;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
import java.util.HashMap;
+import org.junit.jupiter.api.Test;
/**
* TestUtil_local.java is a class ...
- *
+ *
* Lifetime And Scope
*
*
*/
-public class TestUtil_local extends TestCase {
-
-//
-// Protected Constants
-//
-// Class Variables
-//
-//
-// Instance Variables
-//
-// Attribute Instance Variables
-// Relationship Instance Variables
-//
-// Constructors and Initializers
-//
- public TestUtil_local() {
- super("TestUtil_local.java");
- }
+public class TestUtil_local {
- public TestUtil_local(String name) {
- super(name);
- }
-
-//
-// Class methods
-//
-//
-// General Methods
-//
+ @Test
public void testGetLocaleFromString() {
// positive tests
assertNotNull(Util.getLocaleFromString("ps"));
@@ -90,23 +67,25 @@ public void testGetLocaleFromString() {
} catch (Exception exception) {
}
}
-
+
+ @Test
public void testSplit() {
String[] result = null;
-
+
result = Util.split(new HashMap(), "fooBarKey=Zm9vQmFyVmFsdWU====", "=", 2);
assertEquals(2, result.length);
assertEquals(result[1], "Zm9vQmFyVmFsdWU====");
-
+
result = Util.split(new HashMap(), "fooBarKey=Zm9vQmFyVmFsdWU=", "=", 2);
assertEquals(2, result.length);
assertEquals(result[1], "Zm9vQmFyVmFsdWU=");
-
+
result = Util.split(new HashMap(), "fooBarKey2=Zm9vQmFyVmFsdWUy", "=", 2);
assertEquals(2, result.length);
assertEquals(result[1], "Zm9vQmFyVmFsdWUy");
}
+ @Test
public void testExtractFirstNumericSegment() {
char separatorChar = ':';
@@ -132,5 +111,5 @@ public void testExtractFirstNumericSegment() {
assertEquals("there is no numeric segment", e.getMessage());
}
}
-
+
} // end of class TestUtil_local
diff --git a/impl/src/test/java/com/sun/faces/xml/ParseXMLTestCase.java b/impl/src/test/java/com/sun/faces/xml/ParseXMLTestCase.java
index 1e5976421a..93a90d6f83 100644
--- a/impl/src/test/java/com/sun/faces/xml/ParseXMLTestCase.java
+++ b/impl/src/test/java/com/sun/faces/xml/ParseXMLTestCase.java
@@ -16,6 +16,8 @@
package com.sun.faces.xml;
+import static org.junit.jupiter.api.Assertions.fail;
+
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
@@ -24,34 +26,19 @@
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+import org.junit.jupiter.api.Test;
import org.xml.sax.InputSource;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-public class ParseXMLTestCase extends TestCase {
+public class ParseXMLTestCase {
List list = new ArrayList<>();
private final static String xmlDir = "/conf/share";
- public ParseXMLTestCase(String name) {
- super(name);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- }
-
- public static Test suite() {
- return (new TestSuite(ParseXMLTestCase.class));
- }
-
// ------------------------------------------------------------ Test Methods
/**
* Added for issue 904.
*/
+ @Test
public void testParseXML() throws Exception {
String curDir = System.getProperty("user.dir");
@@ -81,7 +68,7 @@ public void testParseXML() throws Exception {
}
// Process all files and directories under dir
- public void visitAllDirsAndFiles(File dir) {
+ private void visitAllDirsAndFiles(File dir) {
if (dir.isFile()) {
if (isXML(dir)) {
@@ -96,7 +83,7 @@ public void visitAllDirsAndFiles(File dir) {
}
}
- public boolean isXML(File file) {
+ private boolean isXML(File file) {
String name = file.getName();
return name.endsWith(".xml");
}
diff --git a/impl/src/test/java/com/sun/faces/xml/XHTMLResolvingHandler.java b/impl/src/test/java/com/sun/faces/xml/XHTMLResolvingHandler.java
index 766ca44be3..3fde265a21 100644
--- a/impl/src/test/java/com/sun/faces/xml/XHTMLResolvingHandler.java
+++ b/impl/src/test/java/com/sun/faces/xml/XHTMLResolvingHandler.java
@@ -24,6 +24,7 @@
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
+
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
diff --git a/impl/src/test/java/jakarta/faces/FacesConfigOrderingTestCase.java b/impl/src/test/java/jakarta/faces/FacesConfigOrderingTestCase.java
new file mode 100644
index 0000000000..32a0eab13a
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/FacesConfigOrderingTestCase.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces;
+
+import static com.sun.faces.util.Util.createLocalDocumentBuilderFactory;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.sun.faces.config.manager.documents.DocumentInfo;
+import com.sun.faces.config.manager.documents.DocumentOrderingWrapper;
+
+import jakarta.faces.context.FacesContext;
+
+public class FacesConfigOrderingTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ Method method = FacesContext.class.getDeclaredMethod(
+ "setCurrentInstance", FacesContext.class);
+ method.setAccessible(true);
+ method.invoke(null, new Object[] { null });
+
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ /**
+ *
+ * verify that the overrides specified in the faces-config.xml in the user's
+ * webapp take precedence.
+ *
+ *
+ * @throws java.lang.Exception
+ */
+ @Test
+ public void testNoOrderingStartWithCab() throws Exception {
+ DocumentInfo docC = createDocument("C", null, null);
+ DocumentInfo doca = createDocument("a", null, null);
+ DocumentInfo docb = createDocument(null, null, null);
+
+ List documents = new ArrayList();
+ // J-
+ Collections.addAll(documents, new DocumentOrderingWrapper(docC),
+ new DocumentOrderingWrapper(doca), new DocumentOrderingWrapper(
+ docb));
+ // J+
+
+ DocumentOrderingWrapper[] wrappers = documents
+ .toArray(new DocumentOrderingWrapper[documents.size()]);
+ String[] originalOrder = extractNames(wrappers);
+ DocumentOrderingWrapper.sort(wrappers);
+
+ String[] orderedNames = extractNames(wrappers);
+
+ // a solution:
+ // ['C', 'a', '']
+ List original = Arrays.asList(originalOrder);
+ List actually = Arrays.asList(orderedNames);
+
+ List possibility1 = Arrays.asList("C", "a", "");
+
+ boolean assertion = (actually.equals(possibility1));
+ String message = "\n original: " + original + "\n expected: "
+ + possibility1 + "\n actually: " + actually + "\n";
+ assertTrue(assertion, message);
+ System.out.println("testNoOrderingStartWithCab: Passed" + message);
+ }
+
+ @Test
+ public void testCafteraStartWithCab() throws Exception {
+ List docCAfterIds = new ArrayList();
+ Collections.addAll(docCAfterIds, "a");
+
+ DocumentInfo docC = createDocument("C", null, docCAfterIds);
+ DocumentInfo doca = createDocument("a", null, null);
+ DocumentInfo docb = createDocument(null, null, null);
+
+ List documents = new ArrayList();
+ //J-
+ Collections.addAll(documents,
+ new DocumentOrderingWrapper(docC),
+ new DocumentOrderingWrapper(doca),
+ new DocumentOrderingWrapper(docb)
+ );
+ //J+
+
+ DocumentOrderingWrapper[] wrappers = documents.toArray(new DocumentOrderingWrapper[documents.size()]);
+ String[] originalOrder = extractNames(wrappers);
+ DocumentOrderingWrapper.sort(wrappers);
+
+ String[] orderedNames = extractNames(wrappers);
+
+ // a solution:
+ // ['a', '', 'C']
+ List original = Arrays.asList(originalOrder);
+ List actually = Arrays.asList(orderedNames);
+
+ List possibility1 = Arrays.asList("a", "", "C");
+
+ boolean assertion = (actually.equals(possibility1));
+ String message = "\n original: " + original + "\n expected: " + possibility1 +
+ "\n actually: " + actually + "\n";
+ assertTrue(assertion, message);
+ System.out.println("testCafteraStartWithCab: Passed" + message);
+ }
+
+ @Test
+ public void testAafterD_BafterCbeforeOthers_CafterDbeforeB_startWithABCD() throws Exception {
+ List docAAfterIds = new ArrayList();
+ Collections.addAll(docAAfterIds, "D");
+
+ // C should before B, hence B needs to be after C
+ List docBAfterIds = new ArrayList();
+ Collections.addAll(docBAfterIds, "C");
+
+ List docBBeforeIds = new ArrayList();
+ Collections.addAll(docBBeforeIds, "@others");
+
+ List docCAfterIds = new ArrayList();
+ Collections.addAll(docCAfterIds, "D");
+
+ List docCBeforeIds = new ArrayList();
+ Collections.addAll(docCBeforeIds, "B");
+
+ DocumentInfo docA = createDocument("A", null, docAAfterIds);
+ DocumentInfo docB = createDocument("B", docBBeforeIds, docBAfterIds);
+ DocumentInfo docC = createDocument("C", docCBeforeIds, docCAfterIds);
+ DocumentInfo docD = createDocument("D", null, null);
+
+ List documents = new ArrayList();
+ //J-
+ Collections.addAll(documents,
+ new DocumentOrderingWrapper(docA),
+ new DocumentOrderingWrapper(docB),
+ new DocumentOrderingWrapper(docC),
+ new DocumentOrderingWrapper(docD)
+ );
+ //J+
+
+ DocumentOrderingWrapper[] wrappers = documents.toArray(new DocumentOrderingWrapper[documents.size()]);
+ String[] originalOrder = extractNames(wrappers);
+ DocumentOrderingWrapper.sort(wrappers);
+
+ String[] orderedNames = extractNames(wrappers);
+
+ // a solution:
+ // ['D', 'C', 'B', 'A']
+ List original = Arrays.asList(originalOrder);
+ List actually = Arrays.asList(orderedNames);
+
+ List possibility1 = Arrays.asList("D", "C", "B", "A");
+
+ boolean assertion = (actually.equals(possibility1)
+ );
+ String message = "\n original: " + original + "\n expected: " + possibility1 +
+ "\n actually: " + actually + "\n";
+ assertTrue(assertion, message);
+ System.out.println("testAafterD_BafterCbeforeOthers_CafterDbeforeB_startWithABCD: Passed" + message);
+ }
+
+ @Test
+ public void testAafterD_BafterCbeforeOthers_CafterDbeforeB_startWithADBC() throws Exception {
+
+ List docAAfterIds = new ArrayList();
+ Collections.addAll(docAAfterIds, "D");
+
+ // C should before B, hence B needs to be after C
+ List docBAfterIds = new ArrayList();
+ Collections.addAll(docBAfterIds, "C");
+
+ List docBBeforeIds = new ArrayList();
+ Collections.addAll(docBBeforeIds, "@others");
+
+ List docCAfterIds = new ArrayList();
+ Collections.addAll(docCAfterIds, "D");
+
+ List docCBeforeIds = new ArrayList();
+ Collections.addAll(docCBeforeIds, "B");
+
+ DocumentInfo docA = createDocument("A", null, docAAfterIds);
+ DocumentInfo docB = createDocument("B", docBBeforeIds, docBAfterIds);
+ DocumentInfo docC = createDocument("C", docCBeforeIds, docCAfterIds);
+ DocumentInfo docD = createDocument("D", null, null);
+
+ List documents = new ArrayList();
+ //J-
+ Collections.addAll(documents,
+ new DocumentOrderingWrapper(docA),
+ new DocumentOrderingWrapper(docD),
+ new DocumentOrderingWrapper(docB),
+ new DocumentOrderingWrapper(docC)
+ );
+ //J+
+
+ DocumentOrderingWrapper[] wrappers = documents.toArray(new DocumentOrderingWrapper[documents.size()]);
+ String[] originalOrder = extractNames(wrappers);
+ DocumentOrderingWrapper.sort(wrappers);
+
+ String[] orderedNames = extractNames(wrappers);
+
+ // a solution:
+ // ['D', 'C', 'B', 'A']
+ List original = Arrays.asList(originalOrder);
+ List actually = Arrays.asList(orderedNames);
+
+ List possibility1 = Arrays.asList("D", "C", "B", "A");
+
+ boolean assertion = (actually.equals(possibility1)
+ );
+ String message = "\n original: " + original + "\n expected: " + possibility1 +
+ "\n actually: " + actually + "\n";
+ assertTrue(assertion, message);
+ System.out.println("testAafterD_BafterCbeforeOthers_CafterDbeforeB_startWithADBC: Passed" + message);
+
+ }
+
+ @Test
+ public void testAafterD_BafterCbeforeOthers_CafterDbeforeB_shuffle() throws Exception {
+
+ List docAAfterIds = new ArrayList();
+ Collections.addAll(docAAfterIds, "D");
+
+ // C should before B, hence B needs to be after C
+ List docBAfterIds = new ArrayList();
+ Collections.addAll(docBAfterIds, "C");
+
+ List docBBeforeIds = new ArrayList();
+ Collections.addAll(docBBeforeIds, "@others");
+
+ List docCAfterIds = new ArrayList();
+ Collections.addAll(docCAfterIds, "D");
+
+ List docCBeforeIds = new ArrayList();
+ Collections.addAll(docCBeforeIds, "B");
+
+ DocumentInfo docA = createDocument("A", null, docAAfterIds);
+ DocumentInfo docB = createDocument("B", docBBeforeIds, docBAfterIds);
+ DocumentInfo docC = createDocument("C", docCBeforeIds, docCAfterIds);
+ DocumentInfo docD = createDocument("D", null, null);
+
+ List documents = new ArrayList();
+ //J-
+ Collections.addAll(documents,
+ new DocumentOrderingWrapper(docA),
+ new DocumentOrderingWrapper(docB),
+ new DocumentOrderingWrapper(docC),
+ new DocumentOrderingWrapper(docD)
+ );
+ //J+
+
+ int number = 100;
+ for (int i = 0; i < number; i++) {
+
+ Collections.shuffle(documents);
+
+ DocumentOrderingWrapper[] wrappers = documents.toArray(new DocumentOrderingWrapper[documents.size()]);
+ String[] originalOrder = extractNames(wrappers);
+ DocumentOrderingWrapper.sort(wrappers);
+
+ String[] orderedNames = extractNames(wrappers);
+
+ // some solutions:
+ // [D, C, B, A]
+ // [D, A, C, B]
+ List original = Arrays.asList(originalOrder);
+ List actually = Arrays.asList(orderedNames);
+
+ List possibility1 = Arrays.asList("D", "C", "B", "A");
+ List possibility2 = Arrays.asList("D", "A", "C", "B");
+
+ boolean assertion = (actually.equals(possibility1)
+ || actually.equals(possibility2)
+ );
+ String message = "\n original: " + original +
+ "\n expected: " + possibility1 +
+ "\n or: " + possibility2 +
+ "\n actually: " + actually + "\n";
+ assertTrue(assertion, message);
+
+ }
+
+ System.out.println("testAafterD_BafterCbeforeOthers_CafterDbeforeB_shuffle: " + number + " shuffles passed.");
+
+ }
+
+ private DocumentInfo createDocument(String documentId,
+ List beforeIds, List afterIds) throws Exception {
+
+ String ns = "http://java.sun.com/xml/ns/javaee";
+ Document document = newDocument();
+ Element root = document.createElementNS(ns, "faces-config");
+ if (documentId != null) {
+ Element nameElement = document.createElementNS(ns, "name");
+ nameElement.setTextContent(documentId);
+ root.appendChild(nameElement);
+ }
+ document.appendChild(root);
+ boolean hasBefore = (beforeIds != null && !beforeIds.isEmpty());
+ boolean hasAfter = (afterIds != null && !afterIds.isEmpty());
+ boolean createOrdering = (hasBefore || hasAfter);
+ if (createOrdering) {
+ Element ordering = document.createElementNS(ns, "ordering");
+ root.appendChild(ordering);
+ if (hasBefore) {
+ populateIds("before", beforeIds, ns, document, ordering);
+ }
+ if (hasAfter) {
+ populateIds("after", afterIds, ns, document, ordering);
+ }
+ }
+
+ return new DocumentInfo(document, null);
+
+ }
+
+ public static String[] extractNames(DocumentOrderingWrapper[] documents) {
+ String[] extractedNames = new String[documents.length];
+ int i = 0;
+
+ for (DocumentOrderingWrapper w : documents) {
+ extractedNames[i] = w.getDocumentId();
+ i++;
+ }
+
+ return extractedNames;
+ }
+
+ private void populateIds(String elementName, List ids, String ns,
+ Document document, Element ordering) {
+
+ Element element = document.createElementNS(ns, elementName);
+ ordering.appendChild(element);
+ for (String id : ids) {
+ Element append;
+ if ("@others".equals(id)) {
+ append = document.createElementNS(ns, "others");
+ } else {
+ append = document.createElementNS(ns, "name");
+ append.setTextContent(id);
+ }
+ element.appendChild(append);
+ }
+
+ }
+
+ private Document newDocument() throws ParserConfigurationException {
+
+ DocumentBuilderFactory factory = createLocalDocumentBuilderFactory();
+ factory.setValidating(false);
+ factory.setNamespaceAware(true);
+ return factory.newDocumentBuilder().newDocument();
+
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/FacesWrapperTestCase.java b/impl/src/test/java/jakarta/faces/FacesWrapperTestCase.java
new file mode 100644
index 0000000000..f8c6c76daa
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/FacesWrapperTestCase.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * A unit test to make sure all classes implementing {@link FacesWrapper} are
+ * actually wrapping all public and protected methods of the wrapped class. This
+ * should help to keep the wrapper classes in synch with the wrapped classes.
+ *
+ */
+public class FacesWrapperTestCase {
+
+ private static List> wrapperClasses;
+ private static List> noWrapperClasses;
+ private static List methodsToIgnore;
+ private static final String JAVAX_FACES_PKG = "jakarta.faces.";
+
+ /**
+ * Perform class-level initialization for test - lookup for classes
+ * implementing FacesWrapper.
+ * @throws java.lang.Exception
+ */
+ @BeforeEach
+ public void setUp() throws Exception {
+ if (wrapperClasses == null) {
+ loadWrapperClasses();
+ methodsToIgnore = new ArrayList();
+ methodsToIgnore.add(Object.class.getMethod("toString", new Class[0]));
+ }
+ }
+
+ /**
+ * Unit test to assert wrapperClasses list was loaded (see {@link #setUp()}.
+ */
+ @Test
+ public void testWrapperClassesLoaded() {
+ assertNotNull(wrapperClasses);
+ assertTrue(!wrapperClasses.isEmpty());
+ }
+
+ /**
+ * Unit test to assert there are no *Wrapper classes not implementing
+ * FacesWrapper.
+ */
+ @Test
+ public void testWrapperClassesImplementFacesWrapper() {
+ assertNotNull(noWrapperClasses);
+ if (noWrapperClasses.size() > 0) {
+ System.out.println("Wrapper classes not implementing jakarta.faces.FacesWrapper:");
+ System.out.println(noWrapperClasses.toString());
+ }
+ assertTrue(noWrapperClasses
+ .isEmpty());
+ }
+
+ /**
+ * The main goal of this TestSuite: unit test to assert all classes
+ * implementing FacesWrapper do wrap all public and protected methods of the
+ * wrapped class.
+ */
+ @Test
+ public void testWrapperClassWrapsPublicAndProtectedMethods() {
+ for (Class> wrapper : wrapperClasses) {
+ if (wrapper.isInterface()) {
+ continue;
+ }
+ List wrapperMethods = getPublicAndProtectedMethods(wrapper);
+ List methodsToWrap = getPublicAndProtectedMethods(wrapper.getSuperclass());
+
+ System.out.println("verify " + wrapper.getName() + " is wrapping "
+ + wrapper.getSuperclass().getName() + " well");
+ String msg = wrapper.getCanonicalName() + " does not wrap method: ";
+ for (Method m : methodsToWrap) {
+ if (isMethodContained(m, methodsToIgnore)) {
+ continue;
+ }
+ assertTrue(isMethodContained(m, wrapperMethods), msg + m.toString());
+ }
+ }
+ }
+
+ // private methods
+ /**
+ * Returns true it the passed method is contained in the also passed list of
+ * methods by also comparing matching parameters.
+ *
+ * @param m the method (from the wrapped class) to compare against.
+ * @param wrapperMethods the list of methods of the wrapper class.
+ */
+ private boolean isMethodContained(Method m, List wrapperMethods) {
+ String name = m.getName();
+ Class>[] paramTypes = m.getParameterTypes();
+ Class> returnType = m.getReturnType();
+ for (Method wm : wrapperMethods) {
+ if (name.equals(wm.getName()) && Arrays.equals(paramTypes, wm.getParameterTypes())
+ && returnType == wm.getReturnType()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Collect public and protected methods of a class.
+ *
+ * @param wrapper the class to find its methods.
+ * @return list of found methods.
+ */
+ private List getPublicAndProtectedMethods(Class> wrapper) {
+ List mList = new ArrayList();
+ if (Object.class == wrapper) {
+ return mList;
+ }
+
+ Method[] methods = wrapper.getDeclaredMethods();
+ for (Method m : methods) {
+ int mod = m.getModifiers();
+ if (!Modifier.isStatic(mod) && (Modifier.isPublic(mod) || Modifier.isProtected(mod))) {
+ mList.add(m);
+ }
+ }
+ return mList;
+ }
+
+ /**
+ * Collect the wrapper classes.
+ */
+ private void loadWrapperClasses() {
+ wrapperClasses = new ArrayList<>();
+ noWrapperClasses = new ArrayList<>();
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ collectWrapperClasses(
+ classLoader,
+ JAVAX_FACES_PKG,
+ new File(classLoader.getResource("jakarta/faces/Messages.properties").getFile())
+ .getParentFile());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Walk package tree for collecting wrapper classes.
+ *
+ * @param classLoader the ClassLoader.
+ * @param pkg package name.
+ * @param jakartaFacesFolder current File (directory or file)
+ * @throws Exception might throw ClassNotFoundException from class loading.
+ */
+ private void collectWrapperClasses(ClassLoader classLoader, String pkg, File jakartaFacesFolder) throws Exception {
+ for (File file : jakartaFacesFolder.listFiles()) {
+ if (file.isDirectory()) {
+ collectWrapperClasses(classLoader, pkg + file.getName() + ".", file);
+ } else {
+ addWrapperClassToWrapperClassesList(classLoader, pkg, file);
+ }
+ }
+ }
+
+ /**
+ * Add classes that are assignable to FacesWrapper class to the
+ * wrapperClasses list - and also add classes with a name ending on
+ * "Wrapper" but being not assignable to FacesWrapper to the
+ * noWrapperClasses list.
+ *
+ * @param cl the ClasslOader used to load the class.
+ * @param pkg the name of the package working in.
+ * @param f the File to analyse.
+ * @throws Exception ClassLoader exceptions.
+ */
+ private void addWrapperClassToWrapperClassesList(ClassLoader cl, String pkg, File f)
+ throws Exception {
+ String name = f.getName();
+ if (!name.endsWith(".class")) {
+ return;
+ }
+ String className = pkg + name.substring(0, name.length() - 6);
+ Class> c = cl.loadClass(className);
+ Class> wrappedClass = c.getSuperclass();
+ if (wrappedClass != null) {
+ // we are not interested in interfaces extending FacesWrapper interface.
+ // also skip classes implementing FacesWrapper but extend from Object (e.g. factories).
+ if (FacesWrapper.class.isAssignableFrom(wrappedClass) || wrappedClass == Object.class) {
+ return;
+ }
+ }
+ if (FacesWrapper.class.isAssignableFrom(c)) {
+ wrapperClasses.add(c);
+ } else if (c != FacesWrapper.class && c.getName().endsWith("Wrapper")) {
+ noWrapperClasses.add(c);
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/FactoryFinderTestCase.java b/impl/src/test/java/jakarta/faces/FactoryFinderTestCase.java
new file mode 100644
index 0000000000..0738dfd342
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/FactoryFinderTestCase.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockHttpServletRequest;
+import com.sun.faces.mock.MockHttpServletResponse;
+import com.sun.faces.mock.MockServletContext;
+
+import jakarta.faces.application.Application;
+import jakarta.faces.application.ApplicationFactory;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.FacesContextFactory;
+import jakarta.faces.lifecycle.Lifecycle;
+import jakarta.faces.lifecycle.LifecycleFactory;
+
+public class FactoryFinderTestCase {
+
+ public static String FACTORIES[][] = {
+ {FactoryFinder.APPLICATION_FACTORY,
+ "com.sun.faces.mock.MockApplicationFactory"
+ },
+ {FactoryFinder.EXTERNAL_CONTEXT_FACTORY,
+ "com.sun.faces.mock.MockExternalContextFactory"
+ },
+ {FactoryFinder.FACES_CONTEXT_FACTORY,
+ "com.sun.faces.mock.MockFacesContextFactory"
+ },
+ {FactoryFinder.LIFECYCLE_FACTORY,
+ "com.sun.faces.mock.MockLifecycleFactory"
+ },
+ {FactoryFinder.RENDER_KIT_FACTORY,
+ "com.sun.faces.mock.MockRenderKitFactory"
+ }
+ };
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ Method method = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
+ method.setAccessible(true);
+ method.invoke(null, new Object[]{null});
+
+ for (int i = 0, len = FACTORIES.length; i < len; i++) {
+ System.getProperties().remove(FACTORIES[i][0]);
+ }
+ }
+
+ // Tear down instance variables required by ths test case
+ @AfterEach
+ public void tearDown() throws Exception {
+ FactoryFinder.releaseFactories();
+ for (int i = 0, len = FACTORIES.length; i < len; i++) {
+ System.getProperties().remove(FACTORIES[i][0]);
+ }
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ /**
+ *
+ * verify that the overrides specified in the faces-config.xml in the user's
+ * webapp take precedence.
+ *
+ * @throws java.lang.Exception
+ */
+ @Test
+ public void testFacesConfigCase() throws Exception {
+ Object factory = null;
+ Class> clazz = null;
+
+ FactoryFinder.releaseFactories();
+ int len, i = 0;
+
+ // simulate the "faces implementation specific" part
+ for (i = 0, len = FACTORIES.length; i < len; i++) {
+ FactoryFinder.setFactory(FACTORIES[i][0],
+ FACTORIES[i][1]);
+ }
+
+ // simulate the "WEB-INF/services" part
+ // this is done by the build.xml file
+ File servicesDir = new File(System.getProperty("basedir"), "target/classes/META-INF/services");
+ servicesDir.mkdirs();
+
+ File servicesFile = new File(servicesDir, "jakarta.faces.context.FacesContextFactory");
+
+ if (servicesFile.exists()) {
+ servicesFile.delete();
+ }
+ PrintWriter writer = new PrintWriter(servicesFile);
+ writer.println("jakarta.faces.mock.MockFacesContextFactoryExtender");
+ writer.flush();
+ writer.close();
+
+ File cServicesDir = new File(System.getProperty("basedir"), "target/generated-classes/cobertura/META-INF/services");
+ cServicesDir.mkdirs();
+
+ File cServicesFile = new File(cServicesDir, "jakarta.faces.context.FacesContextFactory");
+
+ if (cServicesFile.exists()) {
+ cServicesFile.delete();
+ }
+ PrintWriter cWriter = new PrintWriter(cServicesFile);
+ cWriter.println("jakarta.faces.mock.MockFacesContextFactoryExtender");
+ cWriter.flush();
+ cWriter.close();
+
+ // simulate the "webapp faces-config.xml" part
+ FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+ "jakarta.faces.mock.MockFacesContextFactoryExtender2");
+
+ for (i = 0, len = FACTORIES.length; i < len; i++) {
+ clazz = Class.forName(FACTORIES[i][0]);
+ factory = FactoryFinder.getFactory(FACTORIES[i][0]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory for " + clazz.getName()
+ + " not of expected type.");
+ clazz = Class.forName(FACTORIES[i][1]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory " + FACTORIES[i][1] + " not of expected type");
+
+ }
+ // verify that the delegation works
+ assertTrue(System.getProperty(FACTORIES[2][0]).equals("jakarta.faces.mock.MockFacesContextFactoryExtender2"));
+ assertTrue(System.getProperty("oldImpl").equals("jakarta.faces.mock.MockFacesContextFactoryExtender"));
+
+ // Verify IllegalStateException when factory not found
+ FactoryFinder.releaseFactories();
+ FactoryFinder.setFactory(FACTORIES[0][0], FACTORIES[0][1]);
+ FactoryFinder.setFactory(FACTORIES[1][0], FACTORIES[1][1]);
+ FactoryFinder.setFactory(FACTORIES[2][0], FACTORIES[2][1]);
+ FactoryFinder.setFactory(FACTORIES[4][0], FACTORIES[4][1]);
+ boolean exceptionThrown = false;
+ try {
+ factory = FactoryFinder.getFactory(FACTORIES[3][0]);
+ } catch (IllegalStateException ise) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+
+ servicesFile.delete();
+ cServicesFile.delete();
+ }
+
+ // TODO re-enable
+ @Test
+ public void testNoFacesContext() throws Exception {
+// assertNull(FacesContext.getCurrentInstance());
+// Object result = FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+// assertNotNull(result);
+// assertTrue(result instanceof FacesContextFactory);
+ }
+
+ /**
+ *
+ * In the absence of webapp faces-config.xml, verify that the overrides
+ * specified in the META-INF/services take precedence.
+ *
+ * @throws java.lang.Exception
+ */
+ @Test
+ public void testServicesCase() throws Exception {
+ Object factory = null;
+ Class> clazz = null;
+
+ FactoryFinder.releaseFactories();
+ int len, i = 0;
+
+ // simulate the "faces implementation specific" part
+ for (i = 0, len = FACTORIES.length; i < len; i++) {
+ FactoryFinder.setFactory(FACTORIES[i][0],
+ FACTORIES[i][1]);
+ }
+
+ // simulate the "WEB-INF/services" part
+ // this is done by the build.xml file
+ File servicesDir = new File(System.getProperty("basedir"), "target/classes/META-INF/services");
+ servicesDir.mkdirs();
+
+ File servicesFile = new File(servicesDir, "jakarta.faces.context.FacesContextFactory");
+
+ if (servicesFile.exists()) {
+ servicesFile.delete();
+ }
+
+ PrintWriter writer = new PrintWriter(servicesFile);
+ writer.println("jakarta.faces.mock.MockFacesContextFactoryExtender");
+ writer.flush();
+ writer.close();
+
+ File cServicesDir = new File(System.getProperty("basedir"), "target/generated-classes/cobertura/META-INF/services");
+ cServicesDir.mkdirs();
+
+ File cServicesFile = new File(cServicesDir, "jakarta.faces.context.FacesContextFactory");
+
+ if (cServicesFile.exists()) {
+ cServicesFile.delete();
+ }
+
+ PrintWriter cWriter = new PrintWriter(cServicesFile);
+ cWriter.println("jakarta.faces.mock.MockFacesContextFactoryExtender");
+ cWriter.flush();
+ cWriter.close();
+
+ // this testcase omits the "webapp faces-config.xml" simulation
+ for (i = 0, len = FACTORIES.length; i < len; i++) {
+ clazz = Class.forName(FACTORIES[i][0]);
+ factory = FactoryFinder.getFactory(FACTORIES[i][0]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory for " + clazz.getName()
+ + " not of expected type.");
+ clazz = Class.forName(FACTORIES[i][1]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory " + FACTORIES[i][1] + " not of expected type");
+
+ }
+ // verify that the delegation works
+ assertTrue(System.getProperty(FACTORIES[2][0]).equals("jakarta.faces.mock.MockFacesContextFactoryExtender"));
+ assertTrue(System.getProperty("oldImpl").equals("com.sun.faces.mock.MockFacesContextFactory"));
+
+ servicesFile.delete();
+ cServicesFile.delete();
+ }
+
+ @Test
+ public void testNoFacesContextInitially() throws Exception {
+ assertNull(FacesContext.getCurrentInstance());
+
+ FactoryFinder.releaseFactories();
+ FactoryFinder.setFactory(FACTORIES[0][0], FACTORIES[0][1]);
+ FactoryFinder.setFactory(FACTORIES[1][0], FACTORIES[1][1]);
+ FactoryFinder.setFactory(FACTORIES[2][0], FACTORIES[2][1]);
+ FactoryFinder.setFactory(FACTORIES[3][0], FACTORIES[3][1]);
+ FactoryFinder.setFactory(FACTORIES[4][0], FACTORIES[4][1]);
+
+ FacesContextFactory fcFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+ LifecycleFactory lFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+ Object request = new MockHttpServletRequest();
+ Object response = new MockHttpServletResponse();
+ Object containerContext = new MockServletContext();
+ Lifecycle l = lFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+ @SuppressWarnings("unused")
+ FacesContext context = fcFactory.getFacesContext(containerContext, request, response, l);
+
+ ApplicationFactory aFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+ @SuppressWarnings("unused")
+ Application app = aFactory.getApplication();
+ FactoryFinder.releaseFactories();
+ }
+
+ // ------------------------------------------- helpers
+ public static void printRelevantSystemProperties() {
+ System.out.println("++++++Relevant System Properties: ");
+ for (int i = 0, len = FACTORIES.length; i < len; i++) {
+ System.out.println(FACTORIES[i][0] + ": "
+ + System.getProperty(FACTORIES[i][0]));
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/FactoryFinderTestCase2.java b/impl/src/test/java/jakarta/faces/FactoryFinderTestCase2.java
new file mode 100644
index 0000000000..8b91e1f928
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/FactoryFinderTestCase2.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class FactoryFinderTestCase2 {
+
+ public static String FACTORIES[][] = {
+ { FactoryFinder.APPLICATION_FACTORY,
+ "com.sun.faces.mock.MockApplicationFactory"
+ },
+ { FactoryFinder.EXTERNAL_CONTEXT_FACTORY,
+ "com.sun.faces.mock.MockExternalContextFactory"
+ },
+ { FactoryFinder.FACES_CONTEXT_FACTORY,
+ "com.sun.faces.mock.MockFacesContextFactory"
+ },
+ { FactoryFinder.LIFECYCLE_FACTORY,
+ "com.sun.faces.mock.MockLifecycleFactory"
+ },
+ { FactoryFinder.RENDER_KIT_FACTORY,
+ "com.sun.faces.mock.MockRenderKitFactory"
+ }
+ };
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ for (int i = 0, len = FactoryFinderTestCase2.FACTORIES.length; i < len; i++) {
+ System.getProperties().remove(FactoryFinderTestCase2.FACTORIES[i][0]);
+ }
+ }
+
+ // Tear down instance variables required by ths test case
+ @AfterEach
+ public void tearDown() throws Exception {
+ FactoryFinder.releaseFactories();
+ for (int i = 0, len = FactoryFinderTestCase2.FACTORIES.length; i < len; i++) {
+ System.getProperties().remove(FactoryFinderTestCase2.FACTORIES[i][0]);
+ }
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ /**
+ *
+ * In the absence of webapp faces-config.xml and META-INF/services, verify
+ * that the overrides specified in the implementation faces-config.xml take
+ * precedence.
+ * @throws java.lang.Exception
+ */
+ @Test
+ public void testJSFImplCase() throws Exception {
+ Object factory = null;
+ Class> clazz = null;
+
+ FactoryFinder.releaseFactories();
+ int len, i = 0;
+
+ // this testcase only simulates the "faces implementation
+ // specific" part
+ for (i = 0, len = FactoryFinderTestCase2.FACTORIES.length; i < len; i++) {
+ FactoryFinder.setFactory(FactoryFinderTestCase2.FACTORIES[i][0],
+ FactoryFinderTestCase2.FACTORIES[i][1]);
+ }
+
+ for (i = 0, len = FactoryFinderTestCase2.FACTORIES.length; i < len; i++) {
+ clazz = Class.forName(FactoryFinderTestCase2.FACTORIES[i][0]);
+ factory = FactoryFinder.getFactory(FactoryFinderTestCase2.FACTORIES[i][0]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory for " + clazz.getName()
+ + " not of expected type.");
+ clazz = Class.forName(FactoryFinderTestCase2.FACTORIES[i][1]);
+ assertTrue(
+ clazz.isAssignableFrom(factory.getClass()), "Factory " + FactoryFinderTestCase2.FACTORIES[i][1] + " not of expected type");
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/NamingContainerTestCase.java b/impl/src/test/java/jakarta/faces/component/NamingContainerTestCase.java
new file mode 100644
index 0000000000..716212a50c
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/NamingContainerTestCase.java
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.junit.JUnitFacesTestCaseBase;
+import com.sun.faces.mock.MockRenderKit;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+
+/**
+ *
+ * Unit tests for the {@link NamingContainer} functionality of all the standard component classes.
+ *
+ */
+public class NamingContainerTestCase extends JUnitFacesTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // The root of the component tree to be tested
+ private UIViewRoot root = null;
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+
+ root = new UIViewRoot();
+
+ root.setViewId("/viewId");
+ root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+ facesContext.setViewRoot(root);
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = new MockRenderKit();
+ try {
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+ } catch (IllegalArgumentException e) {
+ }
+ Map map = new HashMap<>();
+ externalContext.setRequestParameterMap(map);
+
+ }
+
+ // Tear down instance variables required by this test case.
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+
+ root = null;
+ super.tearDown();
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test nested NamingContainer callbacks
+ @Test
+ public void testNested() {
+
+ NamingContainerTestImpl a = new NamingContainerTestImpl();
+ a.setId("a");
+ NamingContainerTestImpl b = new NamingContainerTestImpl();
+ b.setId("b");
+ NamingContainerTestImpl d = new NamingContainerTestImpl();
+ d.setId("d");
+ UIPanel e = new UIPanel();
+ e.setId("e");
+ UIPanel g = new UIPanel();
+ g.setId("g");
+ a.getChildren().add(b);
+ b.getChildren().add(d);
+ b.getChildren().add(g);
+ d.getChildren().add(e);
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(a == a.findComponent("a"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(a == a.findComponent(":a"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(b == a.findComponent("b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(b == a.findComponent(":b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(d == a.findComponent("b:d"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(d == a.findComponent(":b:d"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(e == a.findComponent("b:d:e"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(e == a.findComponent(":b:d:e"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(g == a.findComponent("b:g"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(g == a.findComponent(":b:g"));
+
+ }
+
+ // Test nested NamingContainer callbacks
+ @Test
+ public void testNested2() {
+
+ NamingContainerTestImpl a = new NamingContainerTestImpl();
+ a.setId("a");
+ NamingContainerTestImpl b = new NamingContainerTestImpl();
+ b.setId("b");
+ NamingContainerTestImpl d = new NamingContainerTestImpl();
+ d.setId("b");
+ UIPanel e = new UIPanel();
+ e.setId("e");
+ UIPanel g = new UIPanel();
+ g.setId("g");
+ a.getChildren().add(b);
+ b.getChildren().add(d);
+ b.getChildren().add(g);
+ d.getChildren().add(e);
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(a == a.findComponent("a"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(a == a.findComponent(":a"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(b == a.findComponent("b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(b == a.findComponent(":b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(d == a.findComponent("b:b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(d == a.findComponent(":b:b"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(e == a.findComponent("b:b:e"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(e == a.findComponent(":b:b:e"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(g == a.findComponent("b:g"));
+
+ NamingContainerTestImpl.trace(null);
+ assertTrue(g == a.findComponent(":b:g"));
+
+ }
+
+ // Test standard NamingContainer functionality
+ @Test
+ public void testStandard() {
+
+ // Set up a component hierarchy as follows (component ids in quotes):
+ // "a" - UIViewRoot at head of hierarchy
+ // "a" has children "b" and "c"
+ // "b" has children "d" and "g"
+ // "d" has children "e" and "f"
+ // "c" has children "h" and "i"
+ // Components "b" and "d" implement NamingContainer
+ UIViewRoot a = root;
+ a.setId("a");
+ UIForm b = new UIForm();
+ b.setId("b");
+ UIPanel c = new UIPanel();
+ c.setId("c");
+ UINamingContainer d = new UINamingContainer();
+ d.setId("d");
+ UIPanel e = new UIPanel();
+ e.setId("e");
+ UIPanel f = new UIPanel();
+ f.setId("f");
+ UIPanel g = new UIPanel();
+ g.setId("g");
+ UIPanel h = new UIPanel();
+ h.setId("h");
+ UIPanel i = new UIPanel();
+ i.setId("i");
+ a.getChildren().add(b);
+ a.getChildren().add(c);
+ b.getChildren().add(d);
+ b.getChildren().add(g);
+ c.getChildren().add(h);
+ c.getChildren().add(i);
+ d.getChildren().add(e);
+ d.getChildren().add(f);
+
+ // Positive relative searches from "a"
+ assertTrue(a == a.findComponent("a"));
+ assertTrue(b == a.findComponent("b"));
+ assertTrue(c == a.findComponent("c"));
+ assertTrue(d == a.findComponent("b:d"));
+ assertTrue(e == a.findComponent("b:d:e"));
+ assertTrue(f == a.findComponent("b:d:f"));
+ assertTrue(g == a.findComponent("b:g"));
+ assertTrue(h == a.findComponent("h"));
+ assertTrue(i == a.findComponent("i"));
+
+ // Negative relative searches from "a"
+ assertNull(a.findComponent("d"));
+ assertNull(a.findComponent("e"));
+ assertNull(a.findComponent("f"));
+ assertNull(a.findComponent("g"));
+
+ // Positive relative searches from "b"
+ assertTrue(b == b.findComponent("b"));
+ assertTrue(d == b.findComponent("d"));
+ assertTrue(e == b.findComponent("d:e"));
+ assertTrue(f == b.findComponent("d:f"));
+ assertTrue(g == b.findComponent("g"));
+
+ // Negative relative searches from "b"
+ assertNull(b.findComponent("a"));
+ assertNull(b.findComponent("c"));
+ assertNull(b.findComponent("e"));
+ assertNull(b.findComponent("f"));
+ assertNull(b.findComponent("h"));
+ assertNull(b.findComponent("i"));
+
+ // Positive relative searches from "c"
+ assertTrue(a == c.findComponent("a"));
+ assertTrue(b == c.findComponent("b"));
+ assertTrue(c == c.findComponent("c"));
+ assertTrue(d == c.findComponent("b:d"));
+ assertTrue(e == c.findComponent("b:d:e"));
+ assertTrue(f == c.findComponent("b:d:f"));
+ assertTrue(g == c.findComponent("b:g"));
+ assertTrue(h == c.findComponent("h"));
+ assertTrue(i == c.findComponent("i"));
+
+ // Negative relative searches from "c"
+ assertNull(c.findComponent("d"));
+ assertNull(c.findComponent("e"));
+ assertNull(c.findComponent("f"));
+ assertNull(c.findComponent("g"));
+
+ // Positive relative searches from "d"
+ assertTrue(d == d.findComponent("d"));
+ assertTrue(e == d.findComponent("e"));
+ assertTrue(f == d.findComponent("f"));
+
+ // Negative relative searches from "d"
+ assertNull(d.findComponent("a"));
+ assertNull(d.findComponent("b"));
+ assertNull(d.findComponent("c"));
+ assertNull(d.findComponent("g"));
+ assertNull(d.findComponent("h"));
+ assertNull(d.findComponent("i"));
+
+ // Positive relative searches from "e"
+ assertTrue(d == e.findComponent("d"));
+ assertTrue(e == e.findComponent("e"));
+ assertTrue(f == e.findComponent("f"));
+
+ // Negative relative searches from "e"
+ assertNull(e.findComponent("a"));
+ assertNull(e.findComponent("b"));
+ assertNull(e.findComponent("c"));
+ assertNull(e.findComponent("g"));
+ assertNull(e.findComponent("h"));
+ assertNull(e.findComponent("i"));
+
+ // Positive relative searches from "f"
+ assertTrue(d == f.findComponent("d"));
+ assertTrue(e == f.findComponent("e"));
+ assertTrue(f == f.findComponent("f"));
+
+ // Negative relative searches from "f"
+ assertNull(f.findComponent("a"));
+ assertNull(f.findComponent("b"));
+ assertNull(f.findComponent("c"));
+ assertNull(f.findComponent("g"));
+ assertNull(f.findComponent("h"));
+ assertNull(f.findComponent("i"));
+
+ // Positive relative searches from "g"
+ assertTrue(b == g.findComponent("b"));
+ assertTrue(d == g.findComponent("d"));
+ assertTrue(e == g.findComponent("d:e"));
+ assertTrue(f == g.findComponent("d:f"));
+ assertTrue(g == g.findComponent("g"));
+
+ // Negative relative searches from "g"
+ assertNull(g.findComponent("a"));
+ assertNull(g.findComponent("c"));
+ assertNull(g.findComponent("e"));
+ assertNull(g.findComponent("f"));
+ assertNull(g.findComponent("h"));
+ assertNull(g.findComponent("i"));
+
+ // Positive relative searches from "h"
+ assertTrue(a == h.findComponent("a"));
+ assertTrue(b == h.findComponent("b"));
+ assertTrue(c == h.findComponent("c"));
+ assertTrue(d == h.findComponent("b:d"));
+ assertTrue(e == h.findComponent("b:d:e"));
+ assertTrue(f == h.findComponent("b:d:f"));
+ assertTrue(g == h.findComponent("b:g"));
+ assertTrue(h == h.findComponent("h"));
+ assertTrue(i == h.findComponent("i"));
+
+ // Negative relative searches from "h"
+ assertNull(h.findComponent("d"));
+ assertNull(h.findComponent("e"));
+ assertNull(h.findComponent("f"));
+ assertNull(h.findComponent("g"));
+
+ // Positive relative searches from "i"
+ assertTrue(a == i.findComponent("a"));
+ assertTrue(b == i.findComponent("b"));
+ assertTrue(c == i.findComponent("c"));
+ assertTrue(d == i.findComponent("b:d"));
+ assertTrue(e == i.findComponent("b:d:e"));
+ assertTrue(f == i.findComponent("b:d:f"));
+ assertTrue(g == i.findComponent("b:g"));
+ assertTrue(h == i.findComponent("h"));
+ assertTrue(i == i.findComponent("i"));
+
+ // Negative relative searches from "i"
+ assertNull(i.findComponent("d"));
+ assertNull(i.findComponent("e"));
+ assertNull(i.findComponent("f"));
+ assertNull(i.findComponent("g"));
+
+ // Absolute searches from "a"
+ assertTrue(a == a.findComponent(":a"));
+ assertTrue(b == a.findComponent(":b"));
+ assertTrue(c == a.findComponent(":c"));
+ assertTrue(d == a.findComponent(":b:d"));
+ assertTrue(e == a.findComponent(":b:d:e"));
+ assertTrue(f == a.findComponent(":b:d:f"));
+ assertTrue(g == a.findComponent(":b:g"));
+ assertTrue(h == a.findComponent(":h"));
+ assertTrue(i == a.findComponent(":i"));
+
+ // Absolute searches from "b"
+ assertTrue(a == b.findComponent(":a"));
+ assertTrue(b == b.findComponent(":b"));
+ assertTrue(c == b.findComponent(":c"));
+ assertTrue(d == b.findComponent(":b:d"));
+ assertTrue(e == b.findComponent(":b:d:e"));
+ assertTrue(f == b.findComponent(":b:d:f"));
+ assertTrue(g == b.findComponent(":b:g"));
+ assertTrue(h == b.findComponent(":h"));
+ assertTrue(i == b.findComponent(":i"));
+
+ // Absolute searches from "c"
+ assertTrue(a == c.findComponent(":a"));
+ assertTrue(b == c.findComponent(":b"));
+ assertTrue(c == c.findComponent(":c"));
+ assertTrue(d == c.findComponent(":b:d"));
+ assertTrue(e == c.findComponent(":b:d:e"));
+ assertTrue(f == c.findComponent(":b:d:f"));
+ assertTrue(g == c.findComponent(":b:g"));
+ assertTrue(h == c.findComponent(":h"));
+ assertTrue(i == c.findComponent(":i"));
+
+ // Absolute searches from "d"
+ assertTrue(a == d.findComponent(":a"));
+ assertTrue(b == d.findComponent(":b"));
+ assertTrue(c == d.findComponent(":c"));
+ assertTrue(d == d.findComponent(":b:d"));
+ assertTrue(e == d.findComponent(":b:d:e"));
+ assertTrue(f == d.findComponent(":b:d:f"));
+ assertTrue(g == d.findComponent(":b:g"));
+ assertTrue(h == d.findComponent(":h"));
+ assertTrue(i == d.findComponent(":i"));
+
+ // Absolute searches from "e"
+ assertTrue(a == e.findComponent(":a"));
+ assertTrue(b == e.findComponent(":b"));
+ assertTrue(c == e.findComponent(":c"));
+ assertTrue(d == e.findComponent(":b:d"));
+ assertTrue(e == e.findComponent(":b:d:e"));
+ assertTrue(f == e.findComponent(":b:d:f"));
+ assertTrue(g == e.findComponent(":b:g"));
+ assertTrue(h == e.findComponent(":h"));
+ assertTrue(i == e.findComponent(":i"));
+
+ // Absolute searches from "f"
+ assertTrue(a == f.findComponent(":a"));
+ assertTrue(b == f.findComponent(":b"));
+ assertTrue(c == f.findComponent(":c"));
+ assertTrue(d == f.findComponent(":b:d"));
+ assertTrue(e == f.findComponent(":b:d:e"));
+ assertTrue(f == f.findComponent(":b:d:f"));
+ assertTrue(g == f.findComponent(":b:g"));
+ assertTrue(h == f.findComponent(":h"));
+ assertTrue(i == f.findComponent(":i"));
+
+ // Absolute searches from "g"
+ assertTrue(a == g.findComponent(":a"));
+ assertTrue(b == g.findComponent(":b"));
+ assertTrue(c == g.findComponent(":c"));
+ assertTrue(d == g.findComponent(":b:d"));
+ assertTrue(e == g.findComponent(":b:d:e"));
+ assertTrue(f == g.findComponent(":b:d:f"));
+ assertTrue(g == g.findComponent(":b:g"));
+ assertTrue(h == g.findComponent(":h"));
+ assertTrue(i == g.findComponent(":i"));
+
+ // Absolute searches from "h"
+ assertTrue(a == h.findComponent(":a"));
+ assertTrue(b == h.findComponent(":b"));
+ assertTrue(c == h.findComponent(":c"));
+ assertTrue(d == h.findComponent(":b:d"));
+ assertTrue(e == h.findComponent(":b:d:e"));
+ assertTrue(f == h.findComponent(":b:d:f"));
+ assertTrue(g == h.findComponent(":b:g"));
+ assertTrue(h == h.findComponent(":h"));
+ assertTrue(i == h.findComponent(":i"));
+
+ // Absolute searches from "i"
+ assertTrue(a == i.findComponent(":a"));
+ assertTrue(b == i.findComponent(":b"));
+ assertTrue(c == i.findComponent(":c"));
+ assertTrue(d == i.findComponent(":b:d"));
+ assertTrue(e == i.findComponent(":b:d:e"));
+ assertTrue(f == i.findComponent(":b:d:f"));
+ assertTrue(g == i.findComponent(":b:g"));
+ assertTrue(h == i.findComponent(":h"));
+ assertTrue(i == i.findComponent(":i"));
+
+ // Cases that should throw exceptions
+ try {
+ a.findComponent(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent("a:c:h");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent("a:c:i");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent(":a:c:h");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent(":a:c:i");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent("c:h");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent("c:i");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent(":c:h");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+ try {
+ a.findComponent(":c:i");
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException ex) {
+ // Expected result
+ }
+
+ }
+
+ // --------------------------------------------------------- Support Methods
+}
diff --git a/impl/src/test/java/jakarta/faces/component/SearchExpressionHandlerTest.java b/impl/src/test/java/jakarta/faces/component/SearchExpressionHandlerTest.java
new file mode 100644
index 0000000000..85062251bc
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/SearchExpressionHandlerTest.java
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.component.search.CompositeSearchKeywordResolver;
+import com.sun.faces.component.search.SearchExpressionContextFactoryImpl;
+import com.sun.faces.component.search.SearchExpressionHandlerImpl;
+import com.sun.faces.component.search.SearchKeywordResolverImplAll;
+import com.sun.faces.component.search.SearchKeywordResolverImplChild;
+import com.sun.faces.component.search.SearchKeywordResolverImplComposite;
+import com.sun.faces.component.search.SearchKeywordResolverImplForm;
+import com.sun.faces.component.search.SearchKeywordResolverImplId;
+import com.sun.faces.component.search.SearchKeywordResolverImplNamingContainer;
+import com.sun.faces.component.search.SearchKeywordResolverImplNext;
+import com.sun.faces.component.search.SearchKeywordResolverImplNone;
+import com.sun.faces.component.search.SearchKeywordResolverImplParent;
+import com.sun.faces.component.search.SearchKeywordResolverImplPrevious;
+import com.sun.faces.component.search.SearchKeywordResolverImplRoot;
+import com.sun.faces.component.search.SearchKeywordResolverImplThis;
+import com.sun.faces.component.visit.VisitContextFactoryImpl;
+import com.sun.faces.junit.JUnitFacesTestCaseBase;
+import com.sun.faces.mock.MockRenderKit;
+
+import jakarta.faces.FacesException;
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.component.search.ComponentNotFoundException;
+import jakarta.faces.component.search.SearchExpressionContext;
+import jakarta.faces.component.search.SearchExpressionHandler;
+import jakarta.faces.component.search.SearchExpressionHint;
+import jakarta.faces.component.search.SearchKeywordContext;
+import jakarta.faces.component.search.SearchKeywordResolver;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+
+public class SearchExpressionHandlerTest extends JUnitFacesTestCaseBase {
+
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.setViewId("/viewId");
+ facesContext.setViewRoot(root);
+
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = new MockRenderKit();
+ try {
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+ } catch (IllegalArgumentException e) {
+ }
+
+ FactoryFinder.setFactory(FactoryFinder.SEARCH_EXPRESSION_CONTEXT_FACTORY, SearchExpressionContextFactoryImpl.class.getName());
+ FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY, VisitContextFactoryImpl.class.getName());
+
+ SearchExpressionHandlerImpl expressionHandlerImpl = new SearchExpressionHandlerImpl();
+ application.setSearchExpressionHandler(expressionHandlerImpl);
+
+ CompositeSearchKeywordResolver searchKeywordResolvers = new CompositeSearchKeywordResolver();
+ searchKeywordResolvers.add(new SearchKeywordResolverImplThis());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplParent());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplForm());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplComposite());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplNext());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplPrevious());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplNone());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplNamingContainer());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplRoot());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplId());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplChild());
+ searchKeywordResolvers.add(new SearchKeywordResolverImplAll());
+ application.setSearchKeywordResolver(searchKeywordResolvers);
+ }
+
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private UIComponent resolveComponent(UIComponent source, String expression, SearchExpressionHint... hints) {
+
+ SearchExpressionContext searchContext = SearchExpressionContext.createSearchExpressionContext(facesContext, source, new HashSet<>(Arrays.asList(hints)),
+ null);
+
+ ResolveComponentCallback callback = new ResolveComponentCallback();
+
+ SearchExpressionHandler handler = FacesContext.getCurrentInstance().getApplication().getSearchExpressionHandler();
+
+ handler.resolveComponent(searchContext, expression, callback);
+
+ return callback.component;
+ }
+
+ private static class ResolveComponentCallback implements ContextCallback {
+ public UIComponent component;
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target) {
+ component = target;
+ }
+ }
+
+ private String resolveClientId(UIComponent source, String expression) {
+ SearchExpressionContext searchContext = SearchExpressionContext.createSearchExpressionContext(facesContext, source);
+ SearchExpressionHandler handler = FacesContext.getCurrentInstance().getApplication().getSearchExpressionHandler();
+
+ return handler.resolveClientId(searchContext, expression);
+ }
+
+ private List resolveComponents(UIComponent source, String expression) {
+ SearchExpressionContext searchContext = SearchExpressionContext.createSearchExpressionContext(facesContext, source);
+ SearchExpressionHandler handler = FacesContext.getCurrentInstance().getApplication().getSearchExpressionHandler();
+
+ ResolveComponentsCallback callback = new ResolveComponentsCallback();
+
+ handler.resolveComponents(searchContext, expression, callback);
+
+ return callback.components;
+ }
+
+ private static class ResolveComponentsCallback implements ContextCallback {
+ public List components = new ArrayList<>();
+
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent target) {
+ components.add(target);
+ }
+ }
+
+ @Test
+ public void test_ResolveComponent_Parent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(innerContainer, resolveComponent(source, "@parent"));
+ }
+
+ @Test
+ public void test_ResolveComponent_ParentParent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(outerContainer, resolveComponent(source, "@parent:@parent"));
+ }
+
+ @Test
+ public void test_ResolveComponent_Form() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(form, resolveComponent(source, "@form"));
+ }
+
+ @Test
+ public void test_ResolveComponent_FormParent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(root, resolveComponent(source, "@form:@parent"));
+ }
+
+ @Test
+ public void test_ResolveComponent_All() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(root, resolveComponent(source, "@all"));
+ }
+
+ @Test
+ public void test_ResolveComponent_This() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(source, resolveComponent(source, "@this"));
+ }
+
+ @Test
+ public void test_ResolveComponent_ThisParent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(innerContainer, resolveComponent(source, "@this:@parent"));
+ }
+
+ @Test
+ public void test_ResolveComponent_Namingcontainer() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(innerContainer, resolveComponent(source, "@namingcontainer"));
+ }
+
+ @Test
+ public void test_ResolveComponent_Absolute() {
+
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertSame(source, resolveComponent(source, " :form:outerContainer:innerContainer:source "));
+ }
+
+ @Test
+ public void test_ResolveComponent_Relative() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertSame(component, resolveComponent(source, " other "));
+ }
+
+ @Test
+ public void test_ResolveComponent_AbsoluteForm() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertSame(root, resolveComponent(source, " :form:@parent "));
+ }
+
+ @Test
+ public void test_ResolveComponent_ParentChild() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertSame(component, resolveComponent(source, " @parent:@child(0) "));
+ assertSame(source, resolveComponent(source, " @parent:@child(1) "));
+ }
+
+ @Test
+ public void test_ResolveComponent_AbsoluteNamingcontainer() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertSame(form, resolveComponent(source, " :form:outerContainer:@namingcontainer "));
+ }
+
+ @Test
+ public void test_ResolveClientId_This() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertEquals("form:outerContainer:innerContainer:source", resolveClientId(source, " @this "));
+ }
+
+ @Test
+ public void test_ResolveClientId_Form() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertEquals("form", resolveClientId(source, " @form "));
+ }
+
+ @Test
+ public void test_ResolveClientId_AbsoluteId() {
+
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertEquals("form", resolveClientId(source, " :form "));
+ }
+
+ @Test
+ public void test_ResolveClientId_Relative() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertEquals("form:outerContainer:innerContainer:other", resolveClientId(source, " other "));
+ }
+
+ @Test
+ public void test_ResolveComponents_RelativeAndParentParent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ List resolvedComponents = resolveComponents(source, " other @parent:@parent ");
+ assertTrue(resolvedComponents.contains(component));
+ assertTrue(resolvedComponents.contains(outerContainer));
+ assertEquals(2, resolvedComponents.size());
+ }
+
+ @Test
+ public void test_ResolveComponents_RelativeAndThisParent() {
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ component.setId("other");
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ List resolvedComponents = resolveComponents(source, " other,@this:@parent @none ");
+ assertTrue(resolvedComponents.contains(component));
+ assertTrue(resolvedComponents.contains(innerContainer));
+ assertEquals(2, resolvedComponents.size());
+ }
+
+ @Test
+ public void test_ResolveComponent_Next() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ UIComponent command3 = new UICommand();
+ command3.setId("command3");
+ root.getChildren().add(command3);
+
+ assertSame(command2, resolveComponent(command1, " @next "));
+ assertSame(command3, resolveComponent(command2, " @next "));
+
+ try {
+ resolveComponent(command3, " @next");
+ fail("This should actually raise an exception");
+ } catch (Exception e) {
+ assertEquals(ComponentNotFoundException.class, e.getClass());
+ }
+ }
+
+ @Test
+ public void test_ResolveComponent_NextNext() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ UIComponent command3 = new UICommand();
+ command3.setId("command3");
+ root.getChildren().add(command3);
+
+ assertSame(command3, resolveComponent(command1, " @next:@next "));
+
+ try {
+ resolveComponent(command2, " @next:@next");
+ fail("This should actually raise an exception");
+ } catch (Exception e) {
+ assertEquals(ComponentNotFoundException.class, e.getClass());
+ }
+
+ try {
+ resolveComponent(command3, " @next:@next");
+ fail("This should actually raise an exception");
+ } catch (Exception e) {
+ assertEquals(ComponentNotFoundException.class, e.getClass());
+ }
+ }
+
+ @Test
+ public void test_ResolveComponent_Previous() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ UIComponent command3 = new UICommand();
+ command3.setId("command3");
+ root.getChildren().add(command3);
+
+ assertSame(command1, resolveComponent(command2, " @previous "));
+ assertSame(command2, resolveComponent(command3, " @previous "));
+
+ try {
+ resolveComponent(command1, " @previous");
+ fail("This should actually raise an exception");
+ } catch (Exception e) {
+ assertEquals(ComponentNotFoundException.class, e.getClass());
+ }
+ }
+
+ @Test
+ public void test_ResolveComponent_Root() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ UIComponent command3 = new UICommand();
+ command3.setId("command3");
+ root.getChildren().add(command3);
+
+ assertSame(facesContext.getViewRoot(), resolveComponent(command2, " @root "));
+ }
+
+ @Test
+ public void test_ResolveComponent_FormChildNextNext() {
+
+ UIForm root = new UIForm();
+ root.setId("form");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ UIComponent command3 = new UICommand();
+ command3.setId("command3");
+ root.getChildren().add(command3);
+
+ assertSame(command3, resolveComponent(command1, " @form:@child(0):@next:@next "));
+ }
+
+ @Test
+ public void test_ResolveComponent_IgnoreNoResult() {
+ UIForm root = new UIForm();
+ root.setId("form");
+
+ UIComponent command1 = new UICommand();
+ command1.setId("command1");
+ root.getChildren().add(command1);
+
+ UIComponent command2 = new UICommand();
+ command2.setId("command2");
+ root.getChildren().add(command2);
+
+ assertSame(null, resolveComponent(command1, " command3 ", SearchExpressionHint.IGNORE_NO_RESULT));
+ }
+
+ @Test
+ public void test_ResolveClientId_AbsoluteWithFormPrependIdFalse() {
+
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ form.setPrependId(false);
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertEquals("outerContainer:innerContainer:source", resolveClientId(source, " :form:outerContainer:innerContainer:source "));
+ }
+
+ @Test
+ public void test_ResolveClientId_AbsoluteWithFormPrependIdFalse_InvokeOnComponent() {
+
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ form.setPrependId(false);
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("outerContainer");
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("innerContainer");
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ source.setId("source");
+ innerContainer.getChildren().add(source);
+
+ assertEquals("outerContainer:innerContainer:source", resolveClientId(source, " outerContainer:innerContainer:source "));
+ }
+
+ @Test
+ public void test_Passthrough() {
+ SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
+
+ SearchExpressionContext searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(facesContext, null);
+
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:3:nested:1:nestedText"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:3:baseText"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:0:baseText"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:3:nested:0:nestedText"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:3:nested"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:table:1:nested:0:nestedText"));
+
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@this"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@this:@parent:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@parent:showName:@parent:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@form"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@form:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@namingcontainer:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@previous"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@next"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@parent:@id(msgName)"));
+
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@whoNows"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@parent:@whoNows"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "mainForm:@whoNows"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "!whoNows"));
+
+ Set hints = new HashSet<>();
+ hints.add(SearchExpressionHint.RESOLVE_CLIENT_SIDE);
+ searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(facesContext, null, hints, null);
+
+ Assertions.assertTrue(handler.isPassthroughExpression(searchExpressionContext, "@form"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@form:showName"));
+ Assertions.assertFalse(handler.isPassthroughExpression(searchExpressionContext, "@form:@child(0)"));
+ }
+
+ @Test
+ public void test_Valid() {
+ SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
+
+ SearchExpressionContext searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(facesContext, null);
+
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:showName"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:3:nested:1:nestedText"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:3:baseText"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:0:baseText"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:3:nested:0:nestedText"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:3:nested"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "mainForm:table:1:nested:0:nestedText"));
+
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@this"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@this:@parent:showName"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@parent:showName:@parent:showName"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@form:showName"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@namingcontainer:showName"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@previous"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@next"));
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@parent:@id(msgName)"));
+
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "@whoNows"));
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "@parent:@whoNows"));
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "mainForm:@whoNows"));
+
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "@none:@parent"));
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "@all:@parent"));
+ }
+
+ @Test
+ public void test_ResolveComponents_Id() {
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ outerContainer.setId("myContainer");
+ root.getChildren().add(outerContainer);
+
+ UIForm form = new UIForm();
+ form.setId("form");
+ root.getChildren().add(form);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ innerContainer.setId("myContainer");
+ form.getChildren().add(innerContainer);
+
+ UINamingContainer innerContainer2 = new UINamingContainer();
+ innerContainer2.setId("myContainer2");
+ form.getChildren().add(innerContainer2);
+
+ UINamingContainer innerContainer3 = new UINamingContainer();
+ innerContainer3.setId("myContainer3-test");
+ form.getChildren().add(innerContainer3);
+
+ List result = resolveComponents(form, " @id(myContainer) ");
+ assertTrue(result.size() == 1);
+ assertTrue(result.contains(innerContainer));
+
+ result = resolveComponents(form, " @id(myContainer3-test) ");
+ assertTrue(result.size() == 1);
+ assertTrue(result.contains(innerContainer3));
+ }
+
+ /**
+ * The SearchExpression API was inspired by PrimeFaces. This test only tests, if PFS (PrimeFaces Selectors -> jQuery
+ * like selectors; like @(#myId > .myStyle)) can be correctly handled by the API+IMPL as a passthrough expression.
+ */
+ @Test
+ public void test_PFS() {
+ CompositeSearchKeywordResolver s = (CompositeSearchKeywordResolver) application.getSearchKeywordResolver();
+ s.add(new SearchKeywordResolver() {
+
+ @Override
+ public void resolve(SearchKeywordContext searchKeywordContext, UIComponent previous, String keyword) {
+
+ }
+
+ @Override
+ public boolean isResolverForKeyword(SearchExpressionContext searchExpressionContext, String keyword) {
+ return keyword.startsWith("(") && keyword.endsWith(")");
+ }
+
+ @Override
+ public boolean isPassthrough(SearchExpressionContext searchExpressionContext, String keyword) {
+ return true;
+ }
+
+ @Override
+ public boolean isLeaf(SearchExpressionContext searchExpressionContext, String keyword) {
+ return true;
+ }
+ });
+
+ UIComponent root = new UIPanel();
+ FacesContext.getCurrentInstance().getViewRoot().getChildren().add(root);
+
+ assertEquals("@(.myPanel #id)", resolveClientId(root, " @(.myPanel #id)"));
+
+ SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
+ SearchExpressionContext searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(facesContext, null);
+ Assertions.assertTrue(handler.isValidExpression(searchExpressionContext, "@(.myPanel #id)"));
+ Assertions.assertFalse(handler.isValidExpression(searchExpressionContext, "@(.myPanel #id):test"));
+ }
+
+ @Test
+ public void test_chainOfResponsability() {
+ CompositeSearchKeywordResolver s = (CompositeSearchKeywordResolver) application.getSearchKeywordResolver();
+ s.add(new CustomSearchKeywordResolverImplForm()); // drop in new @form resolver
+
+ UIComponent root = new UIPanel();
+
+ UIForm form = new UIForm();
+ root.getChildren().add(form);
+
+ UINamingContainer outerContainer = new UINamingContainer();
+ form.getChildren().add(outerContainer);
+
+ UINamingContainer innerContainer = new UINamingContainer();
+ outerContainer.getChildren().add(innerContainer);
+
+ UIComponent component = new UIOutput();
+ innerContainer.getChildren().add(component);
+
+ UIComponent source = new UICommand();
+ innerContainer.getChildren().add(source);
+
+ assertSame(source, resolveComponent(source, "@form"));
+ assertNotSame(form, resolveComponent(source, "@form"));
+ }
+
+ class CustomSearchKeywordResolverImplForm extends SearchKeywordResolverImplForm {
+ @Override
+ public void resolve(SearchKeywordContext searchKeywordContext, UIComponent current, String keyword) {
+ searchKeywordContext.invokeContextCallback(current);
+ }
+ }
+
+ @Test
+ public void test_ResolveComponent_LeafErrorHandling() {
+
+ UIComponent root = new UIPanel();
+ root.setId("root");
+
+ try {
+ resolveComponent(root, " @none:myId");
+ fail("This should actually raise an exception");
+ } catch (Exception e) {
+ assertEquals(FacesException.class, e.getClass());
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/StateHolderSaverTestCase.java b/impl/src/test/java/jakarta/faces/component/StateHolderSaverTestCase.java
new file mode 100644
index 0000000000..721dce80c4
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/StateHolderSaverTestCase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.convert.IntegerConverter;
+
+public class StateHolderSaverTestCase extends UIComponentBaseTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ @Override
+ @Test
+ public void testChildrenRecursive() {
+ }
+
+ @Override
+ @Test
+ public void testComponentReconnect() {
+ }
+
+ @Override
+ @Test
+ public void testComponentRemoval() {
+ }
+
+ @Test
+ public void testImplementsStateHolder() throws Exception {
+ StateHolderSaver saver = null;
+ UIInput postSave, preSave = new UIInput();
+ preSave.setId("id1");
+ preSave.setRendererType(null);
+
+ saver = new StateHolderSaver(facesContext, preSave);
+ postSave = (UIInput) saver.restore(facesContext);
+ assertEquals(postSave.getId(), preSave.getId());
+ }
+
+ @Test
+ public void testImplementsSerializable() throws Exception {
+ StateHolderSaver saver = null;
+ String preSave = "hello";
+ String postSave = null;
+
+ saver = new StateHolderSaver(facesContext, preSave);
+ postSave = (String) saver.restore(facesContext);
+ assertTrue(preSave.equals(postSave));
+ }
+
+ @Test
+ public void testImplementsNeither() throws Exception {
+ StateHolderSaver saver = null;
+ IntegerConverter preSave = new IntegerConverter(), postSave = null;
+
+ saver = new StateHolderSaver(facesContext, preSave);
+ postSave = (IntegerConverter) saver.restore(facesContext);
+ assertTrue(postSave != null); // lack of ClassCastException
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIColumnTestCase.java b/impl/src/test/java/jakarta/faces/component/UIColumnTestCase.java
new file mode 100644
index 0000000000..e17feeb7cf
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIColumnTestCase.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UIColumn}.
+ *
+ */
+public class UIColumnTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIColumn();
+ expectedFamily = UIColumn.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = null;
+ }
+
+ // Tear down instance variables required by ths test case
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIColumn();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UICommandTestCase.java b/impl/src/test/java/jakarta/faces/component/UICommandTestCase.java
new file mode 100644
index 0000000000..b6d12aea60
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UICommandTestCase.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockExternalContext;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.ActionEvent;
+import jakarta.faces.event.ActionListener;
+import jakarta.faces.event.PhaseId;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+import jakarta.faces.render.Renderer;
+
+/**
+ *
+ * Unit tests for {@link UICommand}.
+ *
+ */
+public class UICommandTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UICommand();
+ expectedFamily = UICommand.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = "jakarta.faces.Button";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test order of action listener calls with actionListener also
+ public void PENDING_FIXME_testActionOrder() throws Exception {
+
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = renderKitFactory.getRenderKit(facesContext, RenderKitFactory.HTML_BASIC_RENDER_KIT);
+ renderKit.addRenderer(UICommand.COMPONENT_FAMILY, "jakarta.faces.Button", new ButtonRenderer());
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UICommand command = (UICommand) component;
+ command.setId("command");
+ command.addActionListener(new CommandActionListenerTestImpl("l1"));
+ command.addActionListener(new CommandActionListenerTestImpl("l2"));
+ command.setImmediate(true);
+ request.setAttribute("l3", new CommandActionListenerTestImpl("l3"));
+
+ // Override the default action listener to test ordering
+ ActionListener oldDefaultActionListener = facesContext.getApplication().getActionListener();
+ facesContext.getApplication().setActionListener(new CommandActionListenerTestImpl("14"));
+ Map map = new HashMap<>();
+ map.put(command.getClientId(facesContext), "");
+ MockExternalContext econtext = (MockExternalContext) facesContext.getExternalContext();
+ econtext.setRequestParameterMap(map);
+ CommandActionListenerTestImpl.trace(null);
+ root.processDecodes(facesContext);
+ assertEquals("/l1/l2/l3", CommandActionListenerTestImpl.trace());
+
+ // Restore the default action listener
+ facesContext.getApplication().setActionListener(oldDefaultActionListener);
+ }
+
+ // Test event queuing and broadcasting (any phase listeners)
+ @Test
+ public void testEventsGeneric() {
+
+ UICommand command = (UICommand) component;
+ command.setRendererType(null);
+ ActionEvent event = new ActionEvent(command);
+
+ // Register three listeners
+ command.addActionListener(new ActionListenerTestImpl("AP0"));
+ command.addActionListener(new ActionListenerTestImpl("AP1"));
+ command.addActionListener(new ActionListenerTestImpl("AP2"));
+
+ // Fire events and evaluate results
+ ActionListenerTestImpl.trace(null);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(command);
+ command.queueEvent(event);
+ root.processDecodes(facesContext);
+ root.processValidators(facesContext);
+ root.processApplication(facesContext);
+ assertEquals("/AP0@INVOKE_APPLICATION 5/AP1@INVOKE_APPLICATION 5/AP2@INVOKE_APPLICATION 5", ActionListenerTestImpl.trace());
+
+ }
+
+ // Test event queuing and broadcasting (mixed phase listeners)
+ @Test
+ public void testEventsMixed() {
+
+ UICommand command = (UICommand) component;
+ command.setRendererType(null);
+ ActionEvent event = new ActionEvent(command);
+
+ // Register three listeners
+ command.addActionListener(new ActionListenerTestImpl("ARV"));
+ command.addActionListener(new ActionListenerTestImpl("PV"));
+ command.addActionListener(new ActionListenerTestImpl("AP"));
+
+ // Fire events and evaluate results
+ ActionListenerTestImpl.trace(null);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(command);
+ command.queueEvent(event);
+ root.processDecodes(facesContext);
+ root.processValidators(facesContext);
+ root.processApplication(facesContext);
+ assertEquals("/ARV@INVOKE_APPLICATION 5/PV@INVOKE_APPLICATION 5/AP@INVOKE_APPLICATION 5", ActionListenerTestImpl.trace());
+
+ }
+
+ // Test event queuing and broadcasting (mixed phase listeners), with
+ // immediate set.
+ @Test
+ public void testEventsMixedImmediate() {
+
+ UICommand command = (UICommand) component;
+ command.setImmediate(true);
+ command.setRendererType(null);
+ ActionEvent event = new ActionEvent(command);
+
+ // Register three listeners
+ command.addActionListener(new ActionListenerTestImpl("ARV"));
+ command.addActionListener(new ActionListenerTestImpl("PV"));
+ command.addActionListener(new ActionListenerTestImpl("AP"));
+
+ // Fire events and evaluate results
+ ActionListenerTestImpl.trace(null);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(command);
+ command.queueEvent(event);
+ root.processDecodes(facesContext);
+ root.processValidators(facesContext);
+ root.processApplication(facesContext);
+ assertEquals("/ARV@APPLY_REQUEST_VALUES 2/PV@APPLY_REQUEST_VALUES 2/AP@APPLY_REQUEST_VALUES 2", ActionListenerTestImpl.trace());
+
+ }
+
+ // Test listener registration and deregistration
+ @Test
+ public void testListeners() {
+
+ CommandTestImpl command = new CommandTestImpl();
+
+ command.addActionListener(new ActionListenerTestImpl("ARV0"));
+ command.addActionListener(new ActionListenerTestImpl("ARV1"));
+ command.addActionListener(new ActionListenerTestImpl("PV0"));
+ command.addActionListener(new ActionListenerTestImpl("PV1"));
+ command.addActionListener(new ActionListenerTestImpl("PV2"));
+
+ ActionListener listeners[] = command.getActionListeners();
+ assertEquals(5, listeners.length);
+ command.removeActionListener(listeners[2]);
+ listeners = command.getActionListeners();
+ assertEquals(4, listeners.length);
+
+ }
+
+ // Test empty listener list
+ @Test
+ public void testEmptyListeners() {
+
+ CommandTestImpl command = new CommandTestImpl();
+
+ // No listeners added, should be empty
+ ActionListener listeners[] = command.getActionListeners();
+ assertEquals(0, listeners.length);
+
+ }
+
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ @Test
+ public void testNestedCommands() {
+ UIViewRoot root = new UIViewRoot();
+ UICommand c1 = new UICommand();
+ UICommand c2 = new UICommand();
+ root.getChildren().add(c1);
+ c2.setImmediate(true);
+ c1.getChildren().add(c2);
+ ActionEvent ae = new ActionEvent(c2);
+ c2.queueEvent(ae);
+ assertTrue(ae.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES));
+
+ root = new UIViewRoot();
+ c1 = new UICommand();
+ c2 = new UICommand();
+ root.getChildren().add(c1);
+ c1.setImmediate(true);
+ c2.setImmediate(false);
+ c1.getChildren().add(c2);
+ ae = new ActionEvent(c2);
+ c2.queueEvent(ae);
+ assertTrue(ae.getPhaseId().equals(PhaseId.INVOKE_APPLICATION));
+ }
+
+ @Test
+ public void testGetActionListeners() throws Exception {
+ UICommand command = (UICommand) component;
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(command);
+
+ ActionListenerTestImpl ta1 = new ActionListenerTestImpl("ta1"), ta2 = new ActionListenerTestImpl("ta2");
+
+ command.addActionListener(ta1);
+ command.addActionListener(ta2);
+ ActionListener[] listeners = command.getActionListeners();
+ assertEquals(2, listeners.length);
+ ActionListenerTestImpl[] taListeners = (ActionListenerTestImpl[]) command.getFacesListeners(ActionListenerTestImpl.class);
+ }
+
+ // --------------------------------------------------------- Support Methods
+
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UICommand();
+ component.setRendererType(null);
+ return component;
+ }
+
+ protected boolean listenersAreEqual(FacesContext context, UICommand comp1, UICommand comp2) {
+ ActionListener[] list1 = comp1.getActionListeners();
+ ActionListener[] list2 = comp2.getActionListeners();
+ // make sure they're either both null or both non-null
+ if (null == list1 && null != list2 || null != list1 && null == list2) {
+ return false;
+ }
+ if (null == list1) {
+ return true;
+ }
+ int j = 0, outerLen = list1.length;
+ boolean result = true;
+ if (outerLen != list2.length) {
+ return false;
+ }
+ for (j = 0; j < outerLen; j++) {
+ result = list1[j].equals(list2[j]);
+ if (!result) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // --------------------------------------------------------- Private Classes
+ // "Button" Renderer
+ class ButtonRenderer extends Renderer {
+
+ @Override
+ public void decode(FacesContext context, UIComponent component) {
+
+ if (context == null || component == null) {
+ throw new NullPointerException();
+ }
+
+ if (!(component instanceof ActionSource)) {
+ return;
+ }
+ String clientId = component.getClientId(context);
+ Map params = context.getExternalContext().getRequestParameterMap();
+ if (params.containsKey(clientId)) {
+ component.queueEvent(new ActionEvent(component));
+ }
+ }
+
+ @Override
+ public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
+ if (context == null || component == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ @Override
+ public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
+ if (context == null || component == null) {
+ throw new NullPointerException();
+ }
+ }
+
+ @Override
+ public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
+ if (context == null || component == null) {
+ throw new NullPointerException();
+ }
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIComponentBaseAttachedStateTestCase.java b/impl/src/test/java/jakarta/faces/component/UIComponentBaseAttachedStateTestCase.java
new file mode 100644
index 0000000000..37d97bc789
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIComponentBaseAttachedStateTestCase.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockExternalContext;
+import com.sun.faces.mock.MockFacesContext;
+import com.sun.faces.mock.MockHttpServletRequest;
+import com.sun.faces.mock.MockHttpServletResponse;
+import com.sun.faces.mock.MockLifecycle;
+import com.sun.faces.mock.MockServletContext;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.FacesListener;
+import jakarta.faces.event.ValueChangeListener;
+
+public class UIComponentBaseAttachedStateTestCase {
+
+ private MockFacesContext facesContext = null;
+ private MockServletContext servletContext;
+ private MockHttpServletRequest request;
+ private MockHttpServletResponse response;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ facesContext = new MockFacesContext();
+
+ servletContext = new MockServletContext();
+ servletContext.addInitParameter("appParamName", "appParamValue");
+ servletContext.setAttribute("appScopeName", "appScopeValue");
+ request = new MockHttpServletRequest(null);
+ request.setAttribute("reqScopeName", "reqScopeValue");
+ response = new MockHttpServletResponse();
+
+ // Create something to stand-in as the InitFacesContext
+ new MockFacesContext(new MockExternalContext(servletContext, request, response), new MockLifecycle());
+
+ }
+
+ @AfterEach
+ public void tearDown() throws Exception {
+ FactoryFinder.releaseFactories();
+ Method reInitializeFactoryManager = FactoryFinder.class.getDeclaredMethod("reInitializeFactoryManager", (Class>[]) null);
+ reInitializeFactoryManager.setAccessible(true);
+ reInitializeFactoryManager.invoke(null, (Object[]) null);
+ }
+
+
+ @Test
+ public void testAttachedObjectsSet() throws Exception {
+ Set attachedObjects = new HashSet<>();
+ ValueChangeListener toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ Object result = UIComponentBase.saveAttachedState(facesContext, attachedObjects);
+ @SuppressWarnings("unchecked")
+ Set returnedAttachedObjects = (Set) UIComponentBase
+ .restoreAttachedState(facesContext, result);
+ assertNotNull(returnedAttachedObjects);
+ }
+
+ @Test
+ public void testAttachedObjectsStack() throws Exception {
+ Stack attachedObjects = new Stack<>();
+ ValueChangeListener toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ Object result = UIComponentBase.saveAttachedState(facesContext, attachedObjects);
+ @SuppressWarnings("unchecked")
+ Stack returnedAttachedObjects = (Stack) UIComponentBase
+ .restoreAttachedState(facesContext, result);
+ assertNotNull(returnedAttachedObjects);
+ }
+
+ @Test
+ public void testAttachedObjectsMap() throws Exception {
+ Map attachedObjects = new HashMap<>();
+ ValueChangeListener toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.put("one", toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.put("two", toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.put("three", toAdd);
+ Object result = UIComponentBase.saveAttachedState(facesContext, attachedObjects);
+ @SuppressWarnings("unchecked")
+ Map returnedAttachedObjects = (Map) UIComponentBase
+ .restoreAttachedState(facesContext, result);
+ assertNotNull(returnedAttachedObjects);
+ }
+
+ // Regression test for bug #907
+ @SuppressWarnings("unchecked")
+ public void testAttachedObjectsCount() throws Exception {
+ Set returnedAttachedObjects = null, attachedObjects = new HashSet<>();
+ ValueChangeListener toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ toAdd = new ValueChangeListenerTestImpl();
+ attachedObjects.add(toAdd);
+ Object result = UIComponentBase.saveAttachedState(facesContext, attachedObjects);
+ returnedAttachedObjects = (Set) UIComponentBase.restoreAttachedState(facesContext, result);
+ int firstSize = returnedAttachedObjects.size();
+ returnedAttachedObjects = (Set) UIComponentBase.restoreAttachedState(facesContext, result);
+ int secondSize = returnedAttachedObjects.size();
+ assertEquals(firstSize, secondSize);
+ }
+
+ @Test
+ public void testFacesListenerState() {
+ UIComponent component = new UIOutput();
+ TestFacesListener listener = new TestFacesListener();
+ listener.setValue("initial");
+ component.addFacesListener(listener);
+ component.markInitialState();
+ assertTrue(component.initialStateMarked());
+ assertTrue(listener.initialStateMarked());
+
+ Object state = component.saveState(facesContext);
+ assertNull(state);
+
+ component = new UIOutput();
+ listener = new TestFacesListener();
+ component.addFacesListener(listener);
+ listener.setValue("initial");
+ component.markInitialState();
+ listener.setValue("newvalue");
+ state = component.saveState(facesContext);
+ assertNotNull(state);
+
+ // verify that state is applied to existing Listener instances.
+ component = new UIOutput();
+ listener = new TestFacesListener();
+ component.addFacesListener(listener);
+ listener.setValue("newinitial");
+ component.restoreState(facesContext, state);
+ assertEquals("newvalue", listener.getValue());
+
+ // verify listeners are overwritten when using full state saving
+ component = new UIOutput();
+ listener = new TestFacesListener();
+ component.addFacesListener(listener);
+ listener.setValue("initial");
+ state = component.saveState(facesContext);
+ assertNotNull(state);
+ listener.setValue("postsave");
+
+ component.restoreState(facesContext, state);
+ TestFacesListener l = (TestFacesListener) component.getFacesListeners(TestFacesListener.class)[0];
+ assertTrue(l != listener);
+ assertEquals("initial", l.getValue());
+ }
+
+ @Test
+ public void testTransientListenersState() {
+ UIComponent output = new UIOutput();
+ output.markInitialState();
+ TestFacesListener l1 = new TestFacesListener();
+ TestFacesListener l2 = new TestFacesListener();
+ TestFacesListener l3 = new TestFacesListener();
+ TestFacesListener l4 = new TestFacesListener();
+ l1.setValue("l1");
+ l2.setValue("l2");
+ l3.setValue("l3");
+ l4.setValue("l4");
+ l2.setTransient(true);
+ l4.setTransient(true);
+
+ output.addFacesListener(l1);
+ output.addFacesListener(l2);
+ output.addFacesListener(l3);
+ output.addFacesListener(l4);
+
+ Object state = output.saveState(facesContext);
+ assertNotNull(state);
+ output = new UIOutput();
+ output.restoreState(facesContext, state);
+ FacesListener[] listeners = output.getFacesListeners(TestFacesListener.class);
+ assertTrue(listeners.length == 2);
+ assertEquals("l1", ((TestFacesListener) listeners[0]).getValue());
+ assertEquals("l3", ((TestFacesListener) listeners[1]).getValue());
+
+ output = new UIOutput();
+ output.markInitialState();
+ output.addFacesListener(l2);
+ state = output.saveState(facesContext);
+ assertNotNull(state);
+ output = new UIOutput();
+ output.restoreState(facesContext, state);
+ listeners = output.getFacesListeners(TestFacesListener.class);
+ assertTrue(listeners.length == 0);
+ }
+
+ @Test
+ public void testTransientListenersState2() {
+ UIComponent output = new UIOutput();
+ TestFacesListener l1 = new TestFacesListener();
+ TestFacesListener l2 = new TestFacesListener();
+ TestFacesListener l3 = new TestFacesListener();
+ TestFacesListener l4 = new TestFacesListener();
+ l1.setValue("l1");
+ l2.setValue("l2");
+ l3.setValue("l3");
+ l4.setValue("l4");
+ l2.setTransient(true);
+ l4.setTransient(true);
+
+ output.addFacesListener(l1);
+ output.addFacesListener(l2);
+ output.addFacesListener(l3);
+ output.addFacesListener(l4);
+
+ Object state = output.saveState(facesContext);
+ assertNotNull(state);
+ output = new UIOutput();
+ output.restoreState(facesContext, state);
+ FacesListener[] listeners = output.getFacesListeners(TestFacesListener.class);
+ assertTrue(listeners.length == 2);
+ assertEquals("l1", ((TestFacesListener) listeners[0]).getValue());
+ assertEquals("l3", ((TestFacesListener) listeners[1]).getValue());
+
+ output = new UIOutput();
+ output.addFacesListener(l2);
+ state = output.saveState(facesContext);
+ assertNotNull(state);
+ output = new UIOutput();
+ output.restoreState(facesContext, state);
+ listeners = output.getFacesListeners(TestFacesListener.class);
+ assertTrue(listeners.length == 0);
+ }
+
+ // ---------------------------------------------------------- Nested Classes
+ public static final class TestFacesListener implements FacesListener, PartialStateHolder {
+
+ private boolean initialState;
+ private String value;
+ private boolean trans;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ clearInitialState();
+ this.value = value;
+ }
+
+ @Override
+ public void markInitialState() {
+ initialState = true;
+ }
+
+ @Override
+ public boolean initialStateMarked() {
+ return initialState;
+ }
+
+ @Override
+ public void clearInitialState() {
+ initialState = false;
+ }
+
+ @Override
+ public Object saveState(FacesContext context) {
+ return !initialState ? new Object[] { value } : null;
+ }
+
+ @Override
+ public void restoreState(FacesContext context, Object state) {
+ if (state != null) {
+ Object[] values = (Object[]) state;
+ value = (String) values[0];
+ }
+ }
+
+ @Override
+ public boolean isTransient() {
+ return trans;
+ }
+
+ @Override
+ public void setTransient(boolean trans) {
+ this.trans = trans;
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIComponentBaseBehaviorTestCase.java b/impl/src/test/java/jakarta/faces/component/UIComponentBaseBehaviorTestCase.java
new file mode 100644
index 0000000000..8fe128cc07
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIComponentBaseBehaviorTestCase.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.behavior.ClientBehavior;
+import jakarta.faces.component.behavior.ClientBehaviorContext;
+import jakarta.faces.component.behavior.ClientBehaviorHint;
+import jakarta.faces.component.behavior.ClientBehaviorHolder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.BehaviorEvent;
+
+/**
+ *
+ * Test case for component behaviors.
+ *
+ *
+ * @since 2.0
+ */
+public class UIComponentBaseBehaviorTestCase extends UIComponentTestCase {
+
+ private static final String ONTEST = "ontest";
+ private static final String ONCLICK = "onclick";
+ private static final String ONCHANGE = "onchange";
+ private static final String TEST_FAMILY = "jakarta.faces.Test";
+ private static final Collection EVENTS = Set.of(ONTEST, ONCLICK, ONCHANGE);
+
+ public static class BehaviorComponent extends UIComponentBase implements ClientBehaviorHolder {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jakarta.faces.component.UIComponent#getFamily()
+ */
+ @Override
+ public String getFamily() {
+ return TEST_FAMILY;
+ }
+
+ @Override
+ public Collection getEventNames() {
+ return EVENTS;
+ }
+
+ @Override
+ public String getDefaultEventName() {
+ return ONTEST;
+ }
+
+ }
+
+ public static class TestBehavior implements ClientBehavior, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Set HINTS = Collections.unmodifiableSet(EnumSet.of(ClientBehaviorHint.SUBMITTING));
+
+ private static int sequence = 0;
+
+ private final int id;
+
+ public TestBehavior() {
+ id = sequence++;
+ }
+
+ public String getRendererType() {
+ return TEST_FAMILY;
+ }
+
+ @Override
+ public Set getHints() {
+ return HINTS;
+ }
+
+ @Override
+ public void broadcast(BehaviorEvent event) {
+ }
+
+ @Override
+ public void decode(FacesContext context, UIComponent component) {
+ }
+
+ @Override
+ public String getScript(ClientBehaviorContext bContext) {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + id;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TestBehavior other = (TestBehavior) obj;
+ if (id != other.id) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "Behavior #" + id;
+ }
+ }
+
+ /**
+ * Test method for {@link jakarta.faces.component.UIComponentBase#saveState(jakarta.faces.context.FacesContext)}.
+ */
+ @Test
+ public void testSaveState() {
+ BehaviorComponent comp = new BehaviorComponent();
+ // Cast component to the interface, to be sure about method definition.
+ ClientBehaviorHolder holder = comp;
+ TestBehavior behavior = new TestBehavior();
+ holder.addClientBehavior(ONCLICK, behavior);
+ TestBehavior behavior2 = new TestBehavior();
+ holder.addClientBehavior(ONCLICK, behavior2);
+ TestBehavior behavior3 = new TestBehavior();
+ holder.addClientBehavior(ONCHANGE, behavior3);
+ Object state = comp.saveState(facesContext);
+ BehaviorComponent restoredComp = new BehaviorComponent();
+ restoredComp.restoreState(facesContext, state);
+ Map> behaviors = restoredComp.getClientBehaviors();
+ assertFalse(behaviors.isEmpty());
+ assertTrue(behaviors.containsKey(ONCLICK));
+ assertTrue(behaviors.containsKey(ONCHANGE));
+ assertFalse(behaviors.containsKey(ONTEST));
+ assertEquals(2, behaviors.entrySet().size());
+ assertEquals(2, behaviors.size());
+ assertEquals(2, behaviors.size());
+ assertEquals(2, behaviors.get(ONCLICK).size());
+ assertEquals(1, behaviors.get(ONCHANGE).size());
+ assertEquals(behavior3, behaviors.get(ONCHANGE).get(0));
+ assertEquals(behavior, behaviors.get(ONCLICK).get(0));
+ assertEquals(behavior2, behaviors.get(ONCLICK).get(1));
+ }
+
+ @Test
+ public void testNonClientBehaviorHolder() throws Exception {
+ UIInput input = new UIInput();
+ try {
+ input.addClientBehavior(ONTEST, new TestBehavior());
+ } catch (IllegalStateException e) {
+ return;
+ }
+ assertFalse(true);
+ }
+
+ /**
+ * Test method for
+ * {@link jakarta.faces.component.UIComponentBase#addClientBehavior(java.lang.String, jakarta.faces.component.behavior.ClientBehavior)}.
+ */
+ @Test
+ public void testAddBehavior() {
+ BehaviorComponent comp = new BehaviorComponent();
+ // Cast component to the interface, to be sure about method definition.
+ ClientBehaviorHolder holder = comp;
+ holder.addClientBehavior(ONCLICK, new TestBehavior());
+ assertTrue(holder.getClientBehaviors().containsKey(ONCLICK));
+ holder.addClientBehavior(ONCLICK, new TestBehavior());
+ assertTrue(holder.getClientBehaviors().containsKey(ONCLICK));
+ holder.addClientBehavior(ONCHANGE, new TestBehavior());
+ assertTrue(holder.getClientBehaviors().containsKey(ONCHANGE));
+ holder.addClientBehavior("foo", new TestBehavior());
+ assertFalse(holder.getClientBehaviors().containsKey("foo"));
+ }
+
+ /**
+ * Test method for {@link jakarta.faces.component.UIComponentBase#getEventNames()}.
+ */
+ @Test
+ public void testGetEventNames() {
+ BehaviorComponent comp = new BehaviorComponent();
+ ClientBehaviorHolder holder = comp;
+ assertEquals(EVENTS, holder.getEventNames());
+ }
+
+ /**
+ * Test method for {@link jakarta.faces.component.UIComponentBase#getClientBehaviors()}.
+ */
+ @Test
+ public void testGetBehaviors() {
+ BehaviorComponent comp = new BehaviorComponent();
+ // Cast component to the interface, to be sure about method definition.
+ ClientBehaviorHolder holder = comp;
+ Map> behaviors = holder.getClientBehaviors();
+ assertTrue(behaviors.isEmpty());
+ assertFalse(behaviors.containsKey(ONCLICK));
+ assertFalse(behaviors.containsValue(new TestBehavior()));
+ assertEquals(0, behaviors.entrySet().size());
+ holder.addClientBehavior(ONCLICK, new TestBehavior());
+ holder.addClientBehavior(ONCLICK, new TestBehavior());
+ holder.addClientBehavior(ONCHANGE, new TestBehavior());
+ behaviors = holder.getClientBehaviors();
+ assertFalse(behaviors.isEmpty());
+ assertTrue(behaviors.containsKey(ONCLICK));
+ assertTrue(behaviors.containsKey(ONCHANGE));
+ assertFalse(behaviors.containsKey(ONTEST));
+ assertEquals(2, behaviors.entrySet().size());
+ assertEquals(2, behaviors.size());
+ assertEquals(2, behaviors.size());
+ assertEquals(2, behaviors.get(ONCLICK).size());
+ assertEquals(1, behaviors.get(ONCHANGE).size());
+ }
+
+ /**
+ * Test method for {@link jakarta.faces.component.UIComponentBase#getDefaultEventName()}.
+ */
+ @Test
+ public void testGetDefaultEventName() {
+ BehaviorComponent comp = new BehaviorComponent();
+ // Cast component to the interface, to be sure about method definition.
+ ClientBehaviorHolder holder = comp;
+ assertEquals(ONTEST, holder.getDefaultEventName());
+ }
+
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIComponentBaseTestCase.java b/impl/src/test/java/jakarta/faces/component/UIComponentBaseTestCase.java
new file mode 100644
index 0000000000..b07172cd55
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIComponentBaseTestCase.java
@@ -0,0 +1,1565 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.FacesException;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.AbortProcessingException;
+import jakarta.faces.event.ComponentSystemEvent;
+import jakarta.faces.event.ComponentSystemEventListener;
+import jakarta.faces.event.PostAddToViewEvent;
+import jakarta.faces.event.PostConstructViewMapEvent;
+import jakarta.faces.event.PreRenderComponentEvent;
+import jakarta.faces.event.SystemEvent;
+import jakarta.faces.event.SystemEventListener;
+
+/**
+ *
+ * Base unit tests for all {@link UIComponentBase} subclasses.
+ *
+ */
+public class UIComponentBaseTestCase extends UIComponentTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+
+ // Set up the component under test
+ super.setUp();
+ component = new ComponentTestImpl(expectedId);
+
+ }
+
+ // Tear down instance variables required by ths test case
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+ externalContext.setRequestParameterMap(null);
+
+ super.tearDown();
+
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test lifecycle management methods
+ @Test
+ public void testLifecycleManagement() {
+
+ checkLifecycleParentRendered();
+ checkLifecycleParentUnrendered();
+ checkLifecycleSelfRendered();
+ checkLifecycleSelfUnrendered();
+
+ }
+
+ @Test
+ public void testComponentToFromEL2() throws Exception {
+
+ final FacesContext ctx = facesContext;
+ ComponentTestImpl c = new ComponentTestImpl();
+ ComponentTestImpl c2 = new ComponentTestImpl();
+ UIComponent eeo = new UIComponentOverrideEncodeEnd();
+ ComponentTestImpl c3 = new ComponentTestImpl();
+ UIComponent ebo = new UIComponentOverrideEncodeBegin();
+
+ c.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c);
+ c2.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c2);
+ c2.encodeEnd(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c);
+ c.encodeEnd(ctx);
+ assertNull(UIComponent.getCurrentComponent(ctx));
+
+ // sanity check for the case where a component overrides
+ // encodeBegin() without calling super or pushComponentToEL
+ c.encodeBegin(ctx);
+ c2.encodeBegin(ctx);
+ ebo.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c2);
+ ebo.encodeEnd(ctx); // if the component wasn't pushed
+ // it shouldn't be popped.
+ assertEquals(UIComponent.getCurrentComponent(ctx), c2);
+ c2.encodeEnd(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c);
+ c.encodeEnd(ctx);
+ assertNull(UIComponent.getCurrentComponent(ctx));
+
+ // sanity check for the case where a component overrides
+ // encodeEnd() without calling super or popComponentFromEL
+ c.encodeBegin(ctx);
+ c2.encodeBegin(ctx);
+ eeo.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
+ eeo.encodeEnd(ctx);
+ // this is ugly. Because of a component not doing calling
+ // super() or popComponentFromEL, c2 won't be visible
+ // as the current component.
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
+ c2.encodeEnd(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c);
+ c.encodeEnd(ctx);
+ assertNull(UIComponent.getCurrentComponent(ctx));
+
+ UIComponent eeo2 = new UIComponentOverrideEncodeEnd();
+ c.encodeBegin(ctx);
+ c2.encodeBegin(ctx);
+ eeo.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
+ c3.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c3);
+ eeo2.encodeBegin(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
+ eeo2.encodeEnd(ctx);
+ // this is ugly.
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
+ c3.encodeEnd(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
+ eeo.encodeEnd(ctx);
+ // this is ugly.
+ assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
+ c2.encodeEnd(ctx);
+ assertEquals(UIComponent.getCurrentComponent(ctx), c);
+ c.encodeEnd(ctx);
+ assertNull(UIComponent.getCurrentComponent(ctx));
+
+ }
+
+ @Test
+ public void testEncodeChildren() throws Exception {
+ ComponentTestImpl.trace(null);
+ UIComponent comp1 = new ComponentTestImpl("one");
+ UIComponent comp2 = new ComponentTestImpl("two");
+ UIComponent comp3 = new ComponentTestImpl("three");
+ UIComponent comp4 = new ComponentTestImpl("four");
+
+ comp1.getChildren().add(comp2);
+ comp1.getChildren().add(comp3);
+ comp1.getChildren().add(comp4);
+
+ comp1.encodeChildren(facesContext);
+ System.out.println("Actual: " + ComponentTestImpl.trace());
+ System.out.println("Expected: " + "/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four");
+ assertEquals("/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four", ComponentTestImpl.trace());
+
+ }
+
+ // Test recursive adding and removing child trees with ids
+ @Test
+ public void testChildrenRecursive() {
+
+ // Create the components we will need
+ UIComponent testComponent = new ComponentTestImpl();
+ UIComponent child1 = new ComponentTestImpl("child1");
+ UIComponent child2 = new ComponentTestImpl("child2");
+ UIComponent child3 = new ComponentTestImpl("child3");
+
+ // Prepare ancestry tree before adding to base component
+ child1.getChildren().add(child2);
+ child2.getChildren().add(child3);
+
+ // Verify that no child ids are visible yet
+ assertNull(testComponent.findComponent("child1"));
+ assertNull(testComponent.findComponent("child2"));
+ assertNull(testComponent.findComponent("child3"));
+
+ // Add the entire tree
+ testComponent.getChildren().add(child1);
+
+ // Verify that all named children get added
+ assertEquals(child1, testComponent.findComponent("child1"));
+ assertEquals(child2, testComponent.findComponent("child2"));
+ assertEquals(child3, testComponent.findComponent("child3"));
+
+ // Remove the entire tree
+ testComponent.getChildren().remove(child1);
+
+ // Verify that child ids are no longer visible
+ assertNull(testComponent.findComponent("child1"));
+ assertNull(testComponent.findComponent("child2"));
+ assertNull(testComponent.findComponent("child3"));
+
+ }
+
+ @Test
+ public void testChildrenAndFacetsWithNullGetParent() throws Exception {
+ ComponentTestImpl child = new ComponentTestImpl() {
+ @Override
+ public UIComponent getParent() {
+ return null;
+ }
+ };
+ component.getChildren().add(child);
+ assertNull(component.getChildren().get(0).getParent());
+ ComponentTestImpl facet = new ComponentTestImpl() {
+ @Override
+ public UIComponent getParent() {
+ return null;
+ }
+ };
+ component.getFacets().put("nullParent", facet);
+ assertNull(component.getFacets().get("nullParent").getParent());
+ }
+
+ // Test reconnecting a child or facet to a different component
+ @Test
+ public void testComponentReconnect() {
+
+ UIComponent parent1 = new ComponentTestImpl();
+ UIComponent parent2 = new ComponentTestImpl();
+
+ // Reconnect an existing child as a child
+ checkChildCount(parent1, 0);
+ checkChildCount(parent2, 0);
+ parent1.getChildren().add(component);
+ checkChildCount(parent1, 1);
+ checkChildCount(parent2, 0);
+ checkChildPresent(parent1, component, 0);
+ parent2.getChildren().add(component);
+ checkChildCount(parent1, 0);
+ checkChildCount(parent2, 1);
+ checkChildPresent(parent2, component, 0);
+ parent2.getChildren().clear();
+ checkChildCount(parent1, 0);
+ checkChildCount(parent2, 0);
+
+ // Reconnect an existing child as a facet
+ checkChildCount(parent1, 0);
+ checkFacetCount(parent2, 0);
+ parent1.getChildren().add(component);
+ checkChildCount(parent1, 1);
+ checkFacetCount(parent2, 0);
+ checkChildPresent(parent1, component, 0);
+ parent2.getFacets().put("facet", component);
+ checkChildCount(parent1, 0);
+ checkFacetCount(parent2, 1);
+ checkFacetPresent(parent2, "facet", component);
+ parent2.getFacets().clear();
+ checkChildCount(parent1, 0);
+ checkFacetCount(parent2, 0);
+
+ // Reconnect an existing facet as a child
+ checkFacetCount(parent1, 0);
+ checkChildCount(parent2, 0);
+ parent1.getFacets().put("facet", component);
+ checkFacetCount(parent1, 1);
+ checkChildCount(parent2, 0);
+ checkFacetPresent(parent1, "facet", component);
+ parent2.getChildren().add(component);
+ checkFacetCount(parent1, 0);
+ checkChildCount(parent2, 1);
+ checkChildPresent(parent2, component, 0);
+ parent2.getChildren().clear();
+ checkFacetCount(parent1, 0);
+ checkChildCount(parent2, 0);
+
+ }
+
+ // Test removing components from our naming container.
+ @Test
+ public void testComponentRemoval() {
+
+ UIComponent testComponent = new ComponentTestImpl();
+ UIComponent child1 = new ComponentTestImpl("child1");
+ UIComponent child2 = new ComponentTestImpl("child2");
+ UIComponent child3 = new ComponentTestImpl("child3");
+ UIComponent child = null;
+
+ // adding children to naming container
+ testComponent.getChildren().add(child1);
+ testComponent.getChildren().add(child2);
+ testComponent.getChildren().add(child3);
+
+ // make sure children are stored in naming container properly
+ Iterator kidItr = null;
+
+ kidItr = testComponent.getFacetsAndChildren();
+
+ child = kidItr.next();
+ assertTrue(child.equals(child1));
+
+ child = kidItr.next();
+ assertTrue(child.equals(child2));
+
+ child = kidItr.next();
+ assertTrue(child.equals(child3));
+
+ // make sure child is removed from component and naming container
+ // pass in a component to remove method
+ testComponent.getChildren().remove(child1);
+
+ kidItr = testComponent.getFacetsAndChildren();
+
+ child = kidItr.next();
+ assertTrue(child.equals(child2));
+
+ child = kidItr.next();
+ assertTrue(child.equals(child3));
+
+ // make sure child is removed from component and naming container
+ // pass an index to remove method
+ testComponent.getChildren().remove(0);
+
+ kidItr = testComponent.getFacetsAndChildren();
+
+ child = kidItr.next();
+ assertTrue(child.equals(child3));
+
+ // make sure child is removed from component and naming container
+ // remove all children
+ testComponent.getChildren().clear();
+
+ kidItr = testComponent.getFacetsAndChildren();
+ assertTrue(!kidItr.hasNext());
+ }
+
+ @Test
+ public void testStateHolder2() throws Exception {
+
+ UIComponent c = new UIComponentListener();
+ c.subscribeToEvent(PostAddToViewEvent.class, c);
+ Object state = c.saveState(facesContext);
+ c = new UIComponentListener();
+ c.pushComponentToEL(facesContext, c);
+ c.restoreState(facesContext, state);
+ c.popComponentFromEL(facesContext);
+ assertTrue(c.getListenersForEventClass(PostAddToViewEvent.class).size() == 1);
+
+ }
+
+ @Test
+ public void testAttributesThatAreSetStateHolder() throws Exception {
+ ComponentTestImpl c = new ComponentTestImpl();
+ c.getAttributes().put("attr1", "value1");
+ c.markInitialState();
+ c.getAttributes().put("attr2", "value2");
+ assertEquals(Arrays.asList("attr1", "attr2"), c.getAttributes().get("jakarta.faces.component.UIComponentBase.attributesThatAreSet"));
+
+ Object state = c.saveState(facesContext);
+ c = new ComponentTestImpl();
+ c.pushComponentToEL(facesContext, c);
+ c.restoreState(facesContext, state);
+ c.popComponentFromEL(facesContext);
+ assertEquals(Arrays.asList("attr1", "attr2"), c.getAttributes().get("jakarta.faces.component.UIComponentBase.attributesThatAreSet"));
+ }
+
+ @Test
+ public void testValueExpressions() throws Exception {
+
+ UIComponentBase test = (UIComponentBase) component;
+
+ // generic attributes
+ request.setAttribute("foo", "bar");
+ test.getAttributes().clear();
+ assertNull(test.getAttributes().get("baz"));
+ test.setValueExpression("baz", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
+ assertEquals("bar", test.getAttributes().get("baz"));
+ test.getAttributes().put("baz", "bop");
+ assertEquals("bop", test.getAttributes().get("baz"));
+ test.getAttributes().remove("baz");
+ assertEquals("bar", test.getAttributes().get("baz"));
+ test.setValueExpression("baz", null);
+ assertNull(test.getAttributes().get("baz"));
+
+ // "id" property
+ try {
+ test.setValueExpression("id", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected response
+ }
+
+ // "parent" property
+ try {
+ test.setValueExpression("parent",
+ application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", UIComponent.class));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected response
+ }
+
+ // "rendered" property
+ request.setAttribute("foo", Boolean.FALSE);
+ test.setValueExpression("rendered", null);
+ boolean initial = test.isRendered();
+ if (initial) {
+ request.setAttribute("foo", Boolean.FALSE);
+ } else {
+ request.setAttribute("foo", Boolean.TRUE);
+ }
+ test.setValueExpression("rendered", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", Boolean.class));
+ assertEquals(!initial, test.isRendered());
+ test.setRendered(initial);
+ assertEquals(initial, test.isRendered());
+ assertNotNull(test.getValueExpression("rendered"));
+
+ // "rendererType" property
+ request.setAttribute("foo", "bar");
+ test.setRendererType(null);
+ assertNull(test.getRendererType());
+ test.setValueExpression("rendererType", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
+ assertNotNull(test.getValueExpression("rendererType"));
+ assertEquals("bar", test.getRendererType());
+ test.setRendererType("baz");
+ assertEquals("baz", test.getRendererType());
+ test.setRendererType(null);
+ assertEquals("bar", test.getRendererType());
+ test.setValueExpression("rendererType", null);
+ assertNull(test.getValueExpression("rendererType"));
+ assertNull(test.getRendererType());
+
+ }
+
+ // --------------------------------------------------------- support Methods
+ // Check that the attributes on the specified components are equal
+ protected void checkAttributes(UIComponent comp1, UIComponent comp2) {
+ assertEquals(comp1.getAttributes(), comp2.getAttributes());
+ }
+
+ // Check that the specified components are equal
+ protected void checkComponents(UIComponent comp1, UIComponent comp2) {
+ checkAttributes(comp1, comp2);
+ // checkFacets(comp1, comp2); // Not saved and restored by component
+ checkProperties(comp1, comp2);
+ }
+
+ // Check lifecycle processing when parent "rendered" property is "true"
+ private void checkLifecycleParentRendered() {
+
+ // Put our component under test in a tree under a UIViewRoot
+ component.getAttributes().clear();
+ component.getChildren().clear();
+ component.getFacets().clear();
+ component.setRendered(true);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ UIPanel panel = new UIPanel();
+ panel.setRendered(true);
+ root.getChildren().add(panel);
+ panel.getChildren().add(component);
+
+ // Establish a view with multiple facets and children
+ UIComponent facet1 = new ComponentTestImpl("f1");
+ UIComponent facet2 = new ComponentTestImpl("f2");
+ UIComponent facet3 = new ComponentTestImpl("f3");
+ component.getFacets().put("f1", facet1);
+ component.getFacets().put("f2", facet2);
+ component.getFacets().put("f3", facet3);
+ checkFacetCount(component, 3);
+ UIComponent child1 = new ComponentTestImpl("c1");
+ UIComponent child2 = new ComponentTestImpl("c2");
+ UIComponent child3 = new ComponentTestImpl("c3");
+ component.getChildren().add(child1);
+ component.getChildren().add(child2);
+ component.getChildren().add(child3);
+ checkChildCount(component, 3);
+ UIComponent child2a = new ComponentTestImpl("c2a");
+ UIComponent child2b = new ComponentTestImpl("c2b");
+ child2.getChildren().add(child2a);
+ child2.getChildren().add(child2b);
+ checkChildCount(child2, 2);
+
+ // Enqueue a single FacesEvent for each component
+ component.queueEvent(new EventTestImpl(component));
+ component.queueEvent(new EventTestImpl(facet1));
+ component.queueEvent(new EventTestImpl(facet2));
+ component.queueEvent(new EventTestImpl(facet3));
+ component.queueEvent(new EventTestImpl(child1));
+ component.queueEvent(new EventTestImpl(child2));
+ component.queueEvent(new EventTestImpl(child3));
+ component.queueEvent(new EventTestImpl(child2a));
+ component.queueEvent(new EventTestImpl(child2b));
+
+ // Test processDecodes()
+ ComponentTestImpl.trace(null);
+ component.processDecodes(facesContext);
+ assertEquals(lifecycleTrace("pD", "d"), ComponentTestImpl.trace());
+
+ // Test processValidators()
+ ComponentTestImpl.trace(null);
+ component.processValidators(facesContext);
+ assertEquals(lifecycleTrace("pV", null), ComponentTestImpl.trace());
+
+ // Test processUpdates()
+ ComponentTestImpl.trace(null);
+ component.processUpdates(facesContext);
+ assertEquals(lifecycleTrace("pU", null), ComponentTestImpl.trace());
+
+ }
+
+ // Check lifecycle processing when parent "rendered" property is "false"
+ private void checkLifecycleParentUnrendered() {
+
+ // Put our component under test in a tree under a UIViewRoot
+ component.getAttributes().clear();
+ component.getChildren().clear();
+ component.getFacets().clear();
+ component.setRendered(true);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ UIPanel panel = new UIPanel();
+ panel.setRendered(false);
+ root.getChildren().add(panel);
+ panel.getChildren().add(component);
+
+ // Establish a view with multiple facets and children
+ UIComponent facet1 = new ComponentTestImpl("f1");
+ UIComponent facet2 = new ComponentTestImpl("f2");
+ UIComponent facet3 = new ComponentTestImpl("f3");
+ component.getFacets().put("f1", facet1);
+ component.getFacets().put("f2", facet2);
+ component.getFacets().put("f3", facet3);
+ checkFacetCount(component, 3);
+ UIComponent child1 = new ComponentTestImpl("c1");
+ UIComponent child2 = new ComponentTestImpl("c2");
+ UIComponent child3 = new ComponentTestImpl("c3");
+ component.getChildren().add(child1);
+ component.getChildren().add(child2);
+ component.getChildren().add(child3);
+ checkChildCount(component, 3);
+ UIComponent child2a = new ComponentTestImpl("c2a");
+ UIComponent child2b = new ComponentTestImpl("c2b");
+ child2.getChildren().add(child2a);
+ child2.getChildren().add(child2b);
+ checkChildCount(child2, 2);
+
+ // Enqueue a single FacesEvent for each component
+ component.queueEvent(new EventTestImpl(component));
+ component.queueEvent(new EventTestImpl(facet1));
+ component.queueEvent(new EventTestImpl(facet2));
+ component.queueEvent(new EventTestImpl(facet3));
+ component.queueEvent(new EventTestImpl(child1));
+ component.queueEvent(new EventTestImpl(child2));
+ component.queueEvent(new EventTestImpl(child3));
+ component.queueEvent(new EventTestImpl(child2a));
+ component.queueEvent(new EventTestImpl(child2b));
+
+ // Test processDecodes()
+ ComponentTestImpl.trace(null);
+ component.processDecodes(facesContext);
+ assertEquals(lifecycleTrace("pD", "d"), ComponentTestImpl.trace());
+
+ // Test processValidators()
+ ComponentTestImpl.trace(null);
+ component.processValidators(facesContext);
+ assertEquals(lifecycleTrace("pV", null), ComponentTestImpl.trace());
+
+ // Test processUpdates()
+ ComponentTestImpl.trace(null);
+ component.processUpdates(facesContext);
+ assertEquals(lifecycleTrace("pU", null), ComponentTestImpl.trace());
+
+ }
+
+ // Check lifecycle processing when our "rendered" property is "true"
+ private void checkLifecycleSelfRendered() {
+
+ // Put our component under test in a tree under a UIViewRoot
+ component.getAttributes().clear();
+ component.getChildren().clear();
+ component.getFacets().clear();
+ component.setRendered(true);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Establish a view with multiple facets and children
+ UIComponent facet1 = new ComponentTestImpl("f1");
+ UIComponent facet2 = new ComponentTestImpl("f2");
+ UIComponent facet3 = new ComponentTestImpl("f3");
+ component.getFacets().put("f1", facet1);
+ component.getFacets().put("f2", facet2);
+ component.getFacets().put("f3", facet3);
+ checkFacetCount(component, 3);
+ UIComponent child1 = new ComponentTestImpl("c1");
+ UIComponent child2 = new ComponentTestImpl("c2");
+ UIComponent child3 = new ComponentTestImpl("c3");
+ component.getChildren().add(child1);
+ component.getChildren().add(child2);
+ component.getChildren().add(child3);
+ checkChildCount(component, 3);
+ UIComponent child2a = new ComponentTestImpl("c2a");
+ UIComponent child2b = new ComponentTestImpl("c2b");
+ child2.getChildren().add(child2a);
+ child2.getChildren().add(child2b);
+ checkChildCount(child2, 2);
+
+ // Enqueue a single FacesEvent for each component
+ component.queueEvent(new EventTestImpl(component));
+ component.queueEvent(new EventTestImpl(facet1));
+ component.queueEvent(new EventTestImpl(facet2));
+ component.queueEvent(new EventTestImpl(facet3));
+ component.queueEvent(new EventTestImpl(child1));
+ component.queueEvent(new EventTestImpl(child2));
+ component.queueEvent(new EventTestImpl(child3));
+ component.queueEvent(new EventTestImpl(child2a));
+ component.queueEvent(new EventTestImpl(child2b));
+
+ // Test processDecodes()
+ ComponentTestImpl.trace(null);
+ component.processDecodes(facesContext);
+ assertEquals(lifecycleTrace("pD", "d"), ComponentTestImpl.trace());
+
+ // Test processValidators()
+ ComponentTestImpl.trace(null);
+ component.processValidators(facesContext);
+ assertEquals(lifecycleTrace("pV", null), ComponentTestImpl.trace());
+
+ // Test processUpdates()
+ ComponentTestImpl.trace(null);
+ component.processUpdates(facesContext);
+ assertEquals(lifecycleTrace("pU", null), ComponentTestImpl.trace());
+
+ }
+
+ // Check lifecycle processing when our "rendered" property is "false"
+ private void checkLifecycleSelfUnrendered() {
+
+ // Put our component under test in a tree under a UIViewRoot
+ component.getAttributes().clear();
+ component.getChildren().clear();
+ component.getFacets().clear();
+ component.setRendered(false);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Establish a view with multiple facets and children
+ UIComponent facet1 = new ComponentTestImpl("f1");
+ UIComponent facet2 = new ComponentTestImpl("f2");
+ UIComponent facet3 = new ComponentTestImpl("f3");
+ component.getFacets().put("f1", facet1);
+ component.getFacets().put("f2", facet2);
+ component.getFacets().put("f3", facet3);
+ checkFacetCount(component, 3);
+ UIComponent child1 = new ComponentTestImpl("c1");
+ UIComponent child2 = new ComponentTestImpl("c2");
+ UIComponent child3 = new ComponentTestImpl("c3");
+ component.getChildren().add(child1);
+ component.getChildren().add(child2);
+ component.getChildren().add(child3);
+ checkChildCount(component, 3);
+ UIComponent child2a = new ComponentTestImpl("c2a");
+ UIComponent child2b = new ComponentTestImpl("c2b");
+ child2.getChildren().add(child2a);
+ child2.getChildren().add(child2b);
+ checkChildCount(child2, 2);
+
+ // Enqueue a single FacesEvent for each component
+ component.queueEvent(new EventTestImpl(component));
+ component.queueEvent(new EventTestImpl(facet1));
+ component.queueEvent(new EventTestImpl(facet2));
+ component.queueEvent(new EventTestImpl(facet3));
+ component.queueEvent(new EventTestImpl(child1));
+ component.queueEvent(new EventTestImpl(child2));
+ component.queueEvent(new EventTestImpl(child3));
+ component.queueEvent(new EventTestImpl(child2a));
+ component.queueEvent(new EventTestImpl(child2b));
+
+ // Test processDecodes()
+ ComponentTestImpl.trace(null);
+ component.processDecodes(facesContext);
+ assertEquals(lifecycleTrace("pD", "d"), ComponentTestImpl.trace());
+
+ // Test processValidators()
+ ComponentTestImpl.trace(null);
+ component.processValidators(facesContext);
+ assertEquals(lifecycleTrace("pV", null), ComponentTestImpl.trace());
+
+ // Test processUpdates()
+ ComponentTestImpl.trace(null);
+ component.processUpdates(facesContext);
+ assertEquals(lifecycleTrace("pU", null), ComponentTestImpl.trace());
+
+ }
+
+ // Check that the properties on the specified components are equal
+ protected void checkProperties(UIComponent comp1, UIComponent comp2) {
+ assertEquals(comp1.getClientId(facesContext), comp2.getClientId(facesContext));
+ assertEquals(comp1.getId(), comp2.getId());
+ assertEquals(comp1.isRendered(), comp2.isRendered());
+ assertEquals(comp1.getRendererType(), comp2.getRendererType());
+ assertEquals(comp1.getRendersChildren(), comp2.getRendersChildren());
+ }
+
+ protected void checkComponentListeners(UIComponent control, UIComponent toValidate) {
+
+ List lc = control.getListenersForEventClass(PostAddToViewEvent.class);
+ List tvl = toValidate.getListenersForEventClass(PostAddToViewEvent.class);
+ List lc2 = control.getListenersForEventClass(PostConstructViewMapEvent.class);
+ List tvl2 = toValidate.getListenersForEventClass(PostConstructViewMapEvent.class);
+ assertTrue(lc.size() == tvl.size());
+ assertTrue(lc2.size() == tvl2.size());
+
+ }
+
+ // Create a pristine component of the type to be used in state holder tests
+ protected UIComponent createComponent() {
+ return new ComponentTestImpl();
+ }
+
+ /**
+ * Construct and return a lifecycle method call trace for the specified method names.
+ *
+ * @param lmethod Name of the lifecycle method under test
+ * @param cmethod Name of the component method that corresponds
+ * @return
+ */
+ protected String lifecycleTrace(String lmethod, String cmethod) {
+ StringBuilder sb = new StringBuilder();
+ lifecycleTrace(lmethod, cmethod, component, sb);
+ return sb.toString();
+ }
+
+ protected void lifecycleTrace(String lmethod, String cmethod, UIComponent component, StringBuilder sb) {
+
+ // Append the call for this lifecycle method
+ String id = component.getId();
+ sb.append('/').append(lmethod).append('-').append(id);
+ if (!component.isRendered()) {
+ return;
+ }
+
+ // Append the calls for each facet
+ Iterator names = component.getFacets().keySet().iterator();
+ while (names.hasNext()) {
+ String name = names.next();
+ sb.append('/').append(lmethod).append('-').append(name);
+ if (cmethod != null && component.getFacets().get(name).isRendered()) {
+ sb.append('/').append(cmethod).append('-').append(name);
+ }
+ }
+
+ // Append the calls for each child
+ Iterator kids = component.getChildren().iterator();
+ while (kids.hasNext()) {
+ UIComponent kid = kids.next();
+ lifecycleTrace(lmethod, cmethod, kid, sb);
+ }
+
+ // Append the call for this component's component method
+ if (cmethod != null && component.isRendered()) {
+ sb.append('/').append(cmethod).append('-').append(id);
+ }
+
+ }
+
+ @Test
+ public void testGetFacetsAndChildren() {
+
+ UIComponent testComponent = new ComponentTestImpl();
+ UIComponent child1 = new ComponentTestImpl("child1");
+ UIComponent child2 = new ComponentTestImpl("child2");
+ UIComponent child3 = new ComponentTestImpl("child3");
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+
+ testComponent.getChildren().add(child1);
+ testComponent.getChildren().add(child2);
+ testComponent.getChildren().add(child3);
+ testComponent.getFacets().put("facet1", facet1);
+ testComponent.getFacets().put("facet2", facet2);
+ testComponent.getFacets().put("facet3", facet3);
+
+ Iterator iter = testComponent.getFacetsAndChildren();
+ Object cur = null;
+ boolean exceptionThrown = false;
+ assertTrue(iter.hasNext());
+
+ try {
+ iter.remove();
+ } catch (UnsupportedOperationException e) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+
+ // facets are returned in an undefined order.
+ cur = iter.next();
+ assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
+ cur = iter.next();
+ assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
+ cur = iter.next();
+ assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
+
+ // followed by components, in the order added
+ cur = iter.next();
+ assertTrue(cur == child1);
+ cur = iter.next();
+ assertTrue(cur == child2);
+ cur = iter.next();
+ assertTrue(cur == child3);
+
+ assertTrue(!iter.hasNext());
+
+ }
+
+ private Object foundComponent = null;
+
+ /**
+ *
+ * Build a tree with the following layout.
+ *
+ *
+ * root: id: root
+ *
+ * form1: id: form1
+ *
+ * panel1: id: panel
+ *
+ * input1: id: input1
+ *
+ * input2: id: input2
+ *
+ * form2: id: form2
+ *
+ * panel2: id: panel
+ *
+ * input3: id: input1
+ *
+ * input4: id: input2
+ *
+ *
+ * @return a Map. The key is the string before the first : in the above layout. The value is the
+ * component instance. Note that the keys in the map are not the ids.
+ */
+ private Map setupInvokeOnComponentTree() {
+ UIViewRoot root = new UIViewRoot();
+ UIForm form1 = new UIForm();
+ UIPanel panel1 = new UIPanel();
+ UIInput input1 = new UIInput();
+ UIInput input2 = new UIInput();
+ UIForm form2 = new UIForm();
+ UIPanel panel2 = new UIPanel();
+ UIInput input3 = new UIInput();
+ UIInput input4 = new UIInput();
+
+ root.setId("root");
+ form1.setId("form1");
+ panel1.setId("panel");
+ input1.setId("input1");
+ input2.setId("input2");
+
+ form2.setId("form2");
+ panel2.setId("panel");
+ input3.setId("input1");
+ input4.setId("input2");
+
+ root.getChildren().add(form1);
+ form1.getChildren().add(panel1);
+ panel1.getChildren().add(input1);
+ panel1.getChildren().add(input2);
+
+ root.getChildren().add(form2);
+ form2.getChildren().add(panel2);
+ panel2.getChildren().add(input3);
+ panel2.getChildren().add(input4);
+ Map result = new HashMap<>();
+ result.put("root", root);
+ result.put("form1", form1);
+ result.put("panel1", panel1);
+ result.put("input1", input1);
+ result.put("input2", input2);
+ result.put("form2", form2);
+ result.put("panel2", panel2);
+ result.put("input3", input3);
+ result.put("input4", input4);
+
+ return result;
+ }
+
+ @Test
+ public void testInvokeOnComponentPositive() throws Exception {
+
+ Map tree = setupInvokeOnComponentTree();
+
+ UIViewRoot root = (UIViewRoot) tree.get("root");
+ UIInput input1 = (UIInput) tree.get("input1");
+
+ foundComponent = null;
+ boolean result = false;
+
+ assertNull(UIComponent.getCurrentComponent(facesContext));
+
+ result = root.invokeOnComponent(facesContext, input1.getClientId(facesContext), new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ assertEquals(UIComponent.getCurrentComponent(context), component);
+ foundComponent = component;
+ }
+ });
+ assertEquals(input1, foundComponent);
+ assertTrue(result);
+ assertNull(UIComponent.getCurrentComponent(facesContext));
+
+ }
+
+ @Test
+ public void testInvokeOnComponentNegative() throws Exception {
+ Map tree = setupInvokeOnComponentTree();
+
+ UIViewRoot root = (UIViewRoot) tree.get("root");
+ UIInput input4 = (UIInput) tree.get("input4");
+
+ foundComponent = null;
+ boolean result = false;
+ boolean exceptionThrown = false;
+
+ // Negative case 0, null pointers
+ exceptionThrown = false;
+ FacesContext nullContext = null;
+ ContextCallback nullCallback = null;
+ try {
+ root.invokeOnComponent(nullContext, "form:input7", nullCallback);
+ } catch (NullPointerException npe) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+
+ exceptionThrown = false;
+ try {
+ root.invokeOnComponent(facesContext, null, nullCallback);
+ } catch (NullPointerException npe) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+
+ exceptionThrown = false;
+ try {
+ root.invokeOnComponent(nullContext, null, nullCallback);
+ } catch (NullPointerException npe) {
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+
+ // Negative case 1, not found component.
+ result = root.invokeOnComponent(facesContext, "form:input7", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ }
+ });
+ assertNull(foundComponent);
+ assertTrue(!result);
+
+ // Negative case 2A, callback throws exception with found component
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+ result = root.invokeOnComponent(facesContext, "form2:input2", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ // When else am I going to get the chance to throw this exception?
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertTrue(exceptionThrown);
+ assertEquals(foundComponent, input4);
+ assertTrue(!result);
+
+ // Negative case 2B, callback throws exception with not found component
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+ result = root.invokeOnComponent(facesContext, "form2:input6", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ // When else am I going to get the chance to throw this exception?
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertTrue(!exceptionThrown);
+ assertNull(foundComponent);
+ assertTrue(!result);
+
+ }
+
+ @Test
+ public void testInvokeOnComponentWithPrependId() throws Exception {
+ Map tree = setupInvokeOnComponentTree();
+
+ UIViewRoot root = (UIViewRoot) tree.get("root");
+ UIForm truePrependIdForm = (UIForm) tree.get("form1");
+ UIForm falsePrependIdForm = (UIForm) tree.get("form2");
+ UIInput truePrependIdInput = (UIInput) tree.get("input2");
+ UIInput falsePrependIdInput = (UIInput) tree.get("input3");
+
+ truePrependIdForm.setPrependId(true);
+ falsePrependIdForm.setPrependId(false);
+
+ foundComponent = null;
+ boolean result = false;
+ boolean exceptionThrown = false;
+
+ // Case 1, positive find with prependId == true
+ result = root.invokeOnComponent(facesContext, "form1:input2", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ }
+ });
+ assertEquals(truePrependIdInput, foundComponent);
+ assertTrue(result);
+
+ // Case 2, negative find with prependId == true
+ foundComponent = null;
+ result = false;
+
+ result = root.invokeOnComponent(facesContext, "form9:input5", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ }
+ });
+ assertNull(foundComponent);
+ assertTrue(!result);
+
+ // Case 3, exception positive find with prependId == true
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+
+ result = root.invokeOnComponent(facesContext, "form1:input2", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertEquals(truePrependIdInput, foundComponent);
+ assertTrue(!result);
+ assertTrue(exceptionThrown);
+
+ // Case 4, exception negative find with prependId == true
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+
+ result = root.invokeOnComponent(facesContext, "formFozzy:inputKermit", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertNull(foundComponent);
+ assertTrue(!result);
+ assertTrue(!exceptionThrown);
+
+ // Case 5, positive find with prependId == false
+ result = root.invokeOnComponent(facesContext, "input1", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ }
+ });
+ assertEquals(falsePrependIdInput, foundComponent);
+ assertTrue(result);
+
+ // Case 6, negative find with prependId == false
+ foundComponent = null;
+ result = false;
+
+ result = root.invokeOnComponent(facesContext, "input99", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ }
+ });
+ assertNull(foundComponent);
+ assertTrue(!result);
+
+ // Case 3, exception positive find with prependId == false
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+
+ result = root.invokeOnComponent(facesContext, "input1", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertEquals(falsePrependIdInput, foundComponent);
+ assertTrue(!result);
+ assertTrue(exceptionThrown);
+
+ // Case 4, exception negative find with prependId == false
+ foundComponent = null;
+ result = false;
+ exceptionThrown = false;
+ try {
+
+ result = root.invokeOnComponent(facesContext, "inputKermit", new ContextCallback() {
+ @Override
+ public void invokeContextCallback(FacesContext context, UIComponent component) {
+ foundComponent = component;
+ throw new IllegalStateException();
+ }
+ });
+ } catch (FacesException e) {
+ assertTrue(e.getCause() instanceof IllegalStateException);
+ exceptionThrown = true;
+ }
+ assertNull(foundComponent);
+ assertTrue(!result);
+ assertTrue(!exceptionThrown);
+
+ }
+
+ @Test
+ public void testChildrenListAfterAddPublish() {
+
+ Listener listener = new Listener();
+ application.subscribeToEvent(PostAddToViewEvent.class, listener);
+
+ UIComponent c1 = createComponent();
+ c1.setInView(true);
+ UIComponent c2 = createComponent();
+ c2.setInView(true);
+ UIComponent c3 = createComponent();
+ c3.setInView(true);
+
+ c1.getChildren().add(c2);
+ SystemEvent e = listener.getEvent();
+ assertNotNull(e);
+ assertTrue(e.getSource() == c2);
+ assertTrue(((UIComponent) e.getSource()).getParent() == c1);
+ listener.reset();
+ c2.getChildren().add(c3);
+ e = listener.getEvent();
+ assertNotNull(e);
+ assertTrue(e.getSource() == c3);
+ assertTrue(((UIComponent) e.getSource()).getParent() == c2);
+
+ // ensure events are re-published if the event is added
+ listener.reset();
+ c2.getChildren().remove(c3);
+ c1.getChildren().add(c3);
+ e = listener.getEvent();
+ assertNotNull(e);
+ assertTrue(e.getSource() == c3);
+ assertTrue(((UIComponent) e.getSource()).getParent() == c1);
+
+ application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
+
+ }
+
+ @Test
+ public void testFacetMapAfterAddViewPublish() {
+
+ QueueingListener listener = new QueueingListener();
+ application.subscribeToEvent(PostAddToViewEvent.class, listener);
+
+ UIComponent c1 = createComponent();
+ UIComponent c2 = createComponent();
+ UIComponent c3 = createComponent();
+
+ List e = listener.getEvents();
+ Map facets = c1.getFacets();
+ facets.put("c2", c2);
+ assertEquals(0, e.size());
+
+ UIViewRoot root = new UIViewRoot();
+ root.getChildren().add(c1);
+ assertEquals(2, e.size());
+ assertTrue(e.get(0).getSource() == c1);
+ assertTrue(e.get(1).getSource() == c2);
+
+ // remove c1 from the root and add c3 as a facet to c1 - no events should be
+ // published
+ e.clear();
+ root.getChildren().remove(c1);
+ facets = c1.getFacets();
+ facets.put("c3", c3);
+ assertEquals(0, e.size());
+
+ // reorganize the facet structure to ensure nested facets work
+ facets.remove("c3");
+ c2.getFacets().put("c3", c3);
+ root.getChildren().add(c1);
+ assertEquals(3, e.size());
+ assertTrue(e.get(0).getSource() == c1);
+ assertTrue(e.get(1).getSource() == c2);
+ assertTrue(e.get(2).getSource() == c3);
+
+ e.clear();
+ // ensure clear() method disconnects the facets from the view
+ facets.clear();
+ c2.getFacets().remove("c3");
+ c2.getFacets().put("c3", c3);
+ assertEquals(0, e.size());
+
+ application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
+
+ }
+
+ @Test
+ public void testChildrenListAfterAddViewPublish() {
+
+ QueueingListener listener = new QueueingListener();
+ application.subscribeToEvent(PostAddToViewEvent.class, listener);
+
+ UIComponent c1 = createComponent();
+ UIComponent c2 = createComponent();
+ UIComponent c3 = createComponent();
+ UIComponent c4 = createComponent();
+ c1.getChildren().add(c2);
+ List e = listener.getEvents();
+ assertTrue(e.isEmpty());
+ c2.getChildren().add(c3);
+ assertTrue(e.isEmpty());
+ UIViewRoot root = new UIViewRoot();
+ root.getChildren().add(c1);
+
+ // sub-tree has been added to the view. Ensure that subsequent additions
+ // to that sub-tree cause the PostAddToViewEvent to fire.
+ c2.getChildren().add(c4);
+ assertEquals(4, e.size());
+
+ UIComponent[] comps = { c1, c2, c3, c4 };
+ for (int i = 0; i < comps.length; i++) {
+ assertTrue(e.get(i).getSource() == comps[i], "Index " + i + " invalid");
+ }
+
+ // remove c1 and it's children from the subview, then remove and
+ // re-add one of the children in the sub-tree. No event should
+ // be fired
+ e.clear();
+ root.getChildren().remove(c1);
+ c2.getChildren().remove(c4);
+ c2.getChildren().add(c4);
+ assertEquals(0, e.size());
+
+ c2.getChildren().remove(c4);
+ c1.getChildren().add(c4);
+ assertEquals(0, e.size());
+
+ // re-wire c1 as a child of root and ensure all children get re-notified
+ root.getChildren().add(c1);
+ assertEquals(4, e.size());
+
+ for (int i = 0; i < comps.length; i++) {
+ assertTrue(e.get(i).getSource() == comps[i], "Index " + i + " invalid");
+ }
+
+ // validate clearing c1's children (effectively removing them from the view
+ // will result in no events being fired of components are added to any of
+ // the disconnected children.
+ // At this point in the test, c2 and c4 are children of c1, and c3
+ // is a child of c2.
+ c1.getChildren().clear();
+ UIComponent temp = createComponent();
+ e.clear();
+ c2.getChildren().add(temp);
+ assertEquals(0, e.size());
+ c2.getChildren().remove(temp);
+ c3.getChildren().add(temp);
+ assertEquals(0, e.size());
+ c3.getChildren().remove(temp);
+ c4.getChildren().add(temp);
+ assertEquals(0, e.size());
+ c4.getChildren().remove(temp);
+
+ // now add c2 and c4 as children of c1. This should cause three
+ // events to fire
+ c1.getChildren().add(c2);
+ c1.getChildren().add(c4);
+ assertEquals(3, e.size());
+
+ UIComponent[] comps2 = { c2, c3, c4 };
+ for (int i = 0; i < comps2.length; i++) {
+ assertTrue(e.get(i).getSource() == comps2[i], "Index " + i + " invalid");
+ }
+
+ // validate add(int, UIComponent) fires events
+ e.clear();
+ c1.getChildren().remove(c4);
+ c1.getChildren().add(0, c4);
+
+ assertTrue(c1.getChildren().get(0) == c4);
+ assertTrue(c1.getChildren().get(1) == c2);
+ assertEquals(1, e.size());
+ assertTrue(e.get(0).getSource() == c4);
+
+ // validate addAll(Collection) fires events
+ e.clear();
+ c1.getChildren().clear();
+ List children = new ArrayList<>(2);
+ Collections.addAll(children, c2, c4);
+ c1.getChildren().addAll(children);
+ assertTrue(c1.getChildren().get(0) == c2);
+ assertTrue(c1.getChildren().get(1) == c4);
+ assertEquals(3, e.size());
+ assertTrue(e.get(0).getSource() == c2);
+ assertTrue(e.get(2).getSource() == c4);
+
+ // validate addAll(int, Collection) fires events
+ e.clear();
+ children = new ArrayList<>(2);
+ UIComponent t1 = createComponent();
+ UIComponent t2 = createComponent();
+ Collections.addAll(children, t1, t2);
+ c1.getChildren().addAll(0, children);
+ assertTrue(c1.getChildren().get(0) == t1);
+ assertTrue(c1.getChildren().get(1) == t2);
+ assertTrue(c1.getChildren().get(2) == c2);
+ assertTrue(c1.getChildren().get(3) == c4);
+ assertEquals(2, e.size());
+ assertTrue(e.get(0).getSource() == t1);
+ assertTrue(e.get(1).getSource() == t2);
+
+ // validate retainAll(Collection properly disconnects
+ // the components from the view such that events aren't fired
+ // if children are added to them
+ e.clear();
+ List retained = new ArrayList<>(2);
+ Collections.addAll(retained, c2, c4);
+ c1.getChildren().retainAll(retained);
+ assertTrue(c1.getChildren().size() == 2);
+ assertTrue(c1.getChildren().get(0) == c2);
+ assertTrue(c1.getChildren().get(1) == c4);
+ t1.getChildren().add(t2);
+ assertEquals(0, e.size());
+
+ // test set(int, UIComponent) properly fires an event if the parent
+ // the component is being added to is wired to the view
+ e.clear();
+ c1.getChildren().set(0, t1);
+ assertTrue(c1.getChildren().size() == 2);
+ assertTrue(c1.getChildren().get(0) == t1);
+ assertTrue(c1.getChildren().get(1) == c4);
+ assertEquals(2, e.size());
+ assertTrue(e.get(0).getSource() == t1);
+ assertTrue(e.get(1).getSource() == t2);
+
+ // c2 was removed by the set operation, so ensure it's marked as
+ // having been removed from the view by ensuring events aren't fired.
+ e.clear();
+ UIComponent t3 = createComponent();
+ c2.getChildren().add(t3);
+ assertEquals(0, e.size());
+
+ application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
+
+ // validate Iterator.remove() over c1's children correctly disconnects
+ // the children from the view
+ for (Iterator i = c1.getChildren().iterator(); i.hasNext();) {
+ i.next();
+ i.remove();
+ }
+
+ // at this point, t1 and c4 should be disconnected meaning adding children
+ // to t1, t2, or c4 should result in no events being fired
+ e.clear();
+ t1.getChildren().add(temp);
+ assertEquals(0, e.size());
+ t1.getChildren().remove(temp);
+ t2.getChildren().add(temp);
+ assertEquals(0, e.size());
+ t2.getChildren().remove(temp);
+ c4.getChildren().add(temp);
+ assertEquals(0, e.size());
+ c4.getChildren().remove(temp);
+
+ }
+
+ @Test
+ public void testEncodeBeginPublish() throws Exception {
+
+ Listener listener = new Listener();
+ application.subscribeToEvent(PreRenderComponentEvent.class, listener);
+
+ UIComponent c1 = createComponent();
+ c1.encodeBegin(facesContext);
+ SystemEvent e = listener.getEvent();
+ assertNotNull(e);
+ assertTrue(e.getSource() == c1);
+ listener.reset();
+ c1.encodeChildren(facesContext);
+ assertNull(listener.getEvent());
+ c1.encodeEnd(facesContext);
+ assertNull(listener.getEvent());
+
+ application.unsubscribeFromEvent(PreRenderComponentEvent.class, listener);
+
+ }
+
+ // --------------------------------------------------------- Private Classes
+ public static final class Listener implements SystemEventListener {
+
+ private SystemEvent event;
+
+ @Override
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+ this.event = event;
+ }
+
+ @Override
+ public boolean isListenerForSource(Object source) {
+ return source instanceof UIComponent;
+ }
+
+ public SystemEvent getEvent() {
+ return event;
+ }
+
+ public void reset() {
+ event = null;
+ }
+ }
+
+ public static final class QueueingListener implements SystemEventListener {
+
+ private List events = new ArrayList<>();
+
+ @Override
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+ events.add(event);
+ }
+
+ @Override
+ public boolean isListenerForSource(Object source) {
+ return source instanceof UIComponent;
+ }
+
+ public List getEvents() {
+ return events;
+ }
+
+ public void reset() {
+ events.clear();
+ }
+ }
+
+ public static final class ComponentListener implements ComponentSystemEventListener {
+
+ @Override
+ public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
+
+ }
+ }
+
+ public static final class UIComponentListener extends UIComponentBase implements ComponentSystemEventListener {
+
+ @Override
+ public String getFamily() {
+ return "family";
+ }
+
+ @Override
+ public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
+ }
+
+ }
+
+ public static final class UIComponentOverrideEncodeBegin extends UIComponentBase {
+
+ @Override
+ public String getFamily() {
+ return "UIComponentOverrideEncodeBegin";
+ }
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException {
+ // no-op
+ }
+
+ }
+
+ public static final class UIComponentOverrideEncodeEnd extends UIComponentBase {
+
+ @Override
+ public String getFamily() {
+ return "UIComponentOverrideEncodeEnd";
+ }
+
+ @Override
+ public void encodeEnd(FacesContext context) throws IOException {
+ // no-op
+ }
+ }
+
+ public static final class CustomAbortProcessingException extends AbortProcessingException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public CustomAbortProcessingException() {
+ }
+
+ public CustomAbortProcessingException(String message) {
+ super(message);
+ }
+
+ public CustomAbortProcessingException(Throwable cause) {
+ super(cause);
+ }
+
+ public CustomAbortProcessingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIComponentTestCase.java b/impl/src/test/java/jakarta/faces/component/UIComponentTestCase.java
new file mode 100644
index 0000000000..0e3eb7f9f9
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIComponentTestCase.java
@@ -0,0 +1,1883 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.junit.JUnitFacesTestCaseBase;
+import com.sun.faces.mock.MockRenderKit;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.AbortProcessingException;
+import jakarta.faces.event.ComponentSystemEvent;
+import jakarta.faces.event.ComponentSystemEventListener;
+import jakarta.faces.event.PostValidateEvent;
+import jakarta.faces.event.PreValidateEvent;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+import jakarta.faces.validator.Validator;
+import jakarta.faces.validator.ValidatorException;
+
+/**
+ *
+ * Base unit tests for all {@link UIComponent} implementation classes.
+ *
+ */
+public class UIComponentTestCase extends JUnitFacesTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // The component to be tested
+ protected UIComponent component = null;
+
+ // The set of attribute names expected on a pristine component instance
+ protected String expectedAttributes[] = null;
+
+ // The expected component family on a pristine component instance
+ protected String expectedFamily = null;
+
+ // The expected component identifier on a pristine component instance
+ protected String expectedId = null;
+
+ // The expected rendered on a pristine component instance
+ protected boolean expectedRendered = true;
+
+ // The expected rendererType on a pristine component instance
+ protected String expectedRendererType = null;
+
+ // The expected rendersChildren on a pristine component instance
+ protected boolean expectedRendersChildren = false;
+
+ private Map.Entry bogusEntry = new Map.Entry<>() {
+ @Override
+ public boolean equals(Object r) {
+ return false;
+ }
+
+ @Override
+ public String getKey() {
+ return "key";
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public UIComponent getValue() {
+ return null;
+ }
+
+ @Override
+ public UIComponent setValue(UIComponent value) {
+ return null;
+ }
+
+ };
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+
+ expectedAttributes = new String[0];
+ expectedFamily = "Test";
+ expectedId = "test";
+ expectedRendered = true;
+ expectedRendererType = null;
+ expectedRendersChildren = false;
+
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.setViewId("/viewId");
+ facesContext.setViewRoot(root);
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = new MockRenderKit();
+ try {
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+ } catch (IllegalArgumentException e) {
+ }
+
+ component = new ComponentTestImpl(expectedId);
+ }
+
+ // Tear down instance variables required by this test case.
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+
+ component = null;
+ expectedAttributes = null;
+ expectedFamily = null;
+ expectedId = null;
+ expectedRendered = true;
+ expectedRendererType = null;
+ expectedRendersChildren = false;
+ super.tearDown();
+
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testValidationEvents() {
+ Listener prelistener = new Listener();
+ Listener postlistener = new Listener();
+ List ldata = new ArrayList<>();
+ ldata.add("one");
+ UIViewRoot root = new UIViewRoot();
+ root.setId("root");
+ root.subscribeToEvent(PreValidateEvent.class, prelistener);
+ root.subscribeToEvent(PostValidateEvent.class, postlistener);
+ UIOutput out = new UIOutput();
+ out.setId("out");
+ out.subscribeToEvent(PreValidateEvent.class, prelistener);
+ out.subscribeToEvent(PostValidateEvent.class, postlistener);
+ root.getChildren().add(out);
+ UIForm f = new UIForm();
+ f.setSubmitted(true);
+ f.setId("form");
+ f.subscribeToEvent(PreValidateEvent.class, prelistener);
+ f.subscribeToEvent(PostValidateEvent.class, postlistener);
+ root.getChildren().add(f);
+ UIData data = new UIData();
+ data.setId("data");
+ data.subscribeToEvent(PreValidateEvent.class, prelistener);
+ data.subscribeToEvent(PostValidateEvent.class, postlistener);
+ data.setValue(ldata);
+ UIColumn c = new UIColumn();
+ c.setId("column");
+ c.subscribeToEvent(PreValidateEvent.class, prelistener);
+ c.subscribeToEvent(PostValidateEvent.class, postlistener);
+ UIInput in = new UIInput();
+ in.setId("in");
+ in.subscribeToEvent(PreValidateEvent.class, prelistener);
+ in.subscribeToEvent(PostValidateEvent.class, postlistener);
+ in.addValidator(new ValidationSignal());
+ c.getChildren().add(in);
+ data.getChildren().add(c);
+ f.getChildren().add(data);
+ data.setRowIndex(0);
+ UIComponent col = data.getChildren().get(0);
+ ((UIInput) col.getChildren().get(0)).setSubmittedValue("hello");
+ data.setRowIndex(-1);
+ root.processValidators(facesContext);
+ assertEquals("root/out/form/data/in/", prelistener.getResults());
+ assertEquals("out/*/in/data/form/root/", postlistener.getResults());
+
+ }
+
+ // Test behavior of Map returned by getAttributes()
+ @Test
+ public void testAttributesMap() {
+
+ // Initialize some attributes
+ Map attributes = component.getAttributes();
+ attributes.put("foo", "bar");
+ attributes.put("baz", "bop");
+
+ // Test containsKey()
+ assertTrue(attributes.containsKey("foo"));
+ assertTrue(attributes.containsKey("baz"));
+ assertTrue(!attributes.containsKey("bar"));
+ assertTrue(!attributes.containsKey("bop"));
+ assertTrue(!attributes.containsKey("id")); // Property name
+ assertTrue(!attributes.containsKey("parent")); // Property name
+
+ // Test get()
+ assertEquals("bar", attributes.get("foo"));
+ assertEquals("bop", attributes.get("baz"));
+ assertNull(attributes.get("bar"));
+ assertNull(attributes.get("bop"));
+ component.setId("oldvalue");
+ assertEquals("oldvalue", attributes.get("id")); // Property
+ component.setRendered(false);
+ assertTrue(!((Boolean) attributes.get("rendered")).booleanValue());
+ component.setRendered(true);
+ assertTrue(((Boolean) attributes.get("rendered")).booleanValue());
+
+ // Test put()
+ try {
+ attributes.put(null, "dummy");
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ try {
+ attributes.put("rendersChildren", null); // Primitive property
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+ try {
+ attributes.put("rendersChildren", Boolean.TRUE); // Write-only
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+ attributes.put("id", "newvalue");
+ assertEquals("newvalue", attributes.get("id"));
+ assertEquals("newvalue", component.getId());
+ attributes.put("rendered", Boolean.TRUE);
+ assertTrue(component.isRendered());
+ attributes.put("rendered", Boolean.FALSE);
+ assertTrue(!component.isRendered());
+
+ // Test remove()
+ attributes.remove("baz");
+ assertTrue(!attributes.containsKey("baz"));
+ assertNull(attributes.get("baz"));
+ try {
+ attributes.remove("id");
+ fail("Should have thrown IllegalArgumentException()");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ }
+
+ // Negative tests on attribute methods
+ @Test
+ public void testAttributesNegative() {
+
+ // getAttributes().get() - null
+ try {
+ component.getAttributes().get(null);
+ fail("should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+
+ // getAttributes().put() - null
+ try {
+ component.getAttributes().put(null, "bar");
+ fail("should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+
+ }
+
+ // Positive tests on attribute methods
+ @Test
+ public void testAttributesPositive() {
+
+ checkAttributeCount(component, expectedAttributes.length);
+ checkAttributeMissing(component, "foo");
+ checkAttributeMissing(component, "baz");
+
+ component.getAttributes().put("foo", "bar");
+ checkAttributeCount(component, expectedAttributes.length + 1);
+ checkAttributePresent(component, "foo", "bar");
+ checkAttributeMissing(component, "baz");
+
+ component.getAttributes().put("baz", "bop");
+ checkAttributeCount(component, expectedAttributes.length + 2);
+ checkAttributePresent(component, "foo", "bar");
+ checkAttributePresent(component, "baz", "bop");
+
+ component.getAttributes().put("baz", "boo");
+ checkAttributeCount(component, expectedAttributes.length + 2);
+ checkAttributePresent(component, "foo", "bar");
+ checkAttributePresent(component, "baz", "boo");
+
+ component.getAttributes().remove("foo");
+ checkAttributeCount(component, expectedAttributes.length + 1);
+ checkAttributeMissing(component, "foo");
+ checkAttributePresent(component, "baz", "boo");
+
+ }
+
+ // Test attribute-property transparency
+ @Test
+ public void testAttributesTransparency() {
+
+ assertEquals(component.getChildren(), component.getAttributes().get("children"));
+
+ assertEquals(component.getFacets(), component.getAttributes().get("facets"));
+
+ assertEquals(component.getId(), component.getAttributes().get("id"));
+
+ assertEquals(component.getParent(), component.getAttributes().get("parent"));
+
+ assertEquals(component.isRendered(), ((Boolean) component.getAttributes().get("rendered")).booleanValue());
+ component.setRendered(false);
+ assertEquals(Boolean.FALSE, component.getAttributes().get("rendered"));
+ component.setRendered(true);
+ assertEquals(Boolean.TRUE, component.getAttributes().get("rendered"));
+ component.getAttributes().put("rendered", Boolean.FALSE);
+ assertTrue(!component.isRendered());
+ component.getAttributes().put("rendered", Boolean.TRUE);
+ assertTrue(component.isRendered());
+
+ component.setRendererType("foo");
+ assertEquals("foo", component.getAttributes().get("rendererType"));
+ component.setRendererType(null);
+ assertNull(component.getAttributes().get("rendererType"));
+ component.getAttributes().put("rendererType", "bar");
+ assertEquals("bar", component.getRendererType());
+ component.getAttributes().put("rendererType", null);
+ assertNull(component.getRendererType());
+
+ assertEquals(component.getRendersChildren(), ((Boolean) component.getAttributes().get("rendersChildren")).booleanValue());
+
+ }
+
+ // Test getChildren().iterator()
+ @Test
+ public void testChildrenIterator() {
+
+ Iterator kids;
+
+ // Construct components we will need
+ UIComponent comp0 = new ComponentTestImpl(null);
+ UIComponent comp1 = new ComponentTestImpl("comp1");
+ UIComponent comp2 = new ComponentTestImpl("comp2");
+ UIComponent comp3 = new ComponentTestImpl("comp3");
+ UIComponent comp4 = new ComponentTestImpl("comp4");
+ UIComponent comp5 = new ComponentTestImpl("comp5");
+ List comps = new ArrayList<>();
+ comps.add(comp0);
+ comps.add(comp1);
+ comps.add(comp2);
+ comps.add(comp3);
+ comps.add(comp4);
+ comps.add(comp5);
+
+ // Test hasNext() and next()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().iterator();
+ assertTrue(kids.hasNext());
+ assertEquals(comp0, kids.next());
+ assertEquals(comp1, kids.next());
+ assertEquals(comp2, kids.next());
+ assertEquals(comp3, kids.next());
+ assertEquals(comp4, kids.next());
+ assertEquals(comp5, kids.next());
+ assertTrue(!kids.hasNext());
+
+ // Test remove()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().iterator();
+ while (kids.hasNext()) {
+ UIComponent kid = kids.next();
+ if (kid == comp2 || kid == comp4) {
+ kids.remove();
+ }
+ }
+ kids = component.getChildren().iterator();
+ assertTrue(kids.hasNext());
+ assertEquals(comp0, kids.next());
+ assertEquals(comp1, kids.next());
+ assertEquals(comp3, kids.next());
+ assertEquals(comp5, kids.next());
+ assertTrue(!kids.hasNext());
+
+ }
+
+ // Test getChildren().listIterator()
+ @Test
+ public void testChildrenListIterator() {
+
+ ListIterator kids;
+
+ // Construct components we will need
+ UIComponent comp0 = new ComponentTestImpl(null);
+ UIComponent comp1 = new ComponentTestImpl("comp1");
+ UIComponent comp2 = new ComponentTestImpl("comp2");
+ UIComponent comp3 = new ComponentTestImpl("comp3");
+ UIComponent comp4 = new ComponentTestImpl("comp4");
+ UIComponent comp5 = new ComponentTestImpl("comp5");
+ UIComponent comp6 = new ComponentTestImpl("comp6");
+ List comps = new ArrayList<>();
+ comps.add(comp0);
+ comps.add(comp1);
+ comps.add(comp2);
+ comps.add(comp3);
+ comps.add(comp4);
+ comps.add(comp5);
+
+ // Test hasNext(), next(), and nextIndex()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().listIterator();
+ assertTrue(kids.hasNext());
+ assertEquals(0, kids.nextIndex());
+ assertEquals(comp0, kids.next());
+ assertEquals(1, kids.nextIndex());
+ assertEquals(comp1, kids.next());
+ assertEquals(2, kids.nextIndex());
+ assertEquals(comp2, kids.next());
+ assertEquals(3, kids.nextIndex());
+ assertEquals(comp3, kids.next());
+ assertEquals(4, kids.nextIndex());
+ assertEquals(comp4, kids.next());
+ assertEquals(5, kids.nextIndex());
+ assertEquals(comp5, kids.next());
+ assertEquals(6, kids.nextIndex());
+ assertTrue(!kids.hasNext());
+
+ // Test hasPrevious(), previous(), and previousIndex()
+ assertTrue(kids.hasPrevious());
+ assertEquals(5, kids.previousIndex());
+ assertEquals(comp5, kids.previous());
+ assertEquals(4, kids.previousIndex());
+ assertEquals(comp4, kids.previous());
+ assertEquals(3, kids.previousIndex());
+ assertEquals(comp3, kids.previous());
+ assertEquals(2, kids.previousIndex());
+ assertEquals(comp2, kids.previous());
+ assertEquals(1, kids.previousIndex());
+ assertEquals(comp1, kids.previous());
+ assertEquals(0, kids.previousIndex());
+ assertEquals(comp0, kids.previous());
+ assertEquals(-1, kids.previousIndex());
+ assertTrue(!kids.hasPrevious());
+
+ // Test remove()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().listIterator();
+ while (kids.hasNext()) {
+ UIComponent kid = kids.next();
+ if (kid == comp2 || kid == comp4) {
+ kids.remove();
+ }
+ }
+ kids = component.getChildren().listIterator();
+ assertTrue(kids.hasNext());
+ assertEquals(comp0, kids.next());
+ assertEquals(comp1, kids.next());
+ assertEquals(comp3, kids.next());
+ assertEquals(comp5, kids.next());
+ assertTrue(!kids.hasNext());
+
+ // Test set()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().listIterator();
+ while (kids.hasNext()) {
+ UIComponent kid = kids.next();
+ if (kid == comp2) {
+ kids.set(comp6);
+ }
+ }
+ kids = component.getChildren().listIterator();
+ assertTrue(kids.hasNext());
+ assertEquals(0, kids.nextIndex());
+ assertEquals(comp0, kids.next());
+ assertEquals(1, kids.nextIndex());
+ assertEquals(comp1, kids.next());
+ assertEquals(2, kids.nextIndex());
+ assertEquals(comp6, kids.next());
+ assertEquals(3, kids.nextIndex());
+ assertEquals(comp3, kids.next());
+ assertEquals(4, kids.nextIndex());
+ assertEquals(comp4, kids.next());
+ assertEquals(5, kids.nextIndex());
+ assertEquals(comp5, kids.next());
+ assertEquals(6, kids.nextIndex());
+ assertTrue(!kids.hasNext());
+
+ // Test add()
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().listIterator();
+ while (kids.hasNext()) {
+ UIComponent kid = kids.next();
+ if (kid == comp2) {
+ kids.add(comp6);
+ }
+ }
+ kids = component.getChildren().listIterator();
+ assertTrue(kids.hasNext());
+ assertEquals(0, kids.nextIndex());
+ assertEquals(comp0, kids.next());
+ assertEquals(1, kids.nextIndex());
+ assertEquals(comp1, kids.next());
+ assertEquals(2, kids.nextIndex());
+ assertEquals(comp2, kids.next());
+ assertEquals(3, kids.nextIndex());
+ assertEquals(comp6, kids.next());
+ assertEquals(4, kids.nextIndex());
+ assertEquals(comp3, kids.next());
+ assertEquals(5, kids.nextIndex());
+ assertEquals(comp4, kids.next());
+ assertEquals(6, kids.nextIndex());
+ assertEquals(comp5, kids.next());
+ assertEquals(7, kids.nextIndex());
+ assertTrue(!kids.hasNext());
+
+ // Test listIterator(int)
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ kids = component.getChildren().listIterator(2);
+ assertTrue(kids.hasNext());
+ assertTrue(kids.hasPrevious());
+ assertEquals(2, kids.nextIndex());
+ assertEquals(1, kids.previousIndex());
+ assertEquals(comp2, kids.next());
+ assertEquals(comp3, kids.next());
+ assertEquals(comp4, kids.next());
+ assertEquals(comp4, kids.previous());
+ assertEquals(comp3, kids.previous());
+ assertEquals(comp2, kids.previous());
+ assertEquals(comp1, kids.previous());
+
+ // Test IOB exception for list iterator
+ component.getChildren().clear();
+ component.getChildren().addAll(comps);
+ try {
+ component.getChildren().listIterator(-1);
+ fail("Should throw IndexOutOfBoundsException on index -1");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+
+ try {
+ component.getChildren().listIterator(component.getChildren().size() + 1);
+ fail("Should throw IndexOutOfBoundsException on index = size() + 1");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+
+ // Iterate with list iterator in reverse order
+ int i = component.getChildren().size() - 1;
+ for (ListIterator li = component.getChildren().listIterator(component.getChildren().size()); li.hasPrevious();) {
+
+ assertEquals(comps.get(i--), li.previous());
+ }
+
+ }
+
+ // Negative tests on children methods
+ @Test
+ public void testChidrenNegative() {
+
+ // Construct components we will need
+ UIComponent comp0 = new ComponentTestImpl(null);
+ UIComponent comp1 = new ComponentTestImpl("comp1");
+ UIComponent comp2 = new ComponentTestImpl("comp2");
+ UIComponent comp3 = new ComponentTestImpl("comp3");
+
+ // Set up and verify initial state
+ List children = component.getChildren();
+ children.add(comp0);
+ children.add(comp1);
+ children.add(comp2);
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // add(Object) - NullPointerException
+ try {
+ children.add(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // add(int,Object) - IndexOutOfBoundsException low
+ try {
+ children.add(-1, comp3);
+ fail("Should have thrown IndexOutOfBoundsException low");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // add(int,Object) - IndexOutOfBoundsException high
+ try {
+ children.add(4, comp3);
+ fail("Should have thrown IndexOutOfBoundsException high");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // add(int,Object) - NullPointerException
+ try {
+ children.add(1, null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // set(int,Object) - IndexOutOfBoundsException low
+ try {
+ children.set(-1, comp3);
+ fail("Should have thrown IndexOutOfBoundsException low");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // set(int,Object) - IndexOutOfBoundsException high
+ try {
+ children.set(4, comp3);
+ fail("Should have thrown IndexOutOfBoundsException high");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ // set(int,Object) - NullPointerException
+ try {
+ children.set(1, null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildMissing(component, comp3);
+
+ }
+
+ // Positive tests on children methods
+ @Test
+ public void testChildrenPositive() {
+
+ // Construct components we will need
+ UIComponent comp0 = new ComponentTestImpl(null);
+ UIComponent comp1 = new ComponentTestImpl("comp1");
+ UIComponent comp2 = new ComponentTestImpl("comp2");
+ UIComponent comp3 = new ComponentTestImpl("comp3");
+ UIComponent comp4 = new ComponentTestImpl("comp4");
+ UIComponent comp5 = new ComponentTestImpl("comp5");
+ UIComponent comp6 = new ComponentTestImpl("comp6");
+
+ // Verify initial state
+ List children = component.getChildren();
+ checkChildMissing(component, comp0);
+ checkChildCount(component, 0);
+ checkChildMissing(component, comp1);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildMissing(component, comp4);
+ checkChildMissing(component, comp5);
+ checkChildMissing(component, comp6);
+
+ // add(Object)
+ children.add(comp1);
+ checkChildCount(component, 1);
+ checkChildMissing(component, comp0);
+ checkChildPresent(component, comp1, 0);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildMissing(component, comp4);
+ checkChildMissing(component, comp5);
+ checkChildMissing(component, comp6);
+
+ // add(int, Object)
+ children.add(0, comp0);
+ checkChildCount(component, 2);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildMissing(component, comp4);
+ checkChildMissing(component, comp5);
+ checkChildMissing(component, comp6);
+
+ // addAll(Collection)
+ ArrayList list1 = new ArrayList<>();
+ list1.add(comp4);
+ list1.add(comp5);
+ children.addAll(list1);
+ checkChildCount(component, 4);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildPresent(component, comp4, 2);
+ checkChildPresent(component, comp5, 3);
+ checkChildMissing(component, comp6);
+
+ // addAll(int, Collection)
+ ArrayList list2 = new ArrayList<>();
+ list2.add(comp2);
+ list2.add(comp3);
+ children.addAll(2, list2);
+ checkChildCount(component, 6);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildPresent(component, comp3, 3);
+ checkChildPresent(component, comp4, 4);
+ checkChildPresent(component, comp5, 5);
+ checkChildMissing(component, comp6);
+
+ // contains(Object) is tested in checkChildPresent / checkChildMissing
+ // containsAll(Collection)
+ assertTrue(children.containsAll(list1));
+ assertTrue(children.containsAll(list2));
+
+ // get(int) is tested in checkChildPresent / checkChildMissing
+ // indexOf(Object) is tested in checkChildPresent / checkChildMissing
+ // isEmpty() is tested in checkChildCount
+ // iterator() is tested in testChildrenIterator
+ // listIterator() is tested in testChildrenListIterator
+ // toArray(Object[])
+ UIComponent kids[] = children.toArray(new UIComponent[0]);
+ assertEquals(comp0, kids[0]);
+ assertEquals(comp1, kids[1]);
+ assertEquals(comp2, kids[2]);
+ assertEquals(comp3, kids[3]);
+ assertEquals(comp4, kids[4]);
+ assertEquals(comp5, kids[5]);
+
+ // subList(int,int)
+ List subList = children.subList(3, 5);
+ assertEquals(2, subList.size());
+ assertEquals(comp3, subList.get(0));
+ assertEquals(comp4, subList.get(1));
+
+ // set(int,Object)
+ children.set(4, comp6);
+ checkChildCount(component, 6);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildPresent(component, comp3, 3);
+ checkChildMissing(component, comp4);
+ checkChildPresent(component, comp5, 5);
+ checkChildPresent(component, comp6, 4);
+ assertTrue(!children.containsAll(list1));
+ assertTrue(children.containsAll(list2));
+
+ // remove(int)
+ children.remove(4);
+ checkChildCount(component, 5);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildPresent(component, comp2, 2);
+ checkChildPresent(component, comp3, 3);
+ checkChildMissing(component, comp4);
+ checkChildPresent(component, comp5, 4);
+ checkChildMissing(component, comp6);
+ assertTrue(!children.containsAll(list1));
+ assertTrue(children.containsAll(list2));
+
+ // removeAll(Collection)
+ children.removeAll(list2);
+ checkChildCount(component, 3);
+ checkChildPresent(component, comp0, 0);
+ checkChildPresent(component, comp1, 1);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildMissing(component, comp4);
+ checkChildPresent(component, comp5, 2);
+ checkChildMissing(component, comp6);
+ assertTrue(!children.containsAll(list1));
+ assertTrue(!children.containsAll(list2));
+
+ // retainAll()
+ ArrayList list3 = new ArrayList<>();
+ list3.add(comp1);
+ list3.add(comp3);
+ list3.add(comp5);
+ children.retainAll(list3);
+ checkChildCount(component, 2);
+ checkChildMissing(component, comp0);
+ checkChildPresent(component, comp1, 0);
+ checkChildMissing(component, comp2);
+ checkChildMissing(component, comp3);
+ checkChildMissing(component, comp4);
+ checkChildPresent(component, comp5, 1);
+ checkChildMissing(component, comp6);
+ assertTrue(!children.containsAll(list3));
+
+ // size() is tested in checkChildCount
+ // clear()
+ children.clear();
+ checkChildCount(component, 0);
+ assertNull(comp0.getParent());
+ assertNull(comp1.getParent());
+ assertNull(comp2.getParent());
+ assertNull(comp3.getParent());
+ assertNull(comp4.getParent());
+ assertNull(comp5.getParent());
+ assertNull(comp6.getParent());
+
+ }
+
+ // Test replacing a child with a new one that has the same id
+ @Test
+ public void testChidrenReplace() {
+
+ ComponentTestImpl child1 = new ComponentTestImpl("child");
+ ComponentTestImpl child2 = new ComponentTestImpl("child");
+
+ checkChildCount(component, 0);
+ component.getChildren().add(child1);
+ checkChildCount(component, 1);
+ checkChildPresent(component, child1, 0);
+ checkChildMissing(component, child2);
+ component.getChildren().set(0, child2);
+ checkChildCount(component, 1);
+ checkChildMissing(component, child1);
+ checkChildPresent(component, child2, 0);
+ component.getChildren().clear();
+ checkChildCount(component, 0);
+
+ }
+
+ // Test Set returned by getFacets().entrySet()
+ @Test
+ public void testFacetsMapEntrySet() {
+
+ Map facets;
+ Set> matches;
+ Set> entrySet;
+ Iterator> entries;
+
+ // Construct the pre-load set of facets we will need
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+ UIComponent facet4 = new ComponentTestImpl("facet4");
+ UIComponent facet5 = new ComponentTestImpl("facet5");
+ UIComponent facet6 = new ComponentTestImpl("facet6"); // Not normally added
+ Map preload = new HashMap<>();
+ preload.put("a", facet1);
+ preload.put("b", facet2);
+ preload.put("c", facet3);
+ preload.put("d", facet4);
+ preload.put("e", facet5);
+
+ // Test add()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ try {
+ entrySet.add(bogusEntry);
+ fail("Should have thrown UnsupportedOperationExcepton");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // Test clear()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ assertEquals(5, facets.size());
+ assertEquals(5, entrySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+ entrySet.clear();
+ assertEquals(0, facets.size());
+ assertEquals(0, entrySet.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ // Test contains()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ assertTrue(entrySet.contains(new TestMapEntry("a", facet1)));
+ assertTrue(entrySet.contains(new TestMapEntry("b", facet2)));
+ assertTrue(entrySet.contains(new TestMapEntry("c", facet3)));
+ assertTrue(entrySet.contains(new TestMapEntry("d", facet4)));
+ assertTrue(entrySet.contains(new TestMapEntry("e", facet5)));
+ assertTrue(!entrySet.contains(new TestMapEntry("f", facet6)));
+
+ // Test containsAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ matches = new HashSet<>();
+ matches.add(new TestMapEntry("a", facet1));
+ matches.add(new TestMapEntry("c", facet3));
+ matches.add(new TestMapEntry("d", facet4));
+ assertTrue(entrySet.containsAll(matches));
+ matches = new HashSet<>();
+ matches.add(new TestMapEntry("a", facet1));
+ matches.add(new TestMapEntry("c", facet3));
+ matches.add(new TestMapEntry("f", facet6));
+ assertTrue(!entrySet.containsAll(matches));
+
+ // Test iterator().hasNext() and iterator().next()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ matches = new HashSet<>();
+ entries = entrySet.iterator();
+ while (entries.hasNext()) {
+ matches.add(entries.next());
+ }
+ assertTrue(entrySet.equals(matches));
+
+ // Test iterator().remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ entries = entrySet.iterator();
+ while (entries.hasNext()) {
+ var entry = entries.next();
+ if ("b".equals(entry.getKey()) || "d".equals(entry.getKey())) {
+ entries.remove();
+ }
+ }
+ assertEquals(3, facets.size());
+ assertEquals(3, entrySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test iterator() based modify-value
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ entries = entrySet.iterator();
+ while (entries.hasNext()) {
+ var entry = entries.next();
+ if ("c".equals(entry.getKey())) {
+ entry.setValue(facet6);
+ }
+ }
+ assertEquals(5, facets.size());
+ assertEquals(5, entrySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetPresent(component, "c", facet6);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ entrySet.remove(new TestMapEntry("c", facet3));
+ assertEquals(4, facets.size());
+ assertEquals(4, entrySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test removeAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ matches = new HashSet<>();
+ matches.add(new TestMapEntry("b", facet2));
+ matches.add(new TestMapEntry("d", facet4));
+ entrySet.removeAll(matches);
+ assertEquals(3, facets.size());
+ assertEquals(3, entrySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test retainAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ entrySet = facets.entrySet();
+ matches = new HashSet<>();
+ matches.add(new TestMapEntry("b", facet2));
+ matches.add(new TestMapEntry("d", facet4));
+ matches.add(new TestMapEntry("f", facet6));
+ entrySet.retainAll(matches);
+ assertEquals(2, facets.size());
+ assertEquals(2, entrySet.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ }
+
+ // Test Set returned by getFacets().keySet()
+ @Test
+ public void testFacetsMapKeySet() {
+
+ Map facets;
+ Set matches;
+ Set keySet;
+ Iterator keys;
+
+ // Construct the pre-load set of facets we will need
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+ UIComponent facet4 = new ComponentTestImpl("facet4");
+ UIComponent facet5 = new ComponentTestImpl("facet5");
+ Map preload = new HashMap<>();
+ preload.put("a", facet1);
+ preload.put("b", facet2);
+ preload.put("c", facet3);
+ preload.put("d", facet4);
+ preload.put("e", facet5);
+
+ // Test clear()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ assertEquals(5, facets.size());
+ assertEquals(5, keySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+ keySet.clear();
+ assertEquals(0, facets.size());
+ assertEquals(0, keySet.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ // Test contains()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ assertTrue(keySet.contains("a"));
+ assertTrue(keySet.contains("b"));
+ assertTrue(keySet.contains("c"));
+ assertTrue(keySet.contains("d"));
+ assertTrue(keySet.contains("e"));
+ assertTrue(!keySet.contains("f"));
+
+ // Test containsAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ matches = new HashSet<>();
+ matches.add("a");
+ matches.add("c");
+ matches.add("d");
+ assertTrue(keySet.containsAll(matches));
+ matches = new HashSet<>();
+ matches.add("a");
+ matches.add("c");
+ matches.add("f");
+ assertTrue(!keySet.containsAll(matches));
+
+ // Test iterator().hasNext() and iterator().next()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ matches = new HashSet<>();
+ keys = keySet.iterator();
+ while (keys.hasNext()) {
+ matches.add(keys.next());
+ }
+ assertTrue(keySet.equals(matches));
+
+ // Test iterator().remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ keys = keySet.iterator();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ if ("b".equals(key) || "d".equals(key)) {
+ keys.remove();
+ }
+ }
+ assertEquals(3, facets.size());
+ assertEquals(3, keySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ keySet.remove("c");
+ assertEquals(4, facets.size());
+ assertEquals(4, keySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test removeAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ matches = new HashSet<>();
+ matches.add("b");
+ matches.add("d");
+ keySet.removeAll(matches);
+ assertEquals(3, facets.size());
+ assertEquals(3, keySet.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test retainAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ keySet = facets.keySet();
+ matches = new HashSet<>();
+ matches.add("b");
+ matches.add("d");
+ matches.add("f");
+ keySet.retainAll(matches);
+ assertEquals(2, facets.size());
+ assertEquals(2, keySet.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ }
+
+ // Test Collection returned by getFacets().values()
+ @Test
+ public void testFacetsMapValues() {
+
+ Map facets;
+ Collection matches;
+ Collection values;
+ Iterator vals;
+
+ // Construct the pre-load set of facets we will need
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+ UIComponent facet4 = new ComponentTestImpl("facet4");
+ UIComponent facet5 = new ComponentTestImpl("facet5");
+ UIComponent facet6 = new ComponentTestImpl("facet6"); // Not normally added
+ Map preload = new HashMap<>();
+ preload.put("a", facet1);
+ preload.put("b", facet2);
+ preload.put("c", facet3);
+ preload.put("d", facet4);
+ preload.put("e", facet5);
+
+ // Test add()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ try {
+ values.add(new ComponentTestImpl("facet0"));
+ fail("Should have thrown UnsupportedOperationExcepton");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // Test addAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ try {
+ values.addAll(preload.values());
+ fail("Should have thrown UnsupportedOperationExcepton");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // Test clear()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ assertEquals(5, facets.size());
+ assertEquals(5, values.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+ values.clear();
+ assertEquals(0, facets.size());
+ assertEquals(0, values.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ // Test contains()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ assertTrue(values.contains(facet1));
+ assertTrue(values.contains(facet2));
+ assertTrue(values.contains(facet3));
+ assertTrue(values.contains(facet4));
+ assertTrue(values.contains(facet5));
+ assertTrue(!values.contains(facet6));
+
+ // Test containsAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ matches = new ArrayList<>();
+ matches.add(facet1);
+ matches.add(facet3);
+ matches.add(facet4);
+ assertTrue(values.containsAll(matches));
+ matches = new ArrayList<>();
+ matches.add(facet1);
+ matches.add(facet3);
+ matches.add(facet6);
+ assertTrue(!values.containsAll(matches));
+
+ // Test iterator().hasNext() and iterator().next()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ matches = new ArrayList<>();
+ vals = values.iterator();
+ while (vals.hasNext()) {
+ matches.add(vals.next());
+ }
+ assertTrue(matches.containsAll(values));
+
+ // Test iterator().remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ vals = values.iterator();
+ while (vals.hasNext()) {
+ UIComponent val = vals.next();
+ if (facet2.equals(val) || facet4.equals(val)) {
+ vals.remove();
+ }
+ }
+ assertEquals(3, facets.size());
+ assertEquals(3, values.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test remove()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ values.remove(facet3);
+ assertEquals(4, facets.size());
+ assertEquals(4, values.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test removeAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ matches = new ArrayList<>();
+ matches.add(facet2);
+ matches.add(facet4);
+ values.removeAll(matches);
+ assertEquals(3, facets.size());
+ assertEquals(3, values.size());
+ checkFacetPresent(component, "a", facet1);
+ checkFacetMissing(component, "b", facet2);
+ checkFacetPresent(component, "c", facet3);
+ checkFacetMissing(component, "d", facet4);
+ checkFacetPresent(component, "e", facet5);
+
+ // Test retainAll()
+ facets = component.getFacets();
+ facets.clear();
+ facets.putAll(preload);
+ values = facets.values();
+ matches = new ArrayList<>();
+ matches.add(facet2);
+ matches.add(facet4);
+ matches.add(facet6);
+ values.retainAll(matches);
+ assertEquals(2, facets.size());
+ assertEquals(2, values.size());
+ checkFacetMissing(component, "a", facet1);
+ checkFacetPresent(component, "b", facet2);
+ checkFacetMissing(component, "c", facet3);
+ checkFacetPresent(component, "d", facet4);
+ checkFacetMissing(component, "e", facet5);
+
+ }
+
+ // Negative tests on facet methods
+ @Test
+ public void testFacetsNegative() {
+
+ // Construct components we will need
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+
+ // Set up and verify initial conditions
+ Map facets = component.getFacets();
+ facets.put("facet1", facet1);
+ facets.put("facet2", facet2);
+ checkFacetCount(component, 2);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetPresent(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+
+ // put(Object,Object) - null first argument
+ try {
+ facets.put(null, facet3);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ checkFacetCount(component, 2);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetPresent(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+
+ // put(Object,Object) - null second argument
+ try {
+ facets.put("facet3", null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ checkFacetCount(component, 2);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetPresent(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+
+ }
+
+ // Positive tests on facet methods
+ @Test
+ public void testFacetsPositive() {
+
+ // Construct components we will need
+ UIComponent facet1 = new ComponentTestImpl("facet1");
+ UIComponent facet2 = new ComponentTestImpl("facet2");
+ UIComponent facet3 = new ComponentTestImpl("facet3");
+ UIComponent facet4 = new ComponentTestImpl("facet4");
+ UIComponent facet5 = new ComponentTestImpl("facet5");
+
+ // Verify initial conditions
+ Map facets = component.getFacets();
+ checkFacetCount(component, 0);
+ checkFacetMissing(component, "facet1", facet1);
+ checkFacetMissing(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+ checkFacetMissing(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ // containsKey(Object) is tested in checkFacetMissing / checkFacetPresent
+ // containsValue(Object) is tested in checkFacetMissing / checkFacetPresent
+ // entrySet() is tested in testFacetsMapEntrySet()
+ // get(Object) is tested in checkFacetMissing / checkFacetPresent
+ // isEmpty() is tested in checkFacetCount
+ // keySet() is tested in testFacetsMapKeySet()
+ // put(Object,Object)
+ facets.put("facet1", facet1);
+ checkFacetCount(component, 1);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetMissing(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+ checkFacetMissing(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ // put(Object,Object)
+ facets.put("facet4", facet4);
+ checkFacetCount(component, 2);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetMissing(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+ checkFacetPresent(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ // putAll(Map)
+ Map map = new HashMap<>();
+ map.put("facet2", facet2);
+ map.put("facet3", facet3);
+ facets.putAll(map);
+ checkFacetCount(component, 4);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetPresent(component, "facet2", facet2);
+ checkFacetPresent(component, "facet3", facet3);
+ checkFacetPresent(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ // remove(Object)
+ facets.remove("facet3");
+ checkFacetCount(component, 3);
+ checkFacetPresent(component, "facet1", facet1);
+ checkFacetPresent(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+ checkFacetPresent(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ // values() is tested in testFacetsMapValues()
+ // clear()
+ facets.clear();
+ checkFacetCount(component, 0);
+ checkFacetMissing(component, "facet1", facet1);
+ checkFacetMissing(component, "facet2", facet2);
+ checkFacetMissing(component, "facet3", facet3);
+ checkFacetMissing(component, "facet4", facet4);
+ checkFacetMissing(component, "facet5", facet5);
+
+ }
+
+ // Test a pristine UIComponent instance
+ @Test
+ public void testPristine() {
+
+ // Validate attributes
+ checkAttributeCount(component, expectedAttributes.length);
+ for (int i = 0; i < expectedAttributes.length; i++) {
+ checkAttributePresent(component, expectedAttributes[i], null);
+ }
+
+ // Validate properties
+ assertEquals(expectedFamily, component.getFamily());
+ assertEquals(expectedId, component.getId());
+ assertNull(component.getParent());
+ assertEquals(expectedRendered, component.isRendered());
+ assertEquals(expectedRendererType, component.getRendererType());
+ assertEquals(expectedRendersChildren, component.getRendersChildren());
+
+ // Validate children and facets
+ checkChildCount(component, 0);
+ checkFacetCount(component, 0);
+ int n = 0;
+ Iterator> items = component.getFacetsAndChildren();
+ assertNotNull(items);
+ while (items.hasNext()) {
+ items.next();
+ n++;
+ }
+ assertEquals(0, n);
+
+ }
+
+ // Test setting properties to invalid values
+ @Test
+ public void testPropertiesInvalid() throws Exception {
+
+ // id - zero length
+ try {
+ component.setId("");
+ fail("should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ // id - leading digits
+ try {
+ component.setId("1abc");
+ fail("should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ // id - invalid characters 1
+ try {
+ component.setId("a*c");
+ fail("should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ // id - invalid characters 2
+ try {
+ component.setId(" abc");
+ fail("should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ // id - invalid characters 3
+ try {
+ component.setId("-abc");
+ fail("should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+
+ }
+
+ // Test setting properties to valid values
+ @Test
+ public void testPropertiesValid() throws Exception {
+
+ // id - simple name
+ component.setId("foo");
+ assertEquals("foo", component.getId());
+
+ // id - complex name
+ component.setId("a123-bcd_e");
+ assertEquals("a123-bcd_e", component.getId());
+
+ // parent
+ UIComponent parent = new ComponentTestImpl("parent");
+ component.setParent(parent);
+ assertEquals(parent, component.getParent());
+
+ // rendered
+ component.setRendered(!expectedRendered);
+ assertEquals(!expectedRendered, component.isRendered());
+
+ // rendererType
+ component.setRendererType("foo");
+ assertEquals("foo", component.getRendererType());
+
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Validate that the specified number of attributes are present.
+ protected void checkAttributeCount(UIComponent component, int count) {
+ int result = 0;
+ Iterator> names = component.getAttributes().keySet().iterator();
+ while (names.hasNext()) {
+ names.next();
+ result++;
+ }
+ assertEquals(count, result);
+ }
+
+ // Validate that the specified attribute name is not present
+ protected void checkAttributeMissing(UIComponent component, String name) {
+ assertNull(component.getAttributes().get(name), "Attribute " + name + " should be missing");
+ Iterator> keys = component.getAttributes().keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ if (name.equals(key)) {
+ fail("Attribute " + name + " should not be in names list");
+ }
+ }
+ }
+
+ // Validate that the specified attribute name is present with the
+ // specified value (if value is not null)
+ protected void checkAttributePresent(UIComponent component, String name, Object value) {
+ assertNotNull(component.getAttributes().get(name), "attribute " + name + " should be present");
+ if (value != null) {
+ assertEquals(value, component.getAttributes().get(name));
+ }
+ Iterator> keys = component.getAttributes().keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ if (name.equals(key)) {
+ if (value != null) {
+ assertEquals(value, component.getAttributes().get(name));
+ }
+ return;
+ }
+ }
+ fail("attribute " + name + " should be in name list");
+
+ }
+
+ // Validate that the specified number of children are present
+ protected void checkChildCount(UIComponent component, int count) {
+ assertEquals(count, component.getChildCount());
+ assertEquals(count, component.getChildren().size());
+ assertEquals(count, component.getChildCount());
+ if (count == 0) {
+ assertTrue(component.getChildren().isEmpty());
+ } else {
+ assertTrue(!component.getChildren().isEmpty());
+ }
+ }
+
+ // Validate that the specified child is not present
+ protected void checkChildMissing(UIComponent component, UIComponent child) {
+ assertNull(child.getParent(), "child " + child + " has no parent");
+ List> children = component.getChildren();
+ assertTrue(!children.contains(child), "child " + child + " should not be contained");
+ assertEquals(-1, children.indexOf(child));
+ for (int i = 0; i < children.size(); i++) {
+ if (child.equals(children.get(i))) {
+ fail("child " + child + " should be missing");
+ }
+ }
+ }
+
+ // Validate that the specified child is present at the specified index
+ protected void checkChildPresent(UIComponent component, UIComponent child, int index) {
+ List children = component.getChildren();
+ assertTrue(children.contains(child), "child " + child + " should be contained");
+ assertEquals(index, children.indexOf(child));
+ UIComponent kid = children.get(index);
+ assertEquals(child, kid);
+ assertEquals(component, kid.getParent());
+ }
+
+ // Validate that the specified number of facets is present
+ protected void checkFacetCount(UIComponent component, int count) {
+ assertEquals(count, component.getFacets().size());
+ if (count == 0) {
+ assertTrue(component.getFacets().isEmpty());
+ } else {
+ assertTrue(!component.getFacets().isEmpty());
+ }
+ }
+
+ // Validate that the specified facet is not present
+ protected void checkFacetMissing(UIComponent component, String name, UIComponent facet) {
+ assertNull(facet.getParent(), "facet " + name + " has no parent");
+ Map facets = component.getFacets();
+ assertTrue(!facets.containsKey(name), "facet " + name + " key not present");
+ assertTrue(!facets.containsValue(facet), "facet " + name + " value not present");
+ assertNull(facets.get(name), "facet " + name + " key not found by get");
+ assertNull(component.getFacet(name), "facet " + name + " not returned by getFacet(String)");
+ Iterator keys = facets.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ if (name.equals(key)) {
+ fail("facet " + name + " found in keys");
+ }
+ }
+ Iterator values = facets.values().iterator();
+ while (values.hasNext()) {
+ UIComponent value = values.next();
+ if (facet.equals(value)) {
+ fail("facet " + name + " found in values");
+ }
+ }
+ }
+
+ // Validate that the specified facet is present
+ protected void checkFacetPresent(UIComponent component, String name, UIComponent facet) {
+
+ assertEquals(component, facet.getParent());
+ Map facets = component.getFacets();
+ assertTrue(facets.containsKey(name), "facet " + name + " key is present");
+ assertTrue(facets.containsValue(facet), "facet " + name + " value is present");
+ assertEquals(facet, facets.get(name));
+ assertTrue(facet == component.getFacet(name), "facet " + name + " returned by getFacet(String)");
+ boolean found = false;
+ Iterator keys = facets.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ if (name.equals(key)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ fail("facet " + name + " not found in keys");
+ }
+ found = false;
+ Iterator values = facets.values().iterator();
+ while (values.hasNext()) {
+ UIComponent value = values.next();
+ if (facet.equals(value)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ fail("facet " + name + " not found in values");
+ }
+ }
+
+ // --------------------------------------------------------- Private Classes
+ // Test Implementation of Map.Entry
+ private class TestMapEntry implements Map.Entry {
+
+ private TestMapEntry(String key, UIComponent value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ private String key;
+ private UIComponent value;
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (!(o instanceof Map.Entry)) {
+ return false;
+ }
+ Map.Entry, ?> e = (Map.Entry, ?>) o;
+ if (key == null) {
+ if (e.getKey() != null) {
+ return false;
+ }
+ } else {
+ if (!key.equals(e.getKey())) {
+ return false;
+ }
+ }
+ if (value == null) {
+ if (e.getValue() != null) {
+ return false;
+ }
+ } else {
+ if (!value.equals(e.getValue())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String getKey() {
+ return key;
+ }
+
+ @Override
+ public UIComponent getValue() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
+ }
+
+ @Override
+ public UIComponent setValue(UIComponent value) {
+ UIComponent previous = this.value;
+ this.value = value;
+ return previous;
+ }
+
+ }
+
+ public static class Listener implements ComponentSystemEventListener, Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private StringBuilder sb = new StringBuilder();
+
+ @Override
+ public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
+ UIComponent source = (UIComponent) event.getSource();
+ Boolean validatorCalled = (Boolean) source.getAttributes().remove("vCalled");
+ if (validatorCalled != null) {
+ sb.append("*/");
+ }
+ sb.append(source.getId()).append('/');
+ }
+
+ public String getResults() {
+ return sb.toString();
+ }
+ }
+
+ public static class ValidationSignal implements Validator {
+
+ @Override
+ public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
+
+ component.getAttributes().put("vCalled", Boolean.TRUE);
+
+ }
+ }
+
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIDataTest.java b/impl/src/test/java/jakarta/faces/component/UIDataTest.java
new file mode 100644
index 0000000000..5804801c20
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIDataTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static jakarta.faces.component.NamingContainer.SEPARATOR_CHAR;
+import static jakarta.faces.component.UINamingContainer.SEPARATOR_CHAR_PARAM_NAME;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.render.RenderKit;
+
+/**
+ * @author Manfred Riem (manfred.riem@oracle.com)
+ */
+public class UIDataTest {
+
+ /**
+ * Test partial state saving.
+ */
+ @Test
+ public void testSaveState() {
+ FacesContext context = mock(FacesContext.class);
+ UIData data = new UIData();
+ data.markInitialState();
+ assertNull(data.saveState(context));
+ }
+
+ /**
+ * Test full state saving.
+ */
+ @Test
+ public void testSaveState2() {
+ FacesContext context = mock(FacesContext.class);
+ UIData data = new UIData();
+ assertNotNull(data.saveState(context));
+ }
+
+ /**
+ * Test partial state saving with rowIndex.
+ */
+ @Test
+ public void testSaveState3() {
+ FacesContext context = mock(FacesContext.class);
+ UIData data = new UIData();
+ data.markInitialState();
+ data.setRowIndex(4);
+ assertNotNull(data.saveState(context));
+ }
+
+ @Test
+ public void testInvokeOnComponentMustNotCallSetRowIndexIfNotTouched() throws Exception {
+ FacesContext context = mock(FacesContext.class);
+ ExternalContext externalContext = mock(ExternalContext.class);
+ when(context.getExternalContext()).thenReturn(externalContext);
+ RenderKit renderKit = mock(RenderKit.class);
+ when(context.getRenderKit()).thenReturn(renderKit);
+ context.getAttributes().put(SEPARATOR_CHAR_PARAM_NAME, SEPARATOR_CHAR);
+
+ UIData data = new UIData() {
+ @Override
+ public void setRowIndex(int rowIndex) {
+ context.getAttributes().put("setRowIndexCalled", true);
+ }
+ };
+
+ data.setId("data");
+
+ data.invokeOnComponent(context, "differentId", (contextInLambda, target) -> {
+ });
+
+ assertNull(context.getAttributes().get("setRowIndexCalled"));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIGraphicTestCase.java b/impl/src/test/java/jakarta/faces/component/UIGraphicTestCase.java
new file mode 100644
index 0000000000..01380c37da
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIGraphicTestCase.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UIGraphic}.
+ *
+ */
+public class UIGraphicTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIGraphic();
+ expectedFamily = UIGraphic.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = "jakarta.faces.Image";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+
+ super.testAttributesTransparency();
+ UIGraphic graphic = (UIGraphic) component;
+
+ assertEquals(graphic.getValue(), component.getAttributes().get("value"));
+ graphic.setValue("foo");
+ assertEquals("foo", component.getAttributes().get("value"));
+ graphic.setValue(null);
+ assertNull(component.getAttributes().get("value"));
+ component.getAttributes().put("value", "bar");
+ assertEquals("bar", graphic.getValue());
+ component.getAttributes().put("value", null);
+ assertNull(graphic.getValue());
+
+ assertEquals(graphic.getUrl(), graphic.getAttributes().get("url"));
+ graphic.setUrl("foo");
+ assertEquals("foo", graphic.getAttributes().get("url"));
+ graphic.setUrl(null);
+ assertNull(graphic.getAttributes().get("url"));
+ graphic.getAttributes().put("url", "bar");
+ assertEquals("bar", graphic.getUrl());
+ graphic.getAttributes().put("url", null);
+ assertNull(graphic.getUrl());
+ }
+
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // Test a pristine UIGraphic instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UIGraphic graphic = (UIGraphic) component;
+
+ assertNull(graphic.getValue());
+ assertNull(graphic.getUrl());
+ }
+
+ // Test setting properties to invalid values
+ @Override
+ @Test
+ public void testPropertiesInvalid() throws Exception {
+ super.testPropertiesInvalid();
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIGraphic();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIInputTest.java b/impl/src/test/java/jakarta/faces/component/UIInputTest.java
new file mode 100644
index 0000000000..9646a002d3
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIInputTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.validator.LengthValidator;
+import jakarta.faces.validator.LongRangeValidator;
+import jakarta.faces.validator.Validator;
+
+/**
+ * @author Manfred Riem (manfred.riem@oracle.com)
+ */
+public class UIInputTest {
+
+ @Test
+ public void testSaveState() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ assertNotNull(input.saveState(context));
+ }
+
+ @Test
+ public void testSaveState2() {
+ UIInput input = new UIInput();
+ assertThrows(NullPointerException.class, () -> input.saveState(null));
+ }
+
+ @Test
+ public void testSaveState3() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ input.markInitialState();
+ assertNull(input.saveState(context));
+ }
+
+ @Test
+ public void testSaveState4() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ LengthValidator l1 = new LengthValidator();
+ LengthValidator l2 = new LengthValidator();
+ input.addValidator(l1);
+ input.addValidator(l2);
+ l1.setMinimum(1);
+ l2.setMinimum(2);
+ input.markInitialState();
+ assertTrue(input.initialStateMarked());
+ assertTrue(l1.initialStateMarked());
+ assertTrue(l2.initialStateMarked());
+ Object state = input.saveState(context);
+ assertNull(state);
+ }
+
+ @Test
+ public void testRestoreState() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ input.restoreState(context, null);
+ }
+
+ @Test
+ public void testRestoreState2() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ assertThrows(NullPointerException.class, () -> input.restoreState(null, null));
+ }
+
+ @Test
+ public void testRestoreState3() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ Object state = input.saveState(context);
+ assertNotNull(state);
+ input.restoreState(context, state);
+ }
+
+ @Test
+ public void testRestoreState4() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ input.addValidator(new LongRangeValidator());
+ Object state = input.saveState(context);
+ assertNotNull(state);
+ input = new UIInput();
+ input.restoreState(context, state);
+ }
+
+ @Test
+ public void testRestoreState5() {
+ FacesContext context = Mockito.mock(FacesContext.class);
+ UIInput input = new UIInput();
+ LengthValidator l1 = new LengthValidator();
+ LengthValidator l2 = new LengthValidator();
+ input.addValidator(l1);
+ input.addValidator(l2);
+ l1.setMinimum(1);
+ l2.setMinimum(2);
+ input.markInitialState();
+ l2.setMinimum(3);
+ assertTrue(input.initialStateMarked());
+ assertTrue(l1.initialStateMarked());
+ assertTrue(!l2.initialStateMarked());
+ Object state = input.saveState(context);
+ assertTrue(state instanceof Object[]);
+ Object[] validatorState = (Object[]) ((Object[]) state)[1];
+ assertNotNull(validatorState);
+ assertNull(validatorState[0]);
+ assertNotNull(validatorState[1]);
+ assertTrue(!(validatorState[1] instanceof StateHolderSaver));
+ input = new UIInput();
+ l1 = new LengthValidator();
+ l2 = new LengthValidator();
+ l1.setMinimum(1);
+ l2.setMinimum(2);
+ input.addValidator(l1);
+ input.addValidator(l2);
+ input.restoreState(context, state);
+ assertTrue(l1.getMinimum() == 1);
+ assertTrue(l2.getMinimum() == 3);
+ assertTrue(input.getValidators().length == 2);
+
+ input = new UIInput();
+ l1 = new LengthValidator();
+ l2 = new LengthValidator();
+ input.addValidator(l1);
+ input.addValidator(l2);
+ l1.setMinimum(1);
+ l2.setMinimum(2);
+ input.markInitialState();
+ LengthValidator l3 = new LengthValidator();
+ l3.setMinimum(3);
+ input.addValidator(l3);
+ state = input.saveState(context);
+ assertNotNull(validatorState);
+ assertTrue(state instanceof Object[]);
+ validatorState = (Object[]) ((Object[]) state)[1];
+ assertNotNull(validatorState);
+ assertTrue(validatorState.length == 3);
+ assertNotNull(validatorState[0]);
+ assertNotNull(validatorState[1]);
+ assertNotNull(validatorState[2]);
+ assertTrue(validatorState[0] instanceof StateHolderSaver);
+ assertTrue(validatorState[1] instanceof StateHolderSaver);
+ assertTrue(validatorState[2] instanceof StateHolderSaver);
+
+ input = new UIInput();
+ l1 = new LengthValidator();
+ l2 = new LengthValidator();
+ l3 = new LengthValidator();
+ LengthValidator l4 = new LengthValidator();
+ input.addValidator(l1);
+ input.addValidator(l2);
+ input.addValidator(l3);
+ input.addValidator(l4);
+ l1.setMinimum(100);
+ l2.setMinimum(101);
+ l3.setMinimum(102);
+ l4.setMinimum(103);
+ assertTrue(input.getValidators().length == 4);
+ input.markInitialState();
+ input.restoreState(context, state);
+ assertTrue(input.getValidators().length == 3);
+
+ Validator[] validators = input.getValidators();
+ for (int i = 0, len = validators.length; i < len; i++) {
+ LengthValidator v = (LengthValidator) validators[i];
+ assertTrue(v.getMinimum() == i + 1);
+ }
+
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIInputTestCase.java b/impl/src/test/java/jakarta/faces/component/UIInputTestCase.java
new file mode 100644
index 0000000000..1013cd5732
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIInputTestCase.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Iterator;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.PhaseId;
+import jakarta.faces.event.ValueChangeEvent;
+import jakarta.faces.event.ValueChangeListener;
+import jakarta.faces.validator.Validator;
+
+/**
+ *
+ * Unit tests for {@link UIInput}.
+ *
+ */
+public class UIInputTestCase extends UIOutputTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIInput();
+ expectedFamily = UIInput.COMPONENT_FAMILY;
+ expectedRendererType = "jakarta.faces.Text";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ UIInput input = (UIInput) component;
+
+ assertEquals(input.getSubmittedValue(), input.getAttributes().get("submittedValue"));
+ input.setSubmittedValue("foo");
+ assertEquals("foo", input.getAttributes().get("submittedValue"));
+ input.setSubmittedValue(null);
+ assertNull(input.getAttributes().get("submittedValue"));
+ input.getAttributes().put("submittedValue", "bar");
+ assertEquals("bar", input.getSubmittedValue());
+ input.getAttributes().put("submittedValue", null);
+ assertNull(input.getSubmittedValue());
+
+ input.setRequired(true);
+ assertEquals(Boolean.TRUE, input.getAttributes().get("required"));
+ input.setRequired(false);
+ assertEquals(Boolean.FALSE, input.getAttributes().get("required"));
+ input.getAttributes().put("required", Boolean.TRUE);
+ assertTrue(input.isRequired());
+ input.getAttributes().put("required", Boolean.FALSE);
+ assertTrue(!input.isRequired());
+
+ assertEquals(input.isValid(), true);
+ assertEquals(input.isValid(), ((Boolean) component.getAttributes().get("valid")).booleanValue());
+ input.setValid(false);
+ assertEquals(input.isValid(), ((Boolean) component.getAttributes().get("valid")).booleanValue());
+ component.getAttributes().put("valid", Boolean.TRUE);
+ assertEquals(input.isValid(), ((Boolean) component.getAttributes().get("valid")).booleanValue());
+
+ }
+
+ // Test the compareValues() method
+ @Test
+ public void testCompareValues() {
+ InputTestImpl input = new InputTestImpl();
+ Object value1a = "foo";
+ Object value1b = "foo";
+ Object value2 = "bar";
+ Object value3 = null;
+
+ assertTrue(!input.compareValues(value1a, value1a));
+ assertTrue(!input.compareValues(value1a, value1b));
+ assertTrue(!input.compareValues(value1b, value1b));
+ assertTrue(!input.compareValues(value2, value2));
+ assertTrue(!input.compareValues(value3, value3));
+
+ assertTrue(input.compareValues(value1a, value2));
+ assertTrue(input.compareValues(value1a, value3));
+ assertTrue(input.compareValues(value2, value3));
+ assertTrue(input.compareValues(value3, value2));
+ }
+
+ // Test event queuing and broadcasting (any phase listeners)
+ @Test
+ public void testEventsGeneric() {
+ UIInput input = (UIInput) component;
+ ValueChangeEvent event = new ValueChangeEvent(input, null, null);
+
+ // Register three listeners
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("AP0"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("AP1"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("AP2"));
+
+ // Fire events and evaluate results
+ ValueChangeListenerTestImpl.trace(null);
+ input.broadcast(event);
+ assertEquals("/AP0/AP1/AP2", ValueChangeListenerTestImpl.trace());
+ }
+
+ // Test event queuing and broadcasting (mixed phase listeners)
+ @Test
+ public void testEventsMixed() {
+ UIInput input = (UIInput) component;
+ input.setRendererType(null);
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(input);
+ ValueChangeEvent event = null;
+
+ // Register three listeners
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("ARV"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("PV"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("AP"));
+
+ ValueChangeListenerTestImpl.trace(null);
+ event = new ValueChangeEvent(input, null, null);
+ event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ input.queueEvent(event);
+
+ event = new ValueChangeEvent(input, null, null);
+ event.setPhaseId(PhaseId.PROCESS_VALIDATIONS);
+ input.queueEvent(event);
+
+ event = new ValueChangeEvent(input, null, null);
+ event.setPhaseId(PhaseId.INVOKE_APPLICATION);
+ input.queueEvent(event);
+
+ // Fire events and evaluate results
+ root.processDecodes(facesContext);
+ root.processValidators(facesContext);
+ root.processApplication(facesContext);
+ assertEquals("/ARV/PV/AP/ARV/PV/AP/ARV/PV/AP", ValueChangeListenerTestImpl.trace());
+ }
+
+ // Test listener registration and deregistration
+ @Test
+ public void testListeners() {
+ InputTestImpl input = new InputTestImpl();
+
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("ARV0"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("ARV1"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("PV0"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("PV1"));
+ input.addValueChangeListener(new ValueChangeListenerTestImpl("PV2"));
+
+ ValueChangeListener listeners[] = input.getValueChangeListeners();
+ assertEquals(5, listeners.length);
+ input.removeValueChangeListener(listeners[2]);
+ listeners = input.getValueChangeListeners();
+ assertEquals(4, listeners.length);
+ }
+
+ // Test empty listener list
+ @Test
+ public void testEmptyListeners() {
+ InputTestImpl input = new InputTestImpl();
+
+ // No listeners added, should be empty
+ ValueChangeListener listeners[] = input.getValueChangeListeners();
+ assertEquals(0, listeners.length);
+ }
+
+ // Test a pristine UIInput instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UIInput input = (UIInput) component;
+
+ assertNull(input.getSubmittedValue());
+ assertTrue(!input.isRequired());
+ assertTrue(input.isValid());
+ assertTrue(!input.isImmediate());
+ }
+
+ // Test setting properties to invalid values
+ @Override
+ @Test
+ public void testPropertiesInvalid() throws Exception {
+ super.testPropertiesInvalid();
+ UIInput input = (UIInput) component;
+ }
+
+ // Test validation of a required field
+ @Test
+ public void testValidateRequired() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UIInput input = (UIInput) component;
+ input.setRequired(true);
+ checkMessages(0);
+
+ input.setValid(true);
+ input.setSubmittedValue("foo");
+ input.validate(facesContext);
+ checkMessages(0);
+ assertTrue(input.isValid());
+
+ input.getAttributes().put("label", "mylabel");
+ input.setValid(true);
+ input.setSubmittedValue("");
+ input.validate(facesContext);
+ checkMessages(1);
+ assertTrue(!input.isValid());
+
+ Iterator messages = facesContext.getMessages();
+ while (messages.hasNext()) {
+ FacesMessage message = messages.next();
+ assertTrue(message.getSummary().indexOf("mylabel") >= 0);
+ }
+
+ input.setValid(true);
+ input.setSubmittedValue(null);
+ input.validate(facesContext);
+ // awiner: this was formerly "checkMessages(2)", but a submitted
+ // value of null now explicitly means _do not validate_.
+ checkMessages(1);
+ // awiner: And this next line flipped as well
+ assertTrue(input.isValid());
+ }
+
+ @Test
+ public void testGetValueChangeListeners() throws Exception {
+ UIInput command = (UIInput) component;
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(command);
+
+ ValueChangeListenerTestImpl ta1 = new ValueChangeListenerTestImpl("ta1"), ta2 = new ValueChangeListenerTestImpl("ta2");
+
+ command.addValueChangeListener(ta1);
+ command.addValueChangeListener(ta2);
+ ValueChangeListener[] listeners = command.getValueChangeListeners();
+ assertEquals(2, listeners.length);
+ ValueChangeListenerTestImpl[] taListeners = (ValueChangeListenerTestImpl[]) command.getFacesListeners(ValueChangeListenerTestImpl.class);
+ assertTrue(taListeners != null);
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Check that the number of queued messages equals the expected count
+ // and that each of them is of severity ERROR
+ protected void checkMessages(int expected) {
+ facesContext.getExceptionHandler().handle();
+ int n = 0;
+ Iterator messages = facesContext.getMessages();
+ while (messages.hasNext()) {
+ FacesMessage message = messages.next();
+ assertEquals(FacesMessage.SEVERITY_ERROR, message.getSeverity());
+ n++;
+ // System.err.println(message.getSummary());
+ }
+ assertEquals(expected, n);
+ }
+
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIInput();
+ component.setRendererType(null);
+ return component;
+ }
+
+ protected boolean listenersAreEqual(FacesContext context, UIInput comp1, UIInput comp2) {
+
+ ValueChangeListener list1[] = comp1.getValueChangeListeners();
+ ValueChangeListener list2[] = comp2.getValueChangeListeners();
+ assertNotNull(list1);
+ assertNotNull(list2);
+ assertEquals(list1.length, list2.length);
+ for (int i = 0; i < list1.length; i++) {
+ assertTrue(list1[i].getClass() == list2[i].getClass());
+ }
+ return true;
+ }
+
+ protected void setupNewValue(UIInput input) {
+ input.setSubmittedValue("foo");
+ }
+
+ protected boolean validatorsAreEqual(FacesContext context, UIInput comp1, UIInput comp2) {
+
+ Validator list1[] = comp1.getValidators();
+ Validator list2[] = comp2.getValidators();
+ assertNotNull(list1);
+ assertNotNull(list2);
+ assertEquals(list1.length, list2.length);
+ for (int i = 0; i < list1.length; i++) {
+ assertTrue(list1[i].getClass() == list2[i].getClass());
+ }
+ return true;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIOutputAttachedObjectStateTestCase.java b/impl/src/test/java/jakarta/faces/component/UIOutputAttachedObjectStateTestCase.java
new file mode 100644
index 0000000000..cabd4b5704
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIOutputAttachedObjectStateTestCase.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Method;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockExternalContext;
+import com.sun.faces.mock.MockFacesContext;
+import com.sun.faces.mock.MockHttpServletRequest;
+import com.sun.faces.mock.MockHttpServletResponse;
+import com.sun.faces.mock.MockLifecycle;
+import com.sun.faces.mock.MockServletContext;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.convert.Converter;
+import jakarta.faces.convert.DateTimeConverter;
+
+public class UIOutputAttachedObjectStateTestCase {
+
+ private MockFacesContext facesContext = null;
+ private MockServletContext servletContext;
+ private MockHttpServletRequest request;
+ private MockHttpServletResponse response;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ facesContext = new MockFacesContext();
+ facesContext = new MockFacesContext();
+
+ servletContext = new MockServletContext();
+ servletContext.addInitParameter("appParamName", "appParamValue");
+ servletContext.setAttribute("appScopeName", "appScopeValue");
+ request = new MockHttpServletRequest(null);
+ request.setAttribute("reqScopeName", "reqScopeValue");
+ response = new MockHttpServletResponse();
+
+ // Create something to stand-in as the InitFacesContext
+ new MockFacesContext(new MockExternalContext(servletContext, request, response), new MockLifecycle());
+
+ }
+
+ @AfterEach
+ protected void tearDown() throws Exception {
+ FactoryFinder.releaseFactories();
+ Method reInitializeFactoryManager = FactoryFinder.class.getDeclaredMethod("reInitializeFactoryManager", (Class>[]) null);
+ reInitializeFactoryManager.setAccessible(true);
+ reInitializeFactoryManager.invoke(null, (Object[]) null);
+ }
+
+ // ------------------------------------------------------------ Test Methods
+
+ @Test
+ public void testConverterState() {
+ UIOutput output = new UIOutput();
+ DateTimeConverter converter = new DateTimeConverter();
+ converter.setPattern("MM-dd-yy");
+ output.setConverter(converter);
+ output.markInitialState();
+ assertTrue(output.initialStateMarked());
+ assertTrue(converter.initialStateMarked());
+
+ Object result = output.saveState(facesContext);
+ // initial state has been marked an no changes
+ // have occurred, we should have null state.
+ assertNull(result);
+
+ // setup the scenario again, but this time,
+ // update the converter pattern.
+ output = new UIOutput();
+ converter = new DateTimeConverter();
+ converter.setPattern("MM-dd-yy");
+ output.setConverter(converter);
+ output.markInitialState();
+ assertTrue(output.initialStateMarked());
+ assertTrue(converter.initialStateMarked());
+
+ // now tweak the converter
+ converter.setPattern("dd-MM-yy");
+ result = output.saveState(facesContext);
+ assertTrue(result instanceof Object[]);
+ Object[] state = (Object[]) result;
+
+ // state should have a lenght of 2. The first element
+ // is the state from UIComponentBase, where the second
+ // is the converter state. The first element in this
+ // case should be null
+ assertTrue(state.length == 2);
+ assertTrue(state[0] == null);
+ assertTrue(state[1] != null);
+
+ output = new UIOutput();
+ converter = new DateTimeConverter();
+ output.setConverter(converter);
+
+ // now validate what we've restored
+ // first, ensure converter is null. This will
+ // be the case when initialState has been marked
+ // for the component.
+ output.restoreState(facesContext, state);
+ assertTrue(output.getConverter() != null);
+ assertEquals("dd-MM-yy", converter.getPattern());
+
+ // now validate the case where UIOutput has some event
+ // that adds a converter *after* initial state has been
+ // marked. This will cause the component to save full
+ // state.
+ output = new UIOutput();
+ output.markInitialState();
+ output.setConverter(converter);
+ assertTrue(!output.initialStateMarked());
+ assertTrue(!converter.initialStateMarked());
+
+ result = output.saveState(facesContext);
+ assertNotNull(result);
+
+ // this time, both elements in the state array will not
+ // be null. If we call retoreState() on a new component instance
+ // without setting a converter, we should have a new DateTimeConverter
+ // *with* the expected pattern.
+ assertTrue(result instanceof Object[]);
+ state = (Object[]) result;
+ assertTrue(state.length == 2);
+ assertTrue(state[1] instanceof StateHolderSaver);
+ output = new UIOutput();
+ assertNull(output.getConverter());
+ output.restoreState(facesContext, state);
+ Converter c = output.getConverter();
+ assertNotNull(c);
+ assertTrue(c instanceof DateTimeConverter);
+ converter = (DateTimeConverter) c;
+ assertEquals("dd-MM-yy", converter.getPattern());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIOutputTestCase.java b/impl/src/test/java/jakarta/faces/component/UIOutputTestCase.java
new file mode 100644
index 0000000000..c5a620a011
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIOutputTestCase.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UIOutput}.
+ *
+ */
+public class UIOutputTestCase extends ValueHolderTestCaseBase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIOutput();
+ expectedFamily = UIOutput.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = "jakarta.faces.Text";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIOutput();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIPanelTestCase.java b/impl/src/test/java/jakarta/faces/component/UIPanelTestCase.java
new file mode 100644
index 0000000000..d551eaaa97
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIPanelTestCase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UIPanel}.
+ *
+ */
+public class UIPanelTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIPanel();
+ expectedFamily = UIPanel.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = null;
+ expectedRendersChildren = false;
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIPanel();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIParameterTest.java b/impl/src/test/java/jakarta/faces/component/UIParameterTest.java
new file mode 100644
index 0000000000..e5f4c5f8c4
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIParameterTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Method;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.el.ELContext;
+import jakarta.el.ValueExpression;
+import jakarta.faces.context.FacesContext;
+
+public class UIParameterTest {
+
+ /**
+ * Test isDisable method.
+ */
+ @Test
+ public void testIsDisable() throws Exception {
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ Method method = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
+ method.setAccessible(true);
+ method.invoke(null, facesContext);
+ UIParameter parameter = new UIParameter();
+ parameter.setDisable(true);
+ assertTrue(parameter.isDisable());
+ method.invoke(null, (FacesContext) null);
+ }
+
+ /**
+ * Test isDisable method.
+ */
+ @Test
+ public void testIsDisable2() throws Exception {
+ ELContext elContext = Mockito.mock(ELContext.class);
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ ValueExpression valueExpression = Mockito.mock(ValueExpression.class);
+ Method method = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
+ method.setAccessible(true);
+ method.invoke(null, facesContext);
+ when(facesContext.getExternalContext()).thenReturn(null);
+ when(valueExpression.isLiteralText()).thenReturn(false);
+ when(facesContext.getELContext()).thenReturn(elContext);
+ when(valueExpression.getValue(elContext)).thenReturn(true);
+ UIParameter parameter = new UIParameter();
+ parameter.setValueExpression("disable", valueExpression);
+ assertTrue(parameter.isDisable());
+ method.invoke(null, (FacesContext) null);
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIParameterTestCase.java b/impl/src/test/java/jakarta/faces/component/UIParameterTestCase.java
new file mode 100644
index 0000000000..a8b312a8cb
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIParameterTestCase.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UIParameter}.
+ *
+ */
+public class UIParameterTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIParameter();
+ expectedFamily = UIParameter.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = null;
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ UIParameter parameter = (UIParameter) component;
+
+ assertEquals(parameter.getValue(), component.getAttributes().get("value"));
+ parameter.setValue("foo");
+ assertEquals("foo", component.getAttributes().get("value"));
+ parameter.setValue(null);
+ assertNull(component.getAttributes().get("value"));
+ component.getAttributes().put("value", "bar");
+ assertEquals("bar", parameter.getValue());
+ component.getAttributes().put("value", null);
+ assertNull(parameter.getValue());
+
+ assertEquals(parameter.getName(), parameter.getAttributes().get("name"));
+ parameter.setName("foo");
+ assertEquals("foo", parameter.getAttributes().get("name"));
+ parameter.setName(null);
+ assertNull(parameter.getAttributes().get("name"));
+ parameter.getAttributes().put("name", "bar");
+ assertEquals("bar", parameter.getName());
+ parameter.getAttributes().put("name", null);
+ assertNull(parameter.getName());
+ }
+
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // Test a pristine UIParameter instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UIParameter parameter = (UIParameter) component;
+
+ assertNull(parameter.getValue());
+ assertNull(parameter.getName());
+ }
+
+ // Test setting properties to valid values
+ @Override
+ @Test
+ public void testPropertiesValid() throws Exception {
+ super.testPropertiesValid();
+ UIParameter parameter = (UIParameter) component;
+
+ // value
+ parameter.setValue("foo.bar");
+ assertEquals("foo.bar", parameter.getValue());
+ parameter.setValue(null);
+ assertNull(parameter.getValue());
+
+ parameter.setName("foo");
+ assertEquals("foo", parameter.getName());
+ parameter.setName(null);
+ assertNull(parameter.getName());
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Check that the properties on the specified components are equal
+ @Override
+ protected void checkProperties(UIComponent comp1, UIComponent comp2) {
+ super.checkProperties(comp1, comp2);
+ UIParameter p1 = (UIParameter) comp1;
+ UIParameter p2 = (UIParameter) comp2;
+ assertEquals(p1.getName(), p2.getName());
+ }
+
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIParameter();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectBooleanTestCase.java b/impl/src/test/java/jakarta/faces/component/UISelectBooleanTestCase.java
new file mode 100644
index 0000000000..423bf4c708
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectBooleanTestCase.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for {@link UISelectBoolean}.
+ *
+ */
+public class UISelectBooleanTestCase extends UIInputTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UISelectBoolean();
+ expectedFamily = UISelectBoolean.COMPONENT_FAMILY;
+ expectedRendererType = "jakarta.faces.Checkbox";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ UISelectBoolean selectBoolean = (UISelectBoolean) component;
+
+ selectBoolean.setSelected(false);
+ assertEquals(Boolean.FALSE, selectBoolean.getAttributes().get("selected"));
+ selectBoolean.setSelected(true);
+ assertEquals(Boolean.TRUE, selectBoolean.getAttributes().get("selected"));
+ selectBoolean.getAttributes().put("selected", Boolean.FALSE);
+ assertTrue(!selectBoolean.isSelected());
+ selectBoolean.getAttributes().put("selected", Boolean.TRUE);
+ assertTrue(selectBoolean.isSelected());
+ }
+
+ // Test a pristine UISelectBoolean instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UISelectBoolean selectBoolean = (UISelectBoolean) component;
+ assertTrue(!selectBoolean.isSelected());
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UISelectBoolean();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectItemSub.java b/impl/src/test/java/jakarta/faces/component/UISelectItemSub.java
new file mode 100644
index 0000000000..bdb949ae80
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectItemSub.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+public class UISelectItemSub extends UISelectItem {
+
+ public UISelectItemSub(String value, String label, String description) {
+ setItemValue(value);
+ setItemLabel(label);
+ setItemDescription(description);
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectItemTestCase.java b/impl/src/test/java/jakarta/faces/component/UISelectItemTestCase.java
new file mode 100644
index 0000000000..4cb3712e38
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectItemTestCase.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.model.SelectItem;
+
+/**
+ *
+ * Unit tests for {@link UISelectItem}.
+ *
+ */
+public class UISelectItemTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UISelectItem();
+ expectedFamily = UISelectItem.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = null;
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ UISelectItem selectItem = (UISelectItem) component;
+
+ assertEquals(selectItem.getValue(), component.getAttributes().get("value"));
+ SelectItem item = new SelectItem("foo");
+ selectItem.setValue(item);
+ assertEquals(item, component.getAttributes().get("value"));
+ selectItem.setValue(null);
+
+ assertNull(component.getAttributes().get("value"));
+ component.getAttributes().put("value", "bar");
+ assertEquals("bar", selectItem.getValue());
+ component.getAttributes().put("value", null);
+ assertNull(selectItem.getValue());
+
+ assertEquals(selectItem.getItemDescription(), selectItem.getAttributes().get("itemDescription"));
+ selectItem.setItemDescription("foo");
+ assertEquals("foo", selectItem.getAttributes().get("itemDescription"));
+ selectItem.setItemDescription(null);
+ assertNull(selectItem.getAttributes().get("itemDescription"));
+ selectItem.getAttributes().put("itemDescription", "bar");
+ assertEquals("bar", selectItem.getItemDescription());
+ selectItem.getAttributes().put("itemDescription", null);
+ assertNull(selectItem.getItemDescription());
+
+ assertEquals(selectItem.isItemDisabled(), ((Boolean) selectItem.getAttributes().get("itemDisabled")).booleanValue());
+ selectItem.setItemDisabled(true);
+ assertTrue(((Boolean) selectItem.getAttributes().get("itemDisabled")).booleanValue());
+ selectItem.setItemDisabled(false);
+ assertFalse(((Boolean) selectItem.getAttributes().get("itemDisabled")).booleanValue());
+ selectItem.getAttributes().put("itemDisabled", Boolean.FALSE);
+ assertFalse(selectItem.isItemDisabled());
+ selectItem.getAttributes().put("itemDisabled", Boolean.TRUE);
+ assertTrue(selectItem.isItemDisabled());
+
+ assertEquals(selectItem.getItemLabel(), selectItem.getAttributes().get("itemLabel"));
+ selectItem.setItemLabel("foo");
+ assertEquals("foo", selectItem.getAttributes().get("itemLabel"));
+ selectItem.setItemLabel(null);
+ assertNull(selectItem.getAttributes().get("itemLabel"));
+ selectItem.getAttributes().put("itemLabel", "bar");
+ assertEquals("bar", selectItem.getItemLabel());
+ selectItem.getAttributes().put("itemLabel", null);
+ assertNull(selectItem.getItemLabel());
+
+ assertEquals(selectItem.getItemValue(), selectItem.getAttributes().get("itemValue"));
+ selectItem.setItemValue("foo");
+ assertEquals("foo", selectItem.getAttributes().get("itemValue"));
+ selectItem.setItemValue(null);
+ assertNull(selectItem.getAttributes().get("itemValue"));
+ selectItem.getAttributes().put("itemValue", "bar");
+ assertEquals("bar", selectItem.getItemValue());
+ selectItem.getAttributes().put("itemValue", null);
+ assertNull(selectItem.getItemValue());
+ }
+
+ // Test a pristine UISelectItem instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UISelectItem selectItem = (UISelectItem) component;
+
+ assertNull(selectItem.getValue());
+ assertNull(selectItem.getItemDescription());
+ assertFalse(selectItem.isItemDisabled());
+ assertNull(selectItem.getItemLabel());
+ assertNull(selectItem.getItemValue());
+ }
+
+ // Test setting properties to valid values
+ @Override
+ @Test
+ public void testPropertiesValid() throws Exception {
+ super.testPropertiesValid();
+ UISelectItem selectItem = (UISelectItem) component;
+
+ // value
+ SelectItem item = new SelectItem("foo");
+ selectItem.setValue(item);
+ assertEquals(item, selectItem.getValue());
+ selectItem.setValue(null);
+ assertNull(selectItem.getValue());
+
+ selectItem.setItemDescription("foo");
+ assertEquals("foo", selectItem.getItemDescription());
+ selectItem.setItemDescription(null);
+ assertNull(selectItem.getItemDescription());
+
+ selectItem.setItemDisabled(false);
+ assertFalse(selectItem.isItemDisabled());
+ selectItem.setItemDisabled(true);
+ assertTrue(selectItem.isItemDisabled());
+
+ selectItem.setItemLabel("foo");
+ assertEquals("foo", selectItem.getItemLabel());
+ selectItem.setItemLabel(null);
+ assertNull(selectItem.getItemLabel());
+
+ selectItem.setItemValue("foo");
+ assertEquals("foo", selectItem.getItemValue());
+ selectItem.setItemValue(null);
+ assertNull(selectItem.getItemValue());
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Check that the properties on the specified components are equal
+ @Override
+ protected void checkProperties(UIComponent comp1, UIComponent comp2) {
+ super.checkProperties(comp1, comp2);
+ UISelectItem si1 = (UISelectItem) comp1;
+ UISelectItem si2 = (UISelectItem) comp2;
+ assertEquals(si1.getItemDescription(), si2.getItemDescription());
+ assertEquals(si1.isItemDisabled(), si2.isItemDisabled());
+ assertEquals(si1.getItemLabel(), si2.getItemLabel());
+ assertEquals(si1.getItemValue(), si2.getItemValue());
+ }
+
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UISelectItem();
+ component.setRendererType(null);
+ return component;
+ }
+
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectItemsTestCase.java b/impl/src/test/java/jakarta/faces/component/UISelectItemsTestCase.java
new file mode 100644
index 0000000000..cde6a1e6b1
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectItemsTestCase.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.model.SelectItem;
+
+/**
+ *
+ * Unit tests for {@link UISelectItems}.
+ *
+ */
+public class UISelectItemsTestCase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UISelectItems();
+ expectedFamily = UISelectItems.COMPONENT_FAMILY;
+ expectedId = null;
+ expectedRendererType = null;
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test attribute-property transparency
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ UISelectItems selectItems = (UISelectItems) component;
+
+ assertEquals(selectItems.getValue(), component.getAttributes().get("value"));
+ SelectItem item = new SelectItem("foo");
+ selectItems.setValue(item);
+ assertEquals(item, component.getAttributes().get("value"));
+ selectItems.setValue(null);
+ assertNull(component.getAttributes().get("value"));
+ component.getAttributes().put("value", "bar");
+ assertEquals("bar", selectItems.getValue());
+ component.getAttributes().put("value", null);
+ assertNull(selectItems.getValue());
+ }
+
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // Test a pristine UISelectItems instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UISelectItems selectItems = (UISelectItems) component;
+ assertNull(selectItems.getValue());
+ }
+
+ // Test setting properties to valid values
+ @Override
+ @Test
+ public void testPropertiesValid() throws Exception {
+ super.testPropertiesValid();
+ UISelectItems selectItems = (UISelectItems) component;
+
+ // value
+ SelectItem item = new SelectItem("foo");
+ selectItems.setValue(item);
+ assertEquals(item, selectItems.getValue());
+ selectItems.setValue(null);
+ assertNull(selectItems.getValue());
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UISelectItems();
+ component.setRendererType(null);
+ return component;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectManyTestCase.java b/impl/src/test/java/jakarta/faces/component/UISelectManyTestCase.java
new file mode 100644
index 0000000000..019f132a87
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectManyTestCase.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.renderkit.SelectItemsIterator;
+
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.model.ListDataModel;
+import jakarta.faces.model.SelectItem;
+import jakarta.faces.model.SelectItemGroup;
+
+/**
+ *
+ * Unit tests for {@link UISelectMany}.
+ *
+ */
+public class UISelectManyTestCase extends UIInputTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UISelectMany();
+ expectedFamily = UISelectMany.COMPONENT_FAMILY;
+ expectedRendererType = "jakarta.faces.Listbox";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test the compareValues() method
+ @Override
+ @Test
+ public void testCompareValues() {
+ SelectManyTestImpl selectMany = new SelectManyTestImpl();
+ Object values1a[] = new Object[] { "foo", "bar", "baz" };
+ Object values1b[] = new Object[] { "foo", "baz", "bar" };
+ Object values1c[] = new Object[] { "baz", "foo", "bar" };
+ Object values2[] = new Object[] { "foo", "bar" };
+ Object values3[] = new Object[] { "foo", "bar", "baz", "bop" };
+ Object values4[] = null;
+
+ assertTrue(!selectMany.compareValues(values1a, values1a));
+ assertTrue(!selectMany.compareValues(values1a, values1b));
+ assertTrue(!selectMany.compareValues(values1a, values1c));
+ assertTrue(!selectMany.compareValues(values2, values2));
+ assertTrue(!selectMany.compareValues(values3, values3));
+ assertTrue(!selectMany.compareValues(values4, values4));
+
+ assertTrue(selectMany.compareValues(values1a, values2));
+ assertTrue(selectMany.compareValues(values1a, values3));
+ assertTrue(selectMany.compareValues(values1a, values4));
+ assertTrue(selectMany.compareValues(values2, values3));
+ assertTrue(selectMany.compareValues(values2, values4));
+ assertTrue(selectMany.compareValues(values4, values1a));
+ assertTrue(selectMany.compareValues(values4, values2));
+ assertTrue(selectMany.compareValues(values4, values3));
+ }
+
+ // Test a pristine UISelectMany instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ UISelectMany selectMany = (UISelectMany) component;
+
+ assertNull(selectMany.getSelectedValues());
+ }
+
+ // Test setting properties to invalid values
+ @Override
+ @Test
+ public void testPropertiesInvalid() throws Exception {
+ super.testPropertiesInvalid();
+ }
+
+ // Test validation of value against the valid list
+ @Test
+ public void testValidation() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.getChildren().add(new UISelectItemSub("foo", null, null));
+ selectMany.getChildren().add(new UISelectItemSub("bar", null, null));
+ selectMany.getChildren().add(new UISelectItemSub("baz", null, null));
+
+ // Validate two values that are on the list
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "foo", "baz" });
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid());
+
+ // Validate one value on the list and one not on the list
+ selectMany.getAttributes().put("label", "mylabel");
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "bar", "bop" });
+ selectMany.setRendererType(null); // We don't have any renderers
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid());
+
+ Iterator messages = facesContext.getMessages();
+ while (messages.hasNext()) {
+ FacesMessage message = messages.next();
+ assertTrue(message.getSummary().indexOf("mylabel") >= 0);
+ }
+ }
+
+ // Test validation of component with UISelectItems pointing to map
+ @Test
+ public void testValidation2() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ Map map = new HashMap<>();
+ map.put("key_foo", "foo");
+ map.put("key_bar", "bar");
+ map.put("key_baz", "baz");
+ UISelectItems items = new UISelectItems();
+ items.setValue(map);
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.getChildren().add(items);
+
+ // Validate two values that are on the list
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "foo", "baz" });
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid());
+
+ // Validate one value on the list and one not on the list
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "bar", "bop" });
+ selectMany.setRendererType(null); // We don't have any renderers
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid());
+ }
+
+ // Test validation of component with UISelectItems pointing to Set and the
+ // value of the component is Set
+ @Test
+ public void testValidation3() throws Exception {
+ Set items = new HashSet<>();
+ items.add(new SelectItem("foo"));
+ items.add(new SelectItem("bar"));
+ items.add(new SelectItem("baz"));
+ Set submittedValues = new HashSet<>();
+ submittedValues.add("bar");
+ submittedValues.add("baz");
+ Set invalidValues = new HashSet<>();
+ invalidValues.add("bar");
+ invalidValues.add("car");
+ testValidateWithCollection(items, submittedValues, invalidValues);
+ }
+
+ // Test validation of component with UISelectItems pointing to List
+ @Test
+ public void testValidation4() throws Exception {
+ List items = new ArrayList<>();
+ items.add(new SelectItem("foo"));
+ items.add(new SelectItem("bar"));
+ items.add(new SelectItem("baz"));
+ List submittedValues = new ArrayList<>();
+ submittedValues.add("bar");
+ submittedValues.add("baz");
+ ArrayList invalidValues = new ArrayList<>();
+ invalidValues.add("bar");
+ invalidValues.add("car");
+ testValidateWithCollection(items, submittedValues, invalidValues);
+ }
+
+ // Test validation of component with UISelectItems pointing to an Array
+ @Test
+ public void testValidation5() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ SelectItem[] itemsArray = { new SelectItem("foo"), new SelectItem("bar"), new SelectItem("baz") };
+ UISelectItems items = new UISelectItems();
+ items.setValue(itemsArray);
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.getChildren().add(items);
+
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new String[] { "bar", "baz" });
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid());
+
+ // Validate one value on the list and one not on the list
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new String[] { "bar", "car" });
+ selectMany.setRendererType(null); // We don't have any renderers
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid());
+ }
+
+ private void testValidateWithCollection(Collection selectItems, Object validValues, Object invalidValues) throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ UISelectItems itemsComponent = new UISelectItems();
+ itemsComponent.setValue(selectItems);
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.setRendererType(null);
+ selectMany.getChildren().add(itemsComponent);
+
+ selectMany.setValue(true);
+ selectMany.setSubmittedValue(validValues);
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid());
+ selectMany.updateModel(facesContext);
+
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(invalidValues);
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid());
+
+ }
+
+ private String legalValues[] = { "A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", "C3" };
+
+ private String illegalValues[] = { "D1", "D2", "Group A", "Group B", "Group C" };
+
+ // Test validation against a nested list of available options
+ @Test
+ public void testValidateNested() throws Exception {
+ // Set up UISelectMany with nested UISelectItems
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UISelectMany selectMany = (UISelectMany) component;
+ UISelectItems selectItems = new UISelectItems();
+ selectItems.setValue(setupOptions());
+ selectMany.getChildren().add(selectItems);
+ selectMany.setRequired(true);
+ checkMessages(0);
+
+ // Verify that all legal values will validate
+ for (int i = 0; i < legalValues.length; i++) {
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { legalValues[0], legalValues[i] });
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid(), "Value '" + legalValues[i] + "' found");
+ checkMessages(0);
+ }
+
+ // Verify that illegal values will not validate
+ for (int i = 0; i < illegalValues.length; i++) {
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { legalValues[0], illegalValues[i] });
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid(), "Value '" + illegalValues[i] + "' not found");
+ checkMessages(i + 1);
+ }
+ }
+
+ // Test validation against a nested Set of available options
+ @Test
+ public void testValidateNestedSet() throws Exception {
+ // Set up UISelectMany with nested UISelectItems
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UISelectMany selectMany = (UISelectMany) component;
+ UISelectItems selectItems = new UISelectItems();
+ selectItems.setValue(setupOptionsSet());
+ selectMany.getChildren().add(selectItems);
+ selectMany.setRequired(true);
+ checkMessages(0);
+
+ // Verify that all legal values will validate
+ for (int i = 0; i < legalValues.length; i++) {
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { legalValues[0], legalValues[i] });
+ selectMany.validate(facesContext);
+ assertTrue(selectMany.isValid(), "Value '" + legalValues[i] + "' found");
+ checkMessages(0);
+ }
+
+ // Verify that illegal values will not validate
+ for (int i = 0; i < illegalValues.length; i++) {
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { legalValues[0], illegalValues[i] });
+ selectMany.validate(facesContext);
+ assertTrue(!selectMany.isValid(), "Value '" + illegalValues[i] + "' not found");
+ checkMessages(i + 1);
+ }
+ }
+
+ // Test validation of a required field
+ @Override
+ @Test
+ public void testValidateRequired() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.getChildren().add(new UISelectItemSub("foo", null, null));
+ selectMany.getChildren().add(new UISelectItemSub("bar", null, null));
+ selectMany.getChildren().add(new UISelectItemSub("baz", null, null));
+ selectMany.setRequired(true);
+ checkMessages(0);
+
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "foo" });
+ selectMany.validate(facesContext);
+ checkMessages(0);
+ assertTrue(selectMany.isValid());
+
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(new Object[] { "" });
+ selectMany.validate(facesContext);
+ checkMessages(1);
+ assertTrue(!selectMany.isValid());
+
+ selectMany.setValid(true);
+ selectMany.setSubmittedValue(null);
+ // this execution of validate shouldn't add any messages to the
+ // queue, since a value of null means "don't validate". This is
+ // different behavior than in previous versions of this
+ // testcase, which expected the UISelectMany.validate() to
+ // operate on the previously validated value, which is not
+ // correct.
+ selectMany.validate(facesContext);
+ checkMessages(1);
+ // since we're setting the submitted value to null, we don't
+ // want validation to occurr, therefore, the valid state of the
+ // componet should be as we left it.
+ assertTrue(selectMany.isValid());
+ }
+
+ @Test
+ public void testSelectItemsIterator() {
+ // sub test 1: non-selectitem at end
+ UISelectMany selectMany = (UISelectMany) component;
+ selectMany.getChildren().add(new UISelectItemSub("orr", null, null));
+ UIParameter param = new UIParameter();
+ param.setName("param");
+ param.setValue("paramValue");
+ selectMany.getChildren().add(param);
+ selectMany.getChildren().add(new UISelectItemSub("esposito", null, null));
+ Iterator iter = new SelectItemsIterator<>(facesContext, selectMany);
+ while (iter.hasNext()) {
+ Object object = iter.next();
+ assertTrue(object instanceof jakarta.faces.model.SelectItem);
+ assertTrue(((SelectItem) object).getValue().equals("orr") || ((SelectItem) object).getValue().equals("esposito"));
+ }
+
+ // sub test 2: non-selectitem in middle
+ selectMany = new UISelectMany();
+ selectMany.getChildren().add(new UISelectItemSub("gretsky", null, null));
+ selectMany.getChildren().add(param);
+ selectMany.getChildren().add(new UISelectItemSub("howe", null, null));
+ iter = new SelectItemsIterator<>(facesContext, selectMany);
+ while (iter.hasNext()) {
+ Object object = iter.next();
+ assertTrue(object instanceof jakarta.faces.model.SelectItem);
+ assertTrue(((SelectItem) object).getValue().equals("gretsky") || ((SelectItem) object).getValue().equals("howe"));
+ }
+
+ // sub test 3: Empty collection
+ selectMany = new UISelectMany();
+ UISelectItems items = new UISelectItems();
+ items.setValue(Collections.emptyList());
+ selectMany.getChildren().add(items);
+ iter = new SelectItemsIterator<>(facesContext, selectMany);
+ assertTrue(!iter.hasNext());
+ try {
+ iter.next();
+ assertTrue(false);
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+
+ // sub test 4: items exposed as generic collection of non-SelectItem
+ // instances
+ Collection cItems = new ArrayList<>(5);
+ Collections.addAll(cItems, 0, 1, 2, 3, 4);
+ selectMany = new UISelectMany();
+ items = new UISelectItems();
+ items.setValue(cItems);
+ selectMany.getChildren().add(items);
+ iter = new SelectItemsIterator<>(facesContext, selectMany);
+ SelectItem previous = null;
+ for (int i = 0, len = cItems.size(); i < len; i++) {
+ assertTrue(iter.hasNext());
+ SelectItem item = iter.next();
+ assertNotNull(item);
+ assertEquals(i, item.getValue());
+ assertEquals(Integer.toString(i), item.getLabel());
+ assertNull(item.getDescription());
+ assertFalse(item.isDisabled());
+ assertTrue(item.isEscape());
+ if (previous != null) {
+ // using fly-weight pattern make sure we use the same
+ // instance through out the iteration
+ assertTrue(item == previous);
+ }
+ previous = item;
+ }
+ assertFalse(iter.hasNext());
+ try {
+ iter.next();
+ assertTrue(false);
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+
+ // sub-test 5: DataModel providing the instances to produce
+ // SelectItems from
+ selectMany = new UISelectMany();
+ items = new UISelectItems();
+ items.setValue(new ListDataModel<>((List) cItems));
+ selectMany.getChildren().add(items);
+ iter = new SelectItemsIterator<>(facesContext, selectMany);
+ previous = null;
+ for (int i = 0, len = cItems.size(); i < len; i++) {
+ assertTrue(iter.hasNext());
+ SelectItem item = iter.next();
+ assertNotNull(item);
+ assertEquals(i, item.getValue());
+ assertEquals(Integer.toString(i), item.getLabel());
+ assertNull(item.getDescription());
+ assertFalse(item.isDisabled());
+ assertTrue(item.isEscape());
+ if (previous != null) {
+ // using fly-weight pattern make sure we use the same
+ // instance through out the iteration
+ assertTrue(item == previous);
+ }
+ previous = item;
+ }
+ assertFalse(iter.hasNext());
+ try {
+ iter.next();
+ assertTrue(false);
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UISelectMany();
+ component.setRendererType(null);
+ return component;
+ }
+
+ @Override
+ protected void setupNewValue(UIInput input) {
+ input.setSubmittedValue(new Object[] { "foo" });
+ UISelectItem si = new UISelectItem();
+ si.setItemValue("foo");
+ si.setItemLabel("foo label");
+ input.getChildren().add(si);
+ }
+
+ // Create an options list with nested groups
+ protected List setupOptions() {
+ SelectItemGroup group, subgroup;
+ subgroup = new SelectItemGroup("Group C");
+ subgroup.setSelectItems(new SelectItem[] { new SelectItem("C1"), new SelectItem("C2"), new SelectItem("C3") });
+ List options = new ArrayList<>();
+ options.add(new SelectItem("A1"));
+ group = new SelectItemGroup("Group B");
+ group.setSelectItems(new SelectItem[] { new SelectItem("B1"), subgroup, new SelectItem("B2"), new SelectItem("B3") });
+
+ options.add(group);
+ options.add(new SelectItem("A2"));
+ options.add(new SelectItem("A3"));
+ return options;
+ }
+
+ // Create an options list with nested groups
+ protected Set setupOptionsSet() {
+ SelectItemGroup group, subgroup;
+ subgroup = new SelectItemGroup("Group C");
+ subgroup.setSelectItems(new SelectItem[] { new SelectItem("C1"), new SelectItem("C2"), new SelectItem("C3") });
+ Set options = new HashSet<>();
+ options.add(new SelectItem("A1"));
+ group = new SelectItemGroup("Group B");
+ group.setSelectItems(new SelectItem[] { new SelectItem("B1"), subgroup, new SelectItem("B2"), new SelectItem("B3") });
+ options.add(group);
+ options.add(new SelectItem("A2"));
+ options.add(new SelectItem("A3"));
+ return options;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UISelectOneTestCase.java b/impl/src/test/java/jakarta/faces/component/UISelectOneTestCase.java
new file mode 100644
index 0000000000..dae1499e7f
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UISelectOneTestCase.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.model.SelectItem;
+import jakarta.faces.model.SelectItemGroup;
+
+/**
+ *
+ * Unit tests for {@link UISelectOne}.
+ *
+ */
+public class UISelectOneTestCase extends UIInputTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UISelectOne();
+ expectedFamily = UISelectOne.COMPONENT_FAMILY;
+ expectedRendererType = "jakarta.faces.Menu";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test validation of value against the valid list
+ @Test
+ public void testValidation() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.getChildren().add(new UISelectItemSub("foo", null, null));
+ selectOne.getChildren().add(new UISelectItemSub("bar", null, null));
+ selectOne.getChildren().add(new UISelectItemSub("baz", null, null));
+
+ // Validate a value that is on the list
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("bar");
+ selectOne.setRendererType(null); // We don't have any renderers
+ selectOne.validate(facesContext);
+ assertTrue(selectOne.isValid());
+
+ // Validate a value that is not on the list
+ selectOne.getAttributes().put("label", "mylabel");
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("bop");
+ selectOne.validate(facesContext);
+ assertTrue(!selectOne.isValid());
+ Iterator messages = facesContext.getMessages();
+ while (messages.hasNext()) {
+ FacesMessage message = messages.next();
+ assertTrue(message.getSummary().indexOf("mylabel") >= 0);
+ }
+ }
+
+ // Test validation of component with UISelectItems pointing to map
+ @Test
+ public void testValidation2() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ Map map = new HashMap<>();
+ map.put("key_foo", "foo");
+ map.put("key_bar", "bar");
+ map.put("key_baz", "baz");
+ UISelectItems items = new UISelectItems();
+ items.setValue(map);
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.getChildren().add(items);
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("foo");
+ selectOne.validate(facesContext);
+ assertTrue(selectOne.isValid());
+
+ // Validate one value on the list and one not on the list
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("car");
+ selectOne.setRendererType(null); // We don't have any renderers
+ selectOne.validate(facesContext);
+ assertTrue(!selectOne.isValid());
+ }
+
+ // Test validation of component with UISelectItems pointing to Set
+ @Test
+ public void testValidation3() throws Exception {
+ Set items = new HashSet<>();
+ items.add(new SelectItem("foo"));
+ items.add(new SelectItem("bar"));
+ items.add(new SelectItem("baz"));
+
+ testValidateWithCollection(items, "bar", "car");
+ }
+
+ // Test validation of component with UISelectItems pointing to List
+ @Test
+ public void testValidation4() throws Exception {
+ List items = new ArrayList<>();
+ items.add(new SelectItem("foo"));
+ items.add(new SelectItem("bar"));
+ items.add(new SelectItem("baz"));
+
+ testValidateWithCollection(items, "bar", "car");
+ }
+
+ // Test validation of component with UISelectItems pointing to an Array
+ @Test
+ public void testValidation5() throws Exception {
+ // Put our component under test in a tree under a UIViewRoot
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ // Add valid options to the component under test
+ SelectItem[] itemsArray = { new SelectItem("foo"), new SelectItem("bar"), new SelectItem("baz") };
+ UISelectItems items = new UISelectItems();
+ items.setValue(itemsArray);
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.getChildren().add(items);
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("foo");
+ selectOne.validate(facesContext);
+ assertTrue(selectOne.isValid());
+
+ // Validate one value on the list and one not on the list
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("car");
+ selectOne.setRendererType(null); // We don't have any renderers
+ selectOne.validate(facesContext);
+ assertTrue(!selectOne.isValid());
+ }
+
+ private void testValidateWithCollection(Collection selectItems, String validValue, String invalidValue) throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+
+ UISelectItems itemsComponent = new UISelectItems();
+ itemsComponent.setValue(selectItems);
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.setRendererType(null);
+ selectOne.getChildren().add(itemsComponent);
+
+ selectOne.setValue(true);
+ selectOne.setSubmittedValue(validValue);
+ selectOne.validate(facesContext);
+ assertTrue(selectOne.isValid());
+ selectOne.updateModel(facesContext);
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue(invalidValue);
+ selectOne.validate(facesContext);
+ assertTrue(!selectOne.isValid());
+ }
+
+ private String legalValues[] = { "A1", "A2", "A3", "B1", "B2", "B3", "C1", "C2", "C3" };
+
+ private String illegalValues[] = { "D1", "D2", "Group A", "Group B", "Group C" };
+
+ // Test validation against a nested list of available options
+ @Test
+ public void testValidateNested() throws Exception {
+ // Set up UISelectOne with nested UISelectItems
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UISelectOne selectOne = (UISelectOne) component;
+ UISelectItems selectItems = new UISelectItems();
+ selectItems.setValue(setupOptions());
+ selectOne.getChildren().add(selectItems);
+ selectOne.setRequired(true);
+ checkMessages(0);
+
+ // Verify that all legal values will validate
+ for (int i = 0; i < legalValues.length; i++) {
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue(legalValues[i]);
+ selectOne.validate(facesContext);
+ assertTrue(selectOne.isValid(), "Value '" + legalValues[i] + "' found");
+ checkMessages(0);
+ }
+
+ // Verify that illegal values will not validate
+ for (int i = 0; i < illegalValues.length; i++) {
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue(illegalValues[i]);
+ selectOne.validate(facesContext);
+ assertTrue(!selectOne.isValid(), "Value '" + illegalValues[i] + "' not found");
+ checkMessages(i + 1);
+ }
+ }
+
+ // Test validation of a required field
+ @Override
+ @Test
+ public void testValidateRequired() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.getChildren().add(component);
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.getChildren().add(new UISelectItemSub("foo", null, null));
+ selectOne.getChildren().add(new UISelectItemSub("bar", null, null));
+ selectOne.getChildren().add(new UISelectItemSub("baz", null, null));
+ selectOne.setRequired(true);
+ checkMessages(0);
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("foo");
+ selectOne.validate(facesContext);
+ checkMessages(0);
+ assertTrue(selectOne.isValid());
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue("");
+ selectOne.validate(facesContext);
+ checkMessages(1);
+ assertTrue(!selectOne.isValid());
+
+ selectOne.setValid(true);
+ selectOne.setSubmittedValue(null);
+ // awiner: see UIInputTestCase
+ selectOne.validate(facesContext);
+ checkMessages(1);
+ assertTrue(selectOne.isValid());
+ }
+
+ @Test
+ public void testSelectItemsIterator() {
+ // sub test 1 : non-selectItem at end
+ UISelectOne selectOne = (UISelectOne) component;
+ selectOne.getChildren().add(new UISelectItemSub("orr", null, null));
+ selectOne.getChildren().add(new UISelectItemSub("esposito", null, null));
+ UIParameter param = new UIParameter();
+ param.setName("param");
+ param.setValue("paramValue");
+ selectOne.getChildren().add(param);
+ Iterator iter = new SelectItemsIterator(facesContext, selectOne);
+ while (iter.hasNext()) {
+ SelectItem selectItem = iter.next();
+ assertTrue(selectItem.getValue().equals("orr") || selectItem.getValue().equals("esposito"));
+ }
+
+ // sub test 2: non-selectitem in middle
+ selectOne = new UISelectOne();
+ selectOne.getChildren().add(new UISelectItemSub("gretsky", null, null));
+ selectOne.getChildren().add(param);
+ selectOne.getChildren().add(new UISelectItemSub("howe", null, null));
+ iter = new SelectItemsIterator(facesContext, selectOne);
+ while (iter.hasNext()) {
+ SelectItem selectItem = iter.next();
+ assertTrue(selectItem.getValue().equals("gretsky") || selectItem.getValue().equals("howe"));
+ }
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UISelectOne();
+ component.setRendererType(null);
+ return component;
+ }
+
+ @Override
+ protected void setupNewValue(UIInput input) {
+ input.setSubmittedValue("foo");
+ UISelectItem si = new UISelectItem();
+ si.setItemValue("foo");
+ si.setItemLabel("foo label");
+ input.getChildren().add(si);
+ }
+
+ // Create an options list with nested groups
+ protected List setupOptions() {
+ SelectItemGroup group, subgroup;
+ subgroup = new SelectItemGroup("Group C");
+ subgroup.setSelectItems(new SelectItem[] { new SelectItem("C1"), new SelectItem("C2"), new SelectItem("C3") });
+ List options = new ArrayList<>();
+ options.add(new SelectItem("A1"));
+ group = new SelectItemGroup("Group B");
+ group.setSelectItems(new SelectItem[] { new SelectItem("B1"), subgroup, new SelectItem("B2"), new SelectItem("B3") });
+ options.add(group);
+ options.add(new SelectItem("A2"));
+ options.add(new SelectItem("A3"));
+ return options;
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIViewRootTest.java b/impl/src/test/java/jakarta/faces/component/UIViewRootTest.java
new file mode 100644
index 0000000000..e6b4d66545
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIViewRootTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.application.Application;
+import jakarta.faces.application.ProjectStage;
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.PostConstructViewMapEvent;
+import jakarta.faces.event.PreDestroyViewMapEvent;
+import jakarta.servlet.http.HttpSession;
+
+public class UIViewRootTest {
+
+ @Test
+ public void testViewMapPostConstructViewMapEvent() {
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ Application application = Mockito.mock(Application.class);
+ ExternalContext externalContext = Mockito.mock(ExternalContext.class);
+ HttpSession httpSession = Mockito.mock(HttpSession.class);
+
+ setFacesContext(facesContext);
+
+ when(facesContext.getExternalContext()).thenReturn(externalContext);
+ when(externalContext.getApplicationMap()).thenReturn(null);
+ UIViewRoot viewRoot = new UIViewRoot();
+
+ when(facesContext.getApplication()).thenReturn(application);
+ when(application.getProjectStage()).thenReturn(ProjectStage.UnitTest);
+ application.publishEvent(facesContext, PostConstructViewMapEvent.class, UIViewRoot.class, viewRoot);
+ Map viewMap = viewRoot.getViewMap();
+ assertNotNull(viewMap);
+
+ setFacesContext(null);
+ }
+
+ @Test
+ public void testViewMapPreDestroyViewMapEvent() {
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ Application application = Mockito.mock(Application.class);
+ ExternalContext externalContext = Mockito.mock(ExternalContext.class);
+ HttpSession httpSession = Mockito.mock(HttpSession.class);
+
+ setFacesContext(facesContext);
+
+ when(facesContext.getExternalContext()).thenReturn(externalContext);
+ when(externalContext.getApplicationMap()).thenReturn(null);
+ UIViewRoot viewRoot = new UIViewRoot();
+
+ when(facesContext.getApplication()).thenReturn(application);
+ when(application.getProjectStage()).thenReturn(ProjectStage.UnitTest);
+ application.publishEvent(facesContext, PostConstructViewMapEvent.class, UIViewRoot.class, viewRoot);
+ when(facesContext.getViewRoot()).thenReturn(viewRoot);
+ application.publishEvent(facesContext, PreDestroyViewMapEvent.class, UIViewRoot.class, viewRoot);
+ when(facesContext.getViewRoot()).thenReturn(viewRoot);
+ application.publishEvent(facesContext, PreDestroyViewMapEvent.class, UIViewRoot.class, viewRoot);
+
+
+ Map viewMap = viewRoot.getViewMap();
+ assertNotNull(viewMap);
+ viewRoot.getViewMap().clear();
+ viewRoot.getViewMap().clear();
+
+
+ setFacesContext(null);
+ }
+
+ @Test
+ public void testViewMapSaveAndRestoreState() {
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ Application application = Mockito.mock(Application.class);
+ ExternalContext externalContext = Mockito.mock(ExternalContext.class);
+ HttpSession httpSession = Mockito.mock(HttpSession.class);
+ HashMap attributes = new HashMap<>();
+ HashMap sessionMap = new HashMap<>();
+
+ setFacesContext(facesContext);
+
+ when(facesContext.getExternalContext()).thenReturn(externalContext);
+ when(externalContext.getApplicationMap()).thenReturn(null);
+ UIViewRoot viewRoot1 = new UIViewRoot();
+
+ when(facesContext.getExternalContext()).thenReturn(externalContext);
+ when(externalContext.getApplicationMap()).thenReturn(null);
+ UIViewRoot viewRoot2 = new UIViewRoot();
+
+ when(facesContext.getAttributes()).thenReturn(attributes);
+ when(facesContext.getApplication()).thenReturn(application);
+ when(application.getProjectStage()).thenReturn(ProjectStage.UnitTest);
+ when(facesContext.getExternalContext()).thenReturn(externalContext);
+ when(externalContext.getSessionMap()).thenReturn(sessionMap);
+ application.publishEvent(facesContext, PostConstructViewMapEvent.class, UIViewRoot.class, viewRoot1);
+ Map viewMap = viewRoot1.getViewMap();
+ viewMap.put("one", "one");
+ Object saved = viewRoot1.saveState(facesContext);
+
+ /*
+ * Simulate our ViewMapListener.
+ */
+ Map viewMaps = new HashMap<>();
+ viewMaps.put((String) viewRoot1.getTransientStateHelper().getTransient("com.sun.faces.application.view.viewMapId"), viewMap);
+ sessionMap.put("com.sun.faces.application.view.activeViewMaps", viewMaps);
+
+ viewRoot2.restoreState(facesContext, saved);
+ viewMap = viewRoot2.getViewMap();
+ assertEquals("one", viewMap.get("one"));
+
+ setFacesContext(null);
+ }
+
+ private void setFacesContext(FacesContext facesContext) {
+ try {
+ Method method = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
+ method.setAccessible(true);
+ method.invoke(null, facesContext);
+ } catch (Exception exception) {
+ exception.printStackTrace(System.err);
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/UIViewRootTestCase.java b/impl/src/test/java/jakarta/faces/component/UIViewRootTestCase.java
new file mode 100644
index 0000000000..8f4b1b8972
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/UIViewRootTestCase.java
@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Locale;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockRenderKit;
+
+import jakarta.el.MethodExpression;
+import jakarta.el.ValueExpression;
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.application.ResourceHandler;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.PhaseEvent;
+import jakarta.faces.event.PhaseId;
+import jakarta.faces.event.PhaseListener;
+import jakarta.faces.event.PostRestoreStateEvent;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+
+/**
+ *
+ * Test case for the jakarta.faces.UIViewRoot concrete class.
+ *
+ */
+public class UIViewRootTestCase extends UIComponentBaseTestCase {
+
+ public static String FACTORIES[][] = { { FactoryFinder.APPLICATION_FACTORY, "com.sun.faces.mock.MockApplicationFactory" },
+ { FactoryFinder.FACES_CONTEXT_FACTORY, "com.sun.faces.mock.MockFacesContextFactory" },
+ { FactoryFinder.LIFECYCLE_FACTORY, "com.sun.faces.mock.MockLifecycleFactory" },
+ { FactoryFinder.RENDER_KIT_FACTORY, "com.sun.faces.mock.MockRenderKitFactory" } };
+
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ FactoryFinder.releaseFactories();
+ super.setUp();
+ for (int i = 0, len = FACTORIES.length; i < len; i++) {
+ System.getProperties().remove(FACTORIES[i][0]);
+ }
+
+ FactoryFinder.releaseFactories();
+ int len, i = 0;
+
+ // simulate the "faces implementation specific" part
+ for (i = 0, len = FACTORIES.length; i < len; i++) {
+ FactoryFinder.setFactory(FACTORIES[i][0], FACTORIES[i][1]);
+ }
+
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.setViewId("/viewId");
+ facesContext.setViewRoot(root);
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = new MockRenderKit();
+ try {
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * Tear down instance variables required by this test case.
+ *
+ * @throws java.lang.Exception
+ */
+ @Override
+ @AfterEach
+ public void tearDown() throws Exception {
+ component = null;
+ super.tearDown();
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testAddGetComponentResources() {
+ application.addComponent("jakarta.faces.ComponentResourceContainer", Container.class.getName());
+ UIViewRoot root = new UIViewRoot();
+ UIOutput resource = new UIOutput();
+
+ // no target argument should result in target being head
+ root.addComponentResource(facesContext, resource);
+ List components = root.getComponentResources(facesContext, "head");
+ assertNotNull(components);
+ assertTrue(components.size() == 1);
+ assertTrue(components.get(0) == resource);
+ UIOutput resource2 = new UIOutput();
+ root.addComponentResource(facesContext, resource2);
+ assertTrue(components.size() == 2);
+ assertTrue(components.get(1) == resource2);
+ root.addComponentResource(facesContext, resource2, "form");
+ components = root.getComponentResources(facesContext, "form");
+ assertTrue(components.size() == 1);
+ root.addComponentResource(facesContext, resource2, "body");
+ components = root.getComponentResources(facesContext, "body");
+ assertTrue(components.size() == 1);
+
+ // the default implementation masks the facet name values
+ // of head and form to ensure there are no collisions with valid
+ // facets by the name. Calling UIViewRoot.getFacet("head") or
+ // get("form") will return null.
+ assertNull(root.getFacet("head"));
+ assertNull(root.getFacet("form"));
+ assertNull(root.getFacet("body"));
+ assertNotNull(root.getFacet("jakarta_faces_location_HEAD"));
+ assertNotNull(root.getFacet("jakarta_faces_location_FORM"));
+ assertNotNull(root.getFacet("jakarta_faces_location_BODY"));
+
+ // custom locations will also be masked
+ root.addComponentResource(facesContext, resource2, "gt");
+ assertNotNull(root.getFacet("jakarta_faces_location_gt"));
+ components = root.getComponentResources(facesContext, "gt");
+ assertTrue(components.size() == 1);
+ }
+
+ // Tests that the resources are rendered again if renderall, @all, is set
+ @Test
+ public void testRenderAllComponentResources() {
+ application.addComponent("jakarta.faces.ComponentResourceContainer", Container.class.getName());
+ UIViewRoot previousRoot = facesContext.getViewRoot();
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ // from partial-request we get the resources added to the ViewRoot
+ facesContext.setViewRoot(root);
+ UIOutput script = new UIOutput();
+ script.getAttributes().putIfAbsent("name", "scriptTest");
+ script.getAttributes().putIfAbsent("library", "scriptLibrary");
+
+ root.addComponentResource(facesContext, script);
+
+ facesContext.getPartialViewContext().setPartialRequest(true);
+ // update @all
+ facesContext.getPartialViewContext().setRenderAll(true);
+
+ final PostRestoreStateEvent postRestoreStateEvent = new PostRestoreStateEvent(root);
+ ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
+
+ postRestoreStateEvent.setComponent(root);
+ root.processEvent(postRestoreStateEvent);
+
+ assertFalse(resourceHandler.isResourceRendered(facesContext, "scriptTest", "scriptLibrary"));
+
+ // partial update i.e. @form
+ facesContext.getPartialViewContext().setRenderAll(false);
+ root.processEvent(postRestoreStateEvent);
+
+ assertTrue(resourceHandler.isResourceRendered(facesContext, "scriptTest", "scriptLibrary"));
+
+ facesContext.getPartialViewContext().setPartialRequest(false);
+ facesContext.getPartialViewContext().setRenderAll(false);
+ facesContext.setViewRoot(previousRoot);
+
+ }
+
+ // Test AbortProcessingException support
+ @Test
+ public void testAbortProcessingException() {
+ // Register three listeners, with the second one set to abort
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ root.addFacesListener(new ListenerTestImpl("a", false));
+ root.addFacesListener(new ListenerTestImpl("b", true));
+ root.addFacesListener(new ListenerTestImpl("c", false));
+
+ // Queue two event and check the results
+ ListenerTestImpl.trace(null);
+ EventTestImpl event1 = new EventTestImpl(root, "1");
+ event1.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event1);
+ EventTestImpl event2 = new EventTestImpl(root, "2");
+ event2.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event2);
+ root.processDecodes(facesContext);
+ assertEquals("/a/1/b/1/a/2/b/2", ListenerTestImpl.trace());
+ }
+
+ // Test event queuing and dequeuing during broadcasting
+ @Test
+ public void testEventBroadcasting() {
+ // Register a listener that will conditionally queue a new event
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+
+ root.addFacesListener(new ListenerTestImpl("t", "2", "4"));
+ ListenerTestImpl.trace(null);
+
+ // Queue some events, including the trigger one
+ EventTestImpl event = new EventTestImpl(root, "1");
+ event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event);
+ event = new EventTestImpl(root, "2");
+ event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event);
+ event = new EventTestImpl(root, "3");
+ event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event);
+
+ // Simulate the Apply Request Values phase
+ root.processDecodes(facesContext);
+
+ // Validate the results (expect 4th event to also be queued)
+ String expected = "/t/1/t/2/t/3/t/4";
+ assertEquals(expected, ListenerTestImpl.trace());
+ }
+
+ // Test event queuing and broadcasting
+ @Test
+ public void testEventQueuing() {
+ // Check for correct ifecycle management processing of event broadcast
+ checkEventQueueing(PhaseId.APPLY_REQUEST_VALUES);
+ checkEventQueueing(PhaseId.PROCESS_VALIDATIONS);
+ checkEventQueueing(PhaseId.UPDATE_MODEL_VALUES);
+ checkEventQueueing(PhaseId.INVOKE_APPLICATION);
+ checkEventQueueing(PhaseId.ANY_PHASE);
+ }
+
+ @Test
+ public void testLocaleFromVB() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ ValueExpression expression = application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{locale}", Object.class);
+ request.setAttribute("locale", Locale.CHINESE);
+ assertEquals(Locale.getDefault(), root.getLocale());
+ root.setValueExpression("locale", expression);
+ assertEquals(Locale.CHINESE, root.getLocale());
+
+ // test locale from String
+ request.setAttribute("locale", "en");
+ assertEquals(new Locale("en"), root.getLocale());
+ request.setAttribute("locale", "en_IE");
+ assertEquals(new Locale("en", "IE"), root.getLocale());
+ request.setAttribute("locale", "en_IE_EURO");
+ assertEquals(new Locale("en", "IE", "EURO"), root.getLocale());
+
+ root.setLocale(Locale.CANADA_FRENCH);
+ assertEquals(Locale.CANADA_FRENCH, root.getLocale());
+ }
+
+ @Test
+ public void testUninitializedInstance() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ assertEquals(jakarta.faces.render.RenderKitFactory.HTML_BASIC_RENDER_KIT, root.getRenderKitId());
+ assertEquals(Locale.getDefault(), root.getLocale());
+ }
+
+ @Test
+ public void testPhaseMethExpression() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseMethodExpression(root, false);
+ }
+
+ @Test
+ public void testPhaseMethExpressionSkipping() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseMethodExpression(root, true);
+ }
+
+ @Test
+ public void testPhaseListener() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseListener(root, false);
+ }
+
+ @Test
+ public void testPhaseListenerSkipping() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseListener(root, true);
+ }
+
+ @Test
+ public void testPhaseMethodExpressionAndListener() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseMethodExpressionAndListener(root, false);
+ }
+
+ @Test
+ public void testPhaseMethodExpressionAndListenerSkipping() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ doTestPhaseMethodExpressionAndListener(root, true);
+ }
+
+ @Test
+ public void testPhaseMethExpressionState() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ Object state = root.saveState(facesContext);
+ root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ root.restoreState(facesContext, state);
+
+ doTestPhaseMethodExpression(root, false);
+ }
+
+ @Test
+ public void testPhaseListenerState() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ Object state = root.saveState(facesContext);
+ root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ root.restoreState(facesContext, state);
+
+ doTestPhaseListener(root, false);
+ }
+
+ @Test
+ public void testPhaseMethodExpressionAndListenerState() throws Exception {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ Object state = root.saveState(facesContext);
+ root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ root.restoreState(facesContext, state);
+
+ doTestPhaseMethodExpressionAndListener(root, false);
+ }
+
+ @Test
+ public void testPhaseListenerExceptions() throws Exception {
+ PhaseId[] ids = { PhaseId.APPLY_REQUEST_VALUES, PhaseId.PROCESS_VALIDATIONS, PhaseId.UPDATE_MODEL_VALUES, PhaseId.INVOKE_APPLICATION,
+ PhaseId.RENDER_RESPONSE };
+ Class>[] args = new Class>[] { PhaseEvent.class };
+ MethodExpression beforeExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(),
+ "#{bean.beforePhase}", null, args);
+ MethodExpression afterExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(),
+ "#{bean.afterPhase}", null, args);
+ for (PhaseId id : ids) {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ PhaseListenerBean bean = new PhaseListenerBean(id, true, false);
+ PhaseListenerBean pl1 = new PhaseListenerBean(id);
+ PhaseListenerBean pl2 = new PhaseListenerBean(id);
+ facesContext.getExternalContext().getRequestMap().put("bean", bean);
+ root.setBeforePhaseListener(beforeExpression);
+ root.setAfterPhaseListener(afterExpression);
+ root.addPhaseListener(pl1);
+ root.addPhaseListener(pl2);
+
+ // validate behavior
+ callRightLifecycleMethodGivenPhaseId(root, id);
+ assertTrue(bean.isBeforePhaseCalled());
+ assertTrue(!bean.isAfterPhaseCalled());
+ assertTrue(!pl1.isBeforePhaseCalled());
+ assertTrue(!pl1.isAfterPhaseCalled());
+ assertTrue(!pl2.isBeforePhaseCalled());
+ assertTrue(!pl2.isAfterPhaseCalled());
+
+ // ensure PLs are invoked properly in the case of exceptions
+ root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ bean = new PhaseListenerBean(id);
+ pl1 = new PhaseListenerBean(id, true, false);
+ pl2 = new PhaseListenerBean(id);
+ facesContext.getExternalContext().getRequestMap().put("bean", bean);
+ root.setBeforePhaseListener(beforeExpression);
+ root.setAfterPhaseListener(afterExpression);
+ root.addPhaseListener(pl1);
+ root.addPhaseListener(pl2);
+
+ // validate behavior
+ callRightLifecycleMethodGivenPhaseId(root, id);
+ assertTrue(bean.isBeforePhaseCalled());
+ assertTrue(bean.isAfterPhaseCalled());
+ assertTrue(pl1.isBeforePhaseCalled());
+ assertTrue(!pl1.isAfterPhaseCalled());
+ assertTrue(!pl2.isBeforePhaseCalled());
+ assertTrue(!pl2.isAfterPhaseCalled());
+ }
+ }
+
+ public void doTestPhaseMethodExpression(UIViewRoot root, boolean skipping) throws Exception {
+ PhaseSkipTestComponent comp = null;
+ if (skipping) {
+ comp = new PhaseSkipTestComponent();
+ root.getChildren().add(comp);
+ facesContext.responseComplete();
+ }
+ doTestPhaseMethodExpressionWithPhaseId(root, PhaseId.APPLY_REQUEST_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isDecodeCalled());
+ }
+ doTestPhaseMethodExpressionWithPhaseId(root, PhaseId.PROCESS_VALIDATIONS);
+ if (skipping) {
+ assertTrue(!comp.isProcessValidatorsCalled());
+ }
+ doTestPhaseMethodExpressionWithPhaseId(root, PhaseId.UPDATE_MODEL_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isProcessUpdatesCalled());
+ }
+ doTestPhaseMethodExpressionWithPhaseId(root, PhaseId.INVOKE_APPLICATION);
+ doTestPhaseMethodExpressionWithPhaseId(root, PhaseId.RENDER_RESPONSE);
+ if (skipping) {
+ assertTrue(!comp.isEncodeBeginCalled());
+ }
+ }
+
+ public void doTestPhaseMethodExpressionWithPhaseId(UIViewRoot root, PhaseId phaseId) throws Exception {
+ PhaseListenerBean phaseListenerBean = new PhaseListenerBean(phaseId);
+ facesContext.getExternalContext().getRequestMap().put("bean", phaseListenerBean);
+ Class>[] args = new Class>[] { PhaseEvent.class };
+ MethodExpression beforeExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(),
+ "#{bean.beforePhase}", null, args),
+ afterExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(), "#{bean.afterPhase}",
+ null, args);
+ root.setBeforePhaseListener(beforeExpression);
+ root.setAfterPhaseListener(afterExpression);
+
+ callRightLifecycleMethodGivenPhaseId(root, phaseId);
+
+ assertTrue(phaseListenerBean.isBeforePhaseCalled());
+ assertTrue(phaseListenerBean.isAfterPhaseCalled());
+ }
+
+ public void doTestPhaseListener(UIViewRoot root, boolean skipping) throws Exception {
+ PhaseSkipTestComponent comp = null;
+ if (skipping) {
+ comp = new PhaseSkipTestComponent();
+ root.getChildren().add(comp);
+ facesContext.responseComplete();
+ }
+ doTestPhaseListenerWithPhaseId(root, PhaseId.APPLY_REQUEST_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isDecodeCalled());
+ }
+ doTestPhaseListenerWithPhaseId(root, PhaseId.PROCESS_VALIDATIONS);
+ if (skipping) {
+ assertTrue(!comp.isProcessValidatorsCalled());
+ }
+ doTestPhaseListenerWithPhaseId(root, PhaseId.UPDATE_MODEL_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isProcessUpdatesCalled());
+ }
+ doTestPhaseListenerWithPhaseId(root, PhaseId.INVOKE_APPLICATION);
+ doTestPhaseListenerWithPhaseId(root, PhaseId.RENDER_RESPONSE);
+ if (skipping) {
+ assertTrue(!comp.isEncodeBeginCalled());
+ }
+ }
+
+ public void doTestPhaseListenerWithPhaseId(UIViewRoot root, PhaseId phaseId) throws Exception {
+ PhaseListenerBean phaseListener = new PhaseListenerBean(phaseId);
+ root.addPhaseListener(phaseListener);
+
+ callRightLifecycleMethodGivenPhaseId(root, phaseId);
+
+ assertTrue(phaseListener.isBeforePhaseCalled());
+ assertTrue(phaseListener.isAfterPhaseCalled());
+ }
+
+ public void doTestPhaseMethodExpressionAndListener(UIViewRoot root, boolean skipping) throws Exception {
+ PhaseSkipTestComponent comp = null;
+ if (skipping) {
+ comp = new PhaseSkipTestComponent();
+ root.getChildren().add(comp);
+ facesContext.responseComplete();
+ }
+ doTestPhaseMethodExpressionAndListenerWithPhaseId(root, PhaseId.APPLY_REQUEST_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isDecodeCalled());
+ }
+ doTestPhaseMethodExpressionAndListenerWithPhaseId(root, PhaseId.PROCESS_VALIDATIONS);
+ if (skipping) {
+ assertTrue(!comp.isProcessValidatorsCalled());
+ }
+ doTestPhaseMethodExpressionAndListenerWithPhaseId(root, PhaseId.UPDATE_MODEL_VALUES);
+ if (skipping) {
+ assertTrue(!comp.isProcessUpdatesCalled());
+ }
+ doTestPhaseMethodExpressionAndListenerWithPhaseId(root, PhaseId.INVOKE_APPLICATION);
+ doTestPhaseMethodExpressionAndListenerWithPhaseId(root, PhaseId.RENDER_RESPONSE);
+ if (skipping) {
+ assertTrue(!comp.isEncodeBeginCalled());
+ }
+ }
+
+ public void doTestPhaseMethodExpressionAndListenerWithPhaseId(UIViewRoot root, PhaseId phaseId) throws Exception {
+ PhaseListenerBean phaseListener = new PhaseListenerBean(phaseId);
+ PhaseListenerBean phaseListenerBean = new PhaseListenerBean(phaseId);
+ facesContext.getExternalContext().getRequestMap().put("bean", phaseListenerBean);
+ Class>[] args = new Class>[] { PhaseEvent.class };
+ MethodExpression beforeExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(),
+ "#{bean.beforePhase}", null, args),
+ afterExpression = facesContext.getApplication().getExpressionFactory().createMethodExpression(facesContext.getELContext(), "#{bean.afterPhase}",
+ null, args);
+ root.setBeforePhaseListener(beforeExpression);
+ root.setAfterPhaseListener(afterExpression);
+ root.addPhaseListener(phaseListener);
+
+ callRightLifecycleMethodGivenPhaseId(root, phaseId);
+
+ assertTrue(phaseListenerBean.isBeforePhaseCalled());
+ assertTrue(phaseListenerBean.isAfterPhaseCalled());
+ assertTrue(phaseListener.isBeforePhaseCalled());
+ assertTrue(phaseListener.isAfterPhaseCalled());
+ }
+
+ private void checkEventQueuesSizes(List events, int applyEventsSize, int valEventsSize, int updateEventsSize,
+ int appEventsSize) {
+ List> applyEvents = events.get(PhaseId.APPLY_REQUEST_VALUES.getOrdinal());
+ assertEquals(applyEventsSize, applyEvents.size());
+ List> valEvents = events.get(PhaseId.PROCESS_VALIDATIONS.getOrdinal());
+ assertEquals(valEventsSize, valEvents.size());
+ List> updateEvents = events.get(PhaseId.UPDATE_MODEL_VALUES.getOrdinal());
+ assertEquals(updateEventsSize, updateEvents.size());
+ List> appEvents = events.get(PhaseId.INVOKE_APPLICATION.getOrdinal());
+ assertEquals(appEventsSize, appEvents.size());
+ }
+
+ // Test Events List Clearing
+ @Test
+ public void testEventsListClear() {
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ EventTestImpl event1, event2, event3, event4 = null;
+ event1 = new EventTestImpl(root, "1");
+ event1.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
+ root.queueEvent(event1);
+ event2 = new EventTestImpl(root, "2");
+ event2.setPhaseId(PhaseId.PROCESS_VALIDATIONS);
+ root.queueEvent(event2);
+ event3 = new EventTestImpl(root, "3");
+ event3.setPhaseId(PhaseId.UPDATE_MODEL_VALUES);
+ root.queueEvent(event3);
+ event4 = new EventTestImpl(root, "4");
+ event4.setPhaseId(PhaseId.INVOKE_APPLICATION);
+ root.queueEvent(event4);
+ final Field fields[] = UIViewRoot.class.getDeclaredFields();
+ Field field = null;
+ List events = null;
+ for (int i = 0; i < fields.length; ++i) {
+ if ("events".equals(fields[i].getName())) {
+ field = fields[i];
+ field.setAccessible(true);
+ try {
+ events = TypedCollections.dynamicallyCastList((List>) field.get(root), List.class);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ break;
+ }
+ }
+ // CASE: renderReponse not set; responseComplete not set;
+ // check for existence of events before processDecodes
+ checkEventQueuesSizes(events, 1, 1, 1, 1);
+ root.processDecodes(facesContext);
+ // there should be no events
+ checkEventQueuesSizes(events, 0, 1, 1, 1);
+
+ // requeue apply request event
+ root.queueEvent(event1);
+ // CASE: renderReponse set;
+ // check for existence of events before processValidators
+ checkEventQueuesSizes(events, 1, 1, 1, 1);
+ facesContext.renderResponse();
+ root.processValidators(facesContext);
+ // there should be no events
+ checkEventQueuesSizes(events, 0, 0, 0, 0);
+
+ // reset FacesContext
+ facesContext.setRenderResponse(false);
+ facesContext.setResponseComplete(false);
+ // requeue all events
+ root.queueEvent(event1);
+ root.queueEvent(event2);
+ root.queueEvent(event3);
+ root.queueEvent(event4);
+ try {
+ events = TypedCollections.dynamicallyCastList((List>) field.get(root), List.class);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ // CASE: response set;
+ // check for existence of events before processValidators
+ checkEventQueuesSizes(events, 1, 1, 1, 1);
+ facesContext.renderResponse();
+ root.processValidators(facesContext);
+ // there should be no events
+ checkEventQueuesSizes(events, 0, 0, 0, 0);
+
+ // reset FacesContext
+ facesContext.setRenderResponse(false);
+ facesContext.setResponseComplete(false);
+ // requeue all events
+ root.queueEvent(event1);
+ root.queueEvent(event2);
+ root.queueEvent(event3);
+ root.queueEvent(event4);
+ try {
+ events = TypedCollections.dynamicallyCastList((List>) field.get(root), List.class);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ // CASE: response complete;
+ // check for existence of events before processUpdates
+ checkEventQueuesSizes(events, 1, 1, 1, 1);
+ facesContext.responseComplete();
+ root.processUpdates(facesContext);
+ // there should be no events
+ checkEventQueuesSizes(events, 0, 0, 0, 0);
+
+ // reset FacesContext
+ facesContext.setRenderResponse(false);
+ facesContext.setResponseComplete(false);
+ // requeue all events
+ root.queueEvent(event1);
+ root.queueEvent(event2);
+ root.queueEvent(event3);
+ root.queueEvent(event4);
+ try {
+ events = TypedCollections.dynamicallyCastList((List>) field.get(root), List.class);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ // CASE: response complete;
+ // check for existence of events before processApplication
+ checkEventQueuesSizes(events, 1, 1, 1, 1);
+ facesContext.responseComplete();
+ root.processApplication(facesContext);
+ // there should be no events
+ checkEventQueuesSizes(events, 0, 0, 0, 0);
+
+ // finally, get the internal events list one more time
+ // to make sure it is null
+ try {
+ events = TypedCollections.dynamicallyCastList((List>) field.get(root), List.class);
+ } catch (Exception e) {
+ assertTrue(false);
+ }
+ assertNull(events);
+ }
+
+ private void callRightLifecycleMethodGivenPhaseId(UIViewRoot root, PhaseId phaseId) throws Exception {
+ if (phaseId.getOrdinal() == PhaseId.APPLY_REQUEST_VALUES.getOrdinal()) {
+ root.processDecodes(facesContext);
+ } else if (phaseId.getOrdinal() == PhaseId.PROCESS_VALIDATIONS.getOrdinal()) {
+ root.processValidators(facesContext);
+ } else if (phaseId.getOrdinal() == PhaseId.UPDATE_MODEL_VALUES.getOrdinal()) {
+ root.processUpdates(facesContext);
+ } else if (phaseId.getOrdinal() == PhaseId.INVOKE_APPLICATION.getOrdinal()) {
+ root.processApplication(facesContext);
+ } else if (phaseId.getOrdinal() == PhaseId.RENDER_RESPONSE.getOrdinal()) {
+ root.encodeBegin(facesContext);
+ root.encodeEnd(facesContext);
+ }
+ }
+
+ // --------------------------------------------------------- Support Methods
+ private void checkEventQueueing(PhaseId phaseId) {
+
+ // NOTE: Current semantics for ANY_PHASE listeners is that
+ // the event should be delivered exactly once, so the existence
+ // of such a listener does not cause the event to remain queued.
+ // Therefore, the expected string is the same as for any
+ // phase-specific listener, and it should get matched after
+ // Apply Request Values processing since that is first phase
+ // for which events are fired
+ // Register an event listener for the specified phase id
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ facesContext.setViewRoot(root);
+ EventTestImpl event = null;
+ ListenerTestImpl listener = new ListenerTestImpl("t");
+ root.addFacesListener(listener);
+
+ // Queue some events to be processed
+ event = new EventTestImpl(root, "1");
+ event.setPhaseId(phaseId);
+ root.queueEvent(event);
+ event = new EventTestImpl(root, "2");
+ event.setPhaseId(phaseId);
+ root.queueEvent(event);
+ String expected = "/t/1/t/2";
+
+ // Fire off the relevant lifecycle methods and check expected results
+ ListenerTestImpl.trace(null);
+ assertEquals("", ListenerTestImpl.trace());
+ root.processDecodes(facesContext);
+ if (PhaseId.APPLY_REQUEST_VALUES.equals(phaseId) || PhaseId.ANY_PHASE.equals(phaseId)) {
+ assertEquals(expected, ListenerTestImpl.trace());
+ } else {
+ assertEquals("", ListenerTestImpl.trace());
+ }
+ root.processValidators(facesContext);
+ if (PhaseId.PROCESS_VALIDATIONS.equals(phaseId) || PhaseId.APPLY_REQUEST_VALUES.equals(phaseId) || PhaseId.APPLY_REQUEST_VALUES.equals(phaseId)
+ || PhaseId.ANY_PHASE.equals(phaseId)) {
+ assertEquals(expected, ListenerTestImpl.trace());
+ } else {
+ assertEquals("", ListenerTestImpl.trace());
+ }
+ root.processUpdates(facesContext);
+ if (PhaseId.UPDATE_MODEL_VALUES.equals(phaseId) || PhaseId.PROCESS_VALIDATIONS.equals(phaseId) || PhaseId.APPLY_REQUEST_VALUES.equals(phaseId)
+ || PhaseId.ANY_PHASE.equals(phaseId)) {
+ assertEquals(expected, ListenerTestImpl.trace());
+ } else {
+ assertEquals("", ListenerTestImpl.trace());
+ }
+ root.processApplication(facesContext);
+ assertEquals(expected, ListenerTestImpl.trace());
+ }
+
+ // These overrides are necessary because our normal setup
+ // calls releaseFactories, which makes it impossible to get clientIds.
+ @Override
+ @Test
+ public void testInvokeOnComponentPositive() throws Exception {
+ super.setUp();
+ super.testInvokeOnComponentPositive();
+ }
+
+ @Override
+ @Test
+ public void testInvokeOnComponentNegative() throws Exception {
+ super.setUp();
+ super.testInvokeOnComponentNegative();
+ }
+
+ @Override
+ @Test
+ public void testInvokeOnComponentWithPrependId() throws Exception {
+ super.setUp();
+ super.testInvokeOnComponentWithPrependId();
+ }
+
+ @Override
+ @Test
+ public void testChildrenListAfterAddViewPublish() {
+ // overridding to do nothing. UIViewRoot is a special cases
+ // and there should always only be on UIViewRoot in a tree
+ }
+
+ @Override
+ @Test
+ public void testFacetMapAfterAddViewPublish() {
+ // overridding to do nothing. UIViewRoot is a special cases
+ // and there should always only be on UIViewRoot in a tree
+ }
+
+ // Check that the properties on the specified components are equal
+ @Override
+ protected void checkProperties(UIComponent comp1, UIComponent comp2) {
+ super.checkProperties(comp1, comp2);
+ UIViewRoot vr1 = (UIViewRoot) comp1;
+ UIViewRoot vr2 = (UIViewRoot) comp2;
+ assertEquals(vr2.getRenderKitId(), vr2.getRenderKitId());
+ assertEquals(vr1.getViewId(), vr2.getViewId());
+ assertEquals(vr1.getLocale(), vr2.getLocale());
+ }
+
+ // Create a pristine component of the type to be used in state holder tests
+ @Override
+ protected UIComponent createComponent() {
+ UIComponent component = new UIViewRoot();
+ component.setRendererType(null);
+ return component;
+ }
+
+ public static class PhaseListenerBean extends Object implements PhaseListener {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean beforePhaseCalled = false;
+ private boolean afterPhaseCalled = false;
+ private PhaseId phaseId = null;
+ private boolean exceptionBefore;
+ private boolean exceptionAfter;
+
+ public PhaseListenerBean(PhaseId phaseId) {
+ this.phaseId = phaseId;
+ }
+
+ public PhaseListenerBean(PhaseId phaseId, boolean exceptionBefore, boolean exceptionAfter) {
+ this(phaseId);
+ this.exceptionBefore = exceptionBefore;
+ this.exceptionAfter = exceptionAfter;
+ }
+
+ public boolean isBeforePhaseCalled() {
+ return beforePhaseCalled;
+ }
+
+ public boolean isAfterPhaseCalled() {
+ return afterPhaseCalled;
+ }
+
+ @Override
+ public void beforePhase(PhaseEvent e) {
+ beforePhaseCalled = true;
+ if (exceptionBefore) {
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public void afterPhase(PhaseEvent e) {
+ afterPhaseCalled = true;
+ if (exceptionAfter) {
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ public PhaseId getPhaseId() {
+ return phaseId;
+ }
+ }
+
+ public static class PhaseSkipTestComponent extends UIInput {
+
+ private boolean decodeCalled = false;
+
+ @Override
+ public void decode(FacesContext context) {
+ decodeCalled = true;
+ }
+
+ public boolean isDecodeCalled() {
+ return decodeCalled;
+ }
+
+ private boolean encodeBeginCalled = false;
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException {
+ encodeBeginCalled = true;
+ }
+
+ public boolean isEncodeBeginCalled() {
+ return encodeBeginCalled;
+ }
+
+ private boolean processValidatorsCalled = false;
+
+ @Override
+ public void processValidators(FacesContext context) {
+ processValidatorsCalled = true;
+ }
+
+ public boolean isProcessValidatorsCalled() {
+ return processValidatorsCalled;
+ }
+
+ private boolean processUpdatesCalled = false;
+
+ @Override
+ public void processUpdates(FacesContext context) {
+ processUpdatesCalled = true;
+ }
+
+ public boolean isProcessUpdatesCalled() {
+ return processUpdatesCalled;
+ }
+ }
+
+ public static class Container extends UIPanel {
+
+ @Override
+ public void encodeAll(FacesContext context) throws IOException {
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/component/ValueHolderTestCaseBase.java b/impl/src/test/java/jakarta/faces/component/ValueHolderTestCaseBase.java
new file mode 100644
index 0000000000..0e7bda4afc
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/component/ValueHolderTestCaseBase.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.component;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.html.HtmlInputText;
+import jakarta.faces.convert.LongConverter;
+import jakarta.faces.convert.NumberConverter;
+import jakarta.faces.convert.ShortConverter;
+
+/**
+ *
+ * Unit tests for {@link ValueHolder}. Any test case for a component class that implements {@link ValueHolder} should
+ * extend this class.
+ *
+ */
+public abstract class ValueHolderTestCaseBase extends UIComponentBaseTestCase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ component = new UIOutput();
+ expectedId = null;
+ expectedRendererType = "Text";
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testAttributesTransparencyNonDeterministic() throws Exception {
+ final int numThreads = 30;
+ final Boolean outcomes[] = new Boolean[numThreads];
+ Runnable runnables[] = new Runnable[numThreads];
+ int i = 0;
+
+ for (i = 0; i < outcomes.length; i++) {
+ outcomes[i] = null;
+ }
+
+ for (i = 0; i < runnables.length; i++) {
+ runnables[i] = new Runnable() {
+ @Override
+ public void run() {
+ int threadNum = 0;
+ try {
+ threadNum = Integer.valueOf(Thread.currentThread().getName()).intValue();
+ } catch (NumberFormatException ex) {
+ fail("Expected thread name to be an integer");
+ }
+ // Even threadNums use HtmlInputText, odd use this component
+ boolean isEven = threadNum % 2 == 0;
+ ValueHolder vh = null;
+ UIComponent newComp = null;
+ if (isEven) {
+ newComp = new HtmlInputText();
+ vh = (ValueHolder) newComp;
+ } else {
+ try {
+ newComp = ValueHolderTestCaseBase.this.component.getClass().getDeclaredConstructor()
+ .newInstance();
+ vh = (ValueHolder) newComp;
+
+ } catch (IllegalArgumentException | ReflectiveOperationException | SecurityException ex) {
+ fail("Can't instantiate class of " + ValueHolderTestCaseBase.this.component.getClass().getName());
+ }
+ }
+ try {
+ boolean result = doTestAttributesTransparency(vh, newComp);
+ outcomes[threadNum] = Boolean.valueOf(result);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ outcomes[threadNum] = Boolean.FALSE;
+ }
+ }
+ };
+ }
+// clearDescriptors();
+ Thread thread = null;
+ for (i = 0; i < runnables.length; i++) {
+ thread = new Thread(runnables[i], "" + i);
+ thread.start();
+ }
+
+ // Keep polling the outcomes array until there are no nulls.
+ boolean foundNull = false;
+ while (!foundNull) {
+ for (i = 0; i < outcomes.length; i++) {
+ if (null != outcomes[i]) {
+ foundNull = true;
+ }
+ }
+ Thread.sleep(500);
+ }
+
+ for (i = 0; i < outcomes.length; i++) {
+ if (!outcomes[i].booleanValue()) {
+ fail("Thread " + i + " failed");
+ }
+ }
+ }
+
+ @Override
+ @Test
+ public void testAttributesTransparency() {
+ super.testAttributesTransparency();
+ ValueHolder vh = (ValueHolder) component;
+ doTestAttributesTransparency(vh, component);
+ }
+
+ // Test attribute-property transparency
+ public boolean doTestAttributesTransparency(ValueHolder vh, UIComponent newComp) {
+ assertEquals(vh.getValue(), newComp.getAttributes().get("value"));
+ vh.setValue("foo");
+ assertEquals("foo", newComp.getAttributes().get("value"));
+ vh.setValue(null);
+ assertNull(newComp.getAttributes().get("value"));
+ newComp.getAttributes().put("value", "bar");
+ assertEquals("bar", vh.getValue());
+ newComp.getAttributes().put("value", null);
+ assertNull(vh.getValue());
+
+ assertEquals(vh.getConverter(), newComp.getAttributes().get("converter"));
+ vh.setConverter(new LongConverter());
+ assertNotNull(newComp.getAttributes().get("converter"));
+ assertTrue(newComp.getAttributes().get("converter") instanceof LongConverter);
+ vh.setConverter(null);
+ assertNull(newComp.getAttributes().get("converter"));
+ newComp.getAttributes().put("converter", new ShortConverter());
+ assertNotNull(vh.getConverter());
+ assertTrue(vh.getConverter() instanceof ShortConverter);
+ newComp.getAttributes().put("converter", null);
+ assertNull(vh.getConverter());
+
+ return true;
+ }
+
+ // Suppress lifecycle tests since we do not have a renderer
+ @Override
+ @Test
+ public void testLifecycleManagement() {
+ }
+
+ // Test a pristine ValueHolderBase instance
+ @Override
+ @Test
+ public void testPristine() {
+ super.testPristine();
+ ValueHolder vh = (ValueHolder) component;
+
+ // Validate properties
+ assertNull(vh.getValue());
+ assertNull(vh.getConverter());
+ }
+
+ // Test setting properties to valid values
+ @Override
+ @Test
+ public void testPropertiesValid() throws Exception {
+ super.testPropertiesValid();
+ ValueHolder vh = (ValueHolder) component;
+
+ // value
+ vh.setValue("foo.bar");
+ assertEquals("foo.bar", vh.getValue());
+ vh.setValue(null);
+ assertNull(vh.getValue());
+
+ // converter
+ vh.setConverter(new LongConverter());
+ assertTrue(vh.getConverter() instanceof LongConverter);
+ vh.setConverter(null);
+ assertNull(vh.getConverter());
+ }
+
+ // --------------------------------------------------------- Support Methods
+ // Check that the properties of the NumberConverters are equal
+ protected void checkNumberConverter(NumberConverter nc1, NumberConverter nc2) {
+ assertEquals(nc1.getCurrencyCode(), nc2.getCurrencyCode());
+ assertEquals(nc1.getCurrencySymbol(), nc2.getCurrencySymbol());
+ assertEquals(nc1.isGroupingUsed(), nc2.isGroupingUsed());
+ assertEquals(nc1.isIntegerOnly(), nc2.isIntegerOnly());
+ assertEquals(nc1.getMaxFractionDigits(), nc2.getMaxFractionDigits());
+ assertEquals(nc1.getMaxIntegerDigits(), nc2.getMaxIntegerDigits());
+ assertEquals(nc1.getMinFractionDigits(), nc2.getMinFractionDigits());
+ assertEquals(nc1.getMinIntegerDigits(), nc2.getMinIntegerDigits());
+ assertEquals(nc1.getLocale(), nc2.getLocale());
+ assertEquals(nc1.getPattern(), nc2.getPattern());
+ assertEquals(nc1.getType(), nc2.getType());
+ }
+
+ // Check that the properties on the specified components are equal
+ @Override
+ protected void checkProperties(UIComponent comp1, UIComponent comp2) {
+ super.checkProperties(comp1, comp2);
+ ValueHolder vh1 = (ValueHolder) comp1;
+ ValueHolder vh2 = (ValueHolder) comp2;
+ assertEquals(vh1.getValue(), vh2.getValue());
+ checkNumberConverter((NumberConverter) vh1.getConverter(), (NumberConverter) vh2.getConverter());
+ }
+
+ // Create and configure a NumberConverter
+ protected NumberConverter createNumberConverter() {
+ NumberConverter nc = new NumberConverter();
+ nc.setCurrencyCode("USD");
+ nc.setCurrencySymbol("$");
+ nc.setGroupingUsed(false);
+ nc.setIntegerOnly(true);
+ nc.setMaxFractionDigits(2);
+ nc.setMaxIntegerDigits(10);
+ nc.setMinFractionDigits(2);
+ nc.setMinIntegerDigits(5);
+ nc.setType("currency");
+ return nc;
+ }
+
+ protected void checkNumberConverters(NumberConverter nc1, NumberConverter nc2) {
+ assertNotNull(nc1);
+ assertNotNull(nc2);
+ assertEquals(nc1.getCurrencyCode(), nc2.getCurrencyCode());
+ assertEquals(nc1.getCurrencySymbol(), nc2.getCurrencySymbol());
+ assertEquals(nc1.isGroupingUsed(), nc2.isGroupingUsed());
+ assertEquals(nc1.isIntegerOnly(), nc2.isIntegerOnly());
+ assertEquals(nc1.getMaxFractionDigits(), nc2.getMaxFractionDigits());
+ assertEquals(nc1.getMaxIntegerDigits(), nc2.getMaxIntegerDigits());
+ assertEquals(nc1.getMinFractionDigits(), nc2.getMinFractionDigits());
+ assertEquals(nc1.getMinIntegerDigits(), nc2.getMinIntegerDigits());
+ assertEquals(nc1.getLocale(), nc2.getLocale());
+ assertEquals(nc1.getPattern(), nc2.getPattern());
+ assertEquals(nc1.getType(), nc2.getType());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/BigIntegerConverterTest.java b/impl/src/test/java/jakarta/faces/convert/BigIntegerConverterTest.java
new file mode 100644
index 0000000000..70f8a6c468
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/BigIntegerConverterTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.math.BigInteger;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the BigIntegerConverter class.
+ */
+public class BigIntegerConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(BigInteger.valueOf(123), converter.getAsObject(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ BigIntegerConverter converter = new BigIntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), BigInteger.valueOf(123)));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/DoubleConverterTest.java b/impl/src/test/java/jakarta/faces/convert/DoubleConverterTest.java
new file mode 100644
index 0000000000..976600b158
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/DoubleConverterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the DoubleConverter class.
+ */
+public class DoubleConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ DoubleConverter converter = new DoubleConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(Double.valueOf("12.3"), converter.getAsObject(facesContext, new UIPanel(), "12.3"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ DoubleConverter converter = new DoubleConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("12.3", converter.getAsString(facesContext, new UIPanel(), "12.3"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ DoubleConverter converter = new DoubleConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("12.3", converter.getAsString(facesContext, new UIPanel(), Double.valueOf("12.3")));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/FloatConverterTest.java b/impl/src/test/java/jakarta/faces/convert/FloatConverterTest.java
new file mode 100644
index 0000000000..446940f431
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/FloatConverterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the FloatConverter class.
+ */
+public class FloatConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ FloatConverter converter = new FloatConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(Float.valueOf("12.3"), converter.getAsObject(facesContext, new UIPanel(), "12.3"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ FloatConverter converter = new FloatConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("12.3", converter.getAsString(facesContext, new UIPanel(), "12.3"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ FloatConverter converter = new FloatConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("12.3", converter.getAsString(facesContext, new UIPanel(), Float.valueOf("12.3")));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/IntegerConverterTest.java b/impl/src/test/java/jakarta/faces/convert/IntegerConverterTest.java
new file mode 100644
index 0000000000..4427b9441d
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/IntegerConverterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the IntegerConverter class.
+ */
+public class IntegerConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ IntegerConverter converter = new IntegerConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(Integer.valueOf("123"), converter.getAsObject(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ IntegerConverter converter = new IntegerConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ IntegerConverter converter = new IntegerConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), Integer.valueOf("123")));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/LongConverterTest.java b/impl/src/test/java/jakarta/faces/convert/LongConverterTest.java
new file mode 100644
index 0000000000..27e7f8fa6f
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/LongConverterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the LongConverter class.
+ */
+public class LongConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ LongConverter converter = new LongConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(Long.valueOf("123"), converter.getAsObject(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ LongConverter converter = new LongConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ LongConverter converter = new LongConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), Long.valueOf("123")));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/convert/ShortConverterTest.java b/impl/src/test/java/jakarta/faces/convert/ShortConverterTest.java
new file mode 100644
index 0000000000..5223c7cb6d
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/convert/ShortConverterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.convert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.context.FacesContext;
+
+/**
+ * The JUnit tests for the ShortConverter class.
+ */
+public class ShortConverterTest {
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject() {
+ ShortConverter converter = new ShortConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsObject(null, null, null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject2() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject3() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertNull(converter.getAsObject(facesContext, new UIPanel(), " "));
+ }
+
+ /**
+ * Test getAsObject method.
+ */
+ @Test
+ public void testGetAsObject4() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals(Short.valueOf("123"), converter.getAsObject(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString() {
+ ShortConverter converter = new ShortConverter();
+ assertThrows(NullPointerException.class, () -> converter.getAsString(null, null, null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString2() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("", converter.getAsString(facesContext, new UIPanel(), null));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString3() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), "123"));
+ }
+
+ /**
+ * Test getAsString method.
+ */
+ @Test
+ public void testGetAsString4() {
+ ShortConverter converter = new ShortConverter();
+ FacesContext facesContext = Mockito.mock(FacesContext.class);
+ assertEquals("123", converter.getAsString(facesContext, new UIPanel(), Short.valueOf("123")));
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/event/PhaseIdTest.java b/impl/src/test/java/jakarta/faces/event/PhaseIdTest.java
new file mode 100644
index 0000000000..bbc23c5445
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/event/PhaseIdTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.event;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Iterator;
+
+import org.junit.jupiter.api.Test;
+
+public class PhaseIdTest {
+
+ @Test
+ public void testToString() {
+ Iterator valueIter = PhaseId.VALUES.iterator();
+ String cur = null;
+ while (valueIter.hasNext()) {
+ cur = valueIter.next().toString();
+ System.out.println(cur);
+ assertTrue(cur.length() > 3);
+ }
+
+ }
+
+} // end of class PhaseIdTest
diff --git a/impl/src/test/java/jakarta/faces/model/ArrayDataModelTestCase.java b/impl/src/test/java/jakarta/faces/model/ArrayDataModelTestCase.java
new file mode 100644
index 0000000000..2e179c117a
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/ArrayDataModelTestCase.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * Unit tests for {@link ArrayDataModel}.
+ */
+public class ArrayDataModelTestCase extends DataModelTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ beans = new BeanTestImpl[5];
+ for (int i = 0; i < beans.length; i++) {
+ beans[i] = new BeanTestImpl();
+ }
+ configure();
+ model = new ArrayDataModel(beans);
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // ------------------------------------------------------- Protected Methods
+}
diff --git a/impl/src/test/java/jakarta/faces/model/CollectionDataModelTest.java b/impl/src/test/java/jakarta/faces/model/CollectionDataModelTest.java
new file mode 100644
index 0000000000..bc33faa3f3
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/CollectionDataModelTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * The JUnit tests for CollectionDataModel.
+ *
+ * @author Manfred Riem
+ */
+public class CollectionDataModelTest {
+
+ /**
+ * Test getWrappedData method.
+ */
+ @Test
+ public void testGetWrappedData() {
+ CollectionDataModel model = new CollectionDataModel<>();
+ assertNull(model.getWrappedData());
+ ArrayList list = new ArrayList<>();
+ model.setWrappedData(list);
+ assertNotNull(model.getWrappedData());
+ model.setWrappedData(null);
+ assertNull(model.getWrappedData());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/model/DataModelTestCaseBase.java b/impl/src/test/java/jakarta/faces/model/DataModelTestCaseBase.java
new file mode 100644
index 0000000000..c522afbe73
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/DataModelTestCaseBase.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Abstract base class for {@link DataModel} tests.
+ */
+public abstract class DataModelTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // The array of beans we will be wrapping (must be initialized before setUp)
+ protected BeanTestImpl beans[] = new BeanTestImpl[0];
+
+ // The DataModel we are testing
+ protected DataModel> model = null;
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Configure the properties of the beans we will be wrapping
+ protected void configure() {
+ for (int i = 0; i < beans.length; i++) {
+ BeanTestImpl bean = beans[i];
+ bean.setBooleanProperty((i % 2) == 0);
+ bean.setBooleanSecond(!bean.getBooleanProperty());
+ bean.setByteProperty((byte) i);
+ bean.setDoubleProperty(i * 100.0);
+ bean.setFloatProperty(i * ((float) 10.0));
+ bean.setIntProperty(1000 * i);
+ bean.setLongProperty((long) 10000 * (long) i);
+ bean.setStringProperty("This is string " + i);
+ }
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+
+ // Test invalid arguments to listener methods
+ @Test
+ public void testInvalidListeners() throws Exception {
+ try {
+ model.addDataModelListener(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+
+ try {
+ model.removeDataModelListener(null);
+ fail("Should have thrown NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected result
+ }
+ }
+
+ // Test positioning to all rows in ascending order
+ @Test
+ public void testPositionAscending() throws Exception {
+ StringBuilder sb = new StringBuilder();
+ model.setRowIndex(-1);
+ model.addDataModelListener(new ListenerTestImpl());
+ ListenerTestImpl.trace(null);
+
+ int n = model.getRowCount();
+ for (int i = 0; i < n; i++) {
+ checkRow(i);
+ sb.append('/').append(i);
+ }
+ assertEquals(sb.toString(), ListenerTestImpl.trace());
+ }
+
+ // Test positioning to all rows in descending order
+ @Test
+ public void testPositionDescending() throws Exception {
+ StringBuilder sb = new StringBuilder();
+ model.setRowIndex(-1);
+ model.addDataModelListener(new ListenerTestImpl());
+ ListenerTestImpl.trace(null);
+
+ int n = model.getRowCount();
+ for (int i = (n - 1); i >= 0; i--) {
+ checkRow(i);
+ sb.append('/').append(i);
+ }
+ assertEquals(sb.toString(), ListenerTestImpl.trace());
+ }
+
+ // Test a pristine DataModel instance
+ @Test
+ public void testPristine() throws Exception {
+ // Unopened instance
+ assertNotNull(beans);
+ assertNotNull(model);
+
+ // Correct row count
+ if (model instanceof ResultSetDataModel) {
+ assertEquals(-1, model.getRowCount());
+ } else {
+ assertEquals(beans.length,
+ model.getRowCount());
+ }
+
+ // Correct row index
+ assertEquals(0, model.getRowIndex());
+ }
+
+ // Test removing listener
+ @Test
+ public void testRemoveListener() throws Exception {
+ ListenerTestImpl listener = new ListenerTestImpl();
+ ListenerTestImpl.trace(null);
+ model.addDataModelListener(listener);
+ model.setRowIndex(-1);
+ model.setRowIndex(0);
+ model.setRowIndex(0); // No movement so no event
+ model.setRowIndex(-1);
+ model.removeDataModelListener(listener);
+ model.setRowIndex(0);
+ assertEquals("/-1/0/-1", ListenerTestImpl.trace());
+ }
+
+ // Test resetting the wrapped data (should trigger an event
+ @Test
+ public void testReset() throws Exception {
+ ListenerTestImpl listener = new ListenerTestImpl();
+ ListenerTestImpl.trace(null);
+ model.addDataModelListener(listener);
+
+ assertEquals(0, model.getRowIndex());
+ model.setWrappedData(model.getWrappedData());
+ assertEquals("/0", ListenerTestImpl.trace());
+ }
+
+ // Test row available manipulations
+ @Test
+ public void testRowAvailable() throws Exception {
+ // Position to the "no current row" position
+ model.setRowIndex(-1);
+ assertTrue(!model.isRowAvailable());
+
+ // Position to an arbitrarily high row number
+ model.setRowIndex(beans.length);
+ assertTrue(!model.isRowAvailable());
+
+ // Position to a known good row number
+ model.setRowIndex(0);
+ assertTrue(model.isRowAvailable());
+ }
+
+ // Test the ability to update through the Map returned by getRowData()
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testRowData() throws Exception {
+ // Retrieve the row data for row zero
+ model.setRowIndex(0);
+ Object data = model.getRowData();
+ assertNotNull(data);
+
+ // Modify several property values
+ BeanTestImpl bean = beans[0];
+ bean.setBooleanProperty(!bean.getBooleanProperty());
+ if (data instanceof Map) {
+ ((Map) data).put("booleanProperty",
+ bean.getBooleanProperty()
+ ? Boolean.TRUE : Boolean.FALSE);
+ } else {
+ Method m = data.getClass().getMethod("setBooleanProperty", Boolean.TYPE);
+ m.invoke(data, bean.getBooleanProperty() ? Boolean.TRUE : Boolean.FALSE);
+ }
+ bean.setIntProperty(bean.getIntProperty() + 5);
+ if (data instanceof Map) {
+ ((Map) data).put("intProperty",
+ bean.getIntProperty());
+ } else {
+ Method m = data.getClass().getMethod("setIntProperty", Integer.TYPE);
+ m.invoke(data, bean.getIntProperty());
+ }
+ bean.setStringProperty(bean.getStringProperty() + "XYZ");
+ if (data instanceof Map) {
+ ((Map) data).put("stringProperty",
+ bean.getStringProperty() + "XYZ");
+ } else {
+ Method m = data.getClass().getMethod("setStringProperty", String.class);
+ m.invoke(data, bean.getStringProperty());
+ }
+
+ // Ensure that all the modifications flowed through to beans[0]
+ assertEquals(bean.getBooleanProperty(),
+ beans[0].getBooleanProperty());
+ assertEquals(bean.isBooleanSecond(),
+ beans[0].isBooleanSecond());
+ assertEquals(bean.getByteProperty(),
+ beans[0].getByteProperty());
+ assertEquals(bean.getDoubleProperty(),
+ beans[0].getDoubleProperty(), 0.005);
+ assertEquals(bean.getFloatProperty(),
+ beans[0].getFloatProperty(), (float) 0.005);
+ assertEquals(bean.getIntProperty(),
+ beans[0].getIntProperty());
+ assertEquals(bean.getLongProperty(),
+ beans[0].getLongProperty());
+ assertEquals(bean.getStringProperty(),
+ beans[0].getStringProperty());
+ }
+
+ // Test row index manipulations
+ @Test
+ public void testRowIndex() throws Exception {
+ assertEquals(0, model.getRowIndex());
+
+ // Positive setRowIndex() tests
+ model.setRowIndex(0);
+ model.setRowIndex(-1);
+
+ // Negative setRowIndex() tests
+ try {
+ model.setRowIndex(-2);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected result
+ }
+ }
+
+ @Test
+ public void testIterator() {
+ Iterator> iterator = model.iterator();
+ if (!(model instanceof ScalarDataModel)) {
+ for (int i = 0; i < 5; i++) {
+ System.out.println("Index: " + i);
+ assertTrue(iterator.hasNext());
+ assertNotNull(iterator.next());
+ }
+ } else {
+ assertTrue(iterator.hasNext());
+ assertNotNull(iterator.next());
+ }
+
+ assertTrue(!iterator.hasNext());
+ try {
+ iterator.next();
+ assertTrue(false);
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+ }
+
+ // Test resetting the wrapped data to null
+ @Test
+ public void testWrapped() throws Exception {
+ model.setWrappedData(null);
+ assertTrue(!model.isRowAvailable());
+ assertEquals(-1, model.getRowCount());
+ assertNull(model.getRowData());
+ assertEquals(-1, model.getRowIndex());
+ assertNull(model.getWrappedData());
+ }
+
+ // ------------------------------------------------------- Protected Methods
+ protected BeanTestImpl data() throws Exception {
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof BeanTestImpl);
+ return ((BeanTestImpl) data);
+ }
+
+ protected void checkRow(int i) throws Exception {
+ model.setRowIndex(i);
+ String prompt = "Row " + i + " property ";
+ BeanTestImpl bean = data();
+ assertNotNull(bean, "Row " + i + " data");
+ assertEquals(
+ beans[i].getBooleanProperty(),
+ bean.getBooleanProperty(), prompt + "booleanProperty");
+ assertEquals(
+ beans[i].isBooleanSecond(),
+ bean.isBooleanSecond(), prompt + "booleanSecond");
+ assertEquals(
+ beans[i].getByteProperty(),
+ bean.getByteProperty(), prompt + "byteProperty");
+ assertEquals(
+ "" + beans[i].getDoubleProperty(),
+ "" + bean.getDoubleProperty(), prompt + "doubleProperty");
+ assertEquals(
+ "" + beans[i].getFloatProperty(),
+ "" + bean.getFloatProperty(), prompt + "floatProperty");
+ assertEquals(
+ beans[i].getIntProperty(),
+ bean.getIntProperty(), prompt + "intProperty");
+ assertEquals(
+ beans[i].getLongProperty(),
+ bean.getLongProperty(), prompt + "longProperty");
+ assertEquals(
+ beans[i].getNullProperty(),
+ bean.getNullProperty(), prompt + "nullProperty");
+ assertEquals(
+ beans[i].getReadOnlyProperty(),
+ bean.getReadOnlyProperty(), prompt + "readOnlyProperty");
+ assertEquals(
+ beans[i].getShortProperty(),
+ bean.getShortProperty(), prompt + "shortProperty");
+ assertEquals(
+ beans[i].getStringProperty(),
+ bean.getStringProperty(), prompt + "stringProperty");
+ assertEquals(
+ beans[i].getWriteOnlyPropertyValue(),
+ bean.getWriteOnlyPropertyValue(), prompt + "writeOnlyProperty");
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/model/ListDataModelTestCase.java b/impl/src/test/java/jakarta/faces/model/ListDataModelTestCase.java
new file mode 100644
index 0000000000..552542f90e
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/ListDataModelTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * Unit tests for {@link ListDataModel}.
+ */
+public class ListDataModelTestCase extends DataModelTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ List list = new ArrayList();
+ for (int i = 0; i < 5; i++) {
+ list.add(new BeanTestImpl());
+ }
+ beans = list.toArray(new BeanTestImpl[5]);
+ configure();
+ model = new ListDataModel(list);
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // ------------------------------------------------------- Protected Methods
+}
diff --git a/impl/src/test/java/jakarta/faces/model/ResultSetDataModelTestCase.java b/impl/src/test/java/jakarta/faces/model/ResultSetDataModelTestCase.java
new file mode 100644
index 0000000000..635edacba9
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/ResultSetDataModelTestCase.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.mock.MockResultSet;
+
+/**
+ *
+ * Unit tests for {@link ArrayDataModel}.
+ */
+public class ResultSetDataModelTestCase extends DataModelTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // The ResultSet passed to our ResultSetDataModel
+ protected MockResultSet result = null;
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ beans = new BeanTestImpl[5];
+ for (int i = 0; i < beans.length; i++) {
+ beans[i] = new BeanTestImpl();
+ }
+ configure();
+ result = new MockResultSet(beans);
+ model = new ResultSetDataModel(result);
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // Test ((Map) getRowData()).containsKey()
+ @Test
+ public void testRowDataContainsKey() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+
+ // Test exact match on column names
+ assertTrue(map.containsKey("booleanProperty"));
+ assertTrue(map.containsKey("booleanSecond"));
+ assertTrue(map.containsKey("byteProperty"));
+ assertTrue(map.containsKey("doubleProperty"));
+ assertTrue(map.containsKey("floatProperty"));
+ assertTrue(map.containsKey("intProperty"));
+ assertTrue(map.containsKey("longProperty"));
+ assertTrue(map.containsKey("stringProperty"));
+
+ // Test inexact match on column names
+ assertTrue(map.containsKey("booleanPROPERTY"));
+ assertTrue(map.containsKey("booleanSECOND"));
+ assertTrue(map.containsKey("bytePROPERTY"));
+ assertTrue(map.containsKey("doublePROPERTY"));
+ assertTrue(map.containsKey("floatPROPERTY"));
+ assertTrue(map.containsKey("intPROPERTY"));
+ assertTrue(map.containsKey("longPROPERTY"));
+ assertTrue(map.containsKey("stringPROPERTY"));
+
+ // Test false return on invalid column names
+ assertTrue(!map.containsKey("foo"));
+ assertTrue(!map.containsKey("FOO"));
+ assertTrue(!map.containsKey("bar"));
+ assertTrue(!map.containsKey("BAR"));
+ }
+
+ // Test ((Map) getRowData()).containsValue()
+ @Test
+ public void testRowDataContainsValue() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+
+ // Test positive results
+ assertTrue(map.containsValue(Boolean.TRUE));
+ assertTrue(map.containsValue(Boolean.FALSE));
+ assertTrue(map.containsValue(Byte.valueOf((byte) 1)));
+ assertTrue(map.containsValue(Double.valueOf(100.0)));
+ assertTrue(map.containsValue(Float.valueOf((float) 10.0)));
+ assertTrue(map.containsValue(Integer.valueOf(1000)));
+ assertTrue(map.containsValue(Long.valueOf(10000l)));
+ assertTrue(map.containsValue("This is string 1"));
+
+ // Test negative results
+ assertTrue(!map.containsValue("foo"));
+ assertTrue(!map.containsValue(Integer.valueOf(654321)));
+ }
+
+ // Test ((Map) getRowData()).entrySet()
+ @Test
+ public void testRowDataEntrySet() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+ Set set = map.entrySet();
+
+ // Test exact match postive results
+ assertTrue(set.contains(new TestEntry("booleanProperty", Boolean.FALSE)));
+ assertTrue(set.contains(new TestEntry("booleanSecond", Boolean.TRUE)));
+ assertTrue(set.contains(new TestEntry("byteProperty", Byte.valueOf((byte) 1))));
+ assertTrue(set.contains(new TestEntry("doubleProperty", Double.valueOf(100.0))));
+ assertTrue(set.contains(new TestEntry("floatProperty", Float.valueOf((float) 10.0))));
+ assertTrue(set.contains(new TestEntry("intProperty", Integer.valueOf(1000))));
+ assertTrue(set.contains(new TestEntry("longProperty", Long.valueOf(10000l))));
+ assertTrue(set.contains(new TestEntry("stringProperty", "This is string 1")));
+
+ // Test exact match postive results
+ assertTrue(set.contains(new TestEntry("booleanPROPERTY", Boolean.FALSE)));
+ assertTrue(set.contains(new TestEntry("booleanSECOND", Boolean.TRUE)));
+ assertTrue(set.contains(new TestEntry("bytePROPERTY", Byte.valueOf((byte) 1))));
+ assertTrue(set.contains(new TestEntry("doublePROPERTY", Double.valueOf(100.0))));
+ assertTrue(set.contains(new TestEntry("floatPROPERTY", Float.valueOf((float) 10.0))));
+ assertTrue(set.contains(new TestEntry("intPROPERTY", Integer.valueOf(1000))));
+ assertTrue(set.contains(new TestEntry("longPROPERTY", Long.valueOf(10000l))));
+ assertTrue(set.contains(new TestEntry("stringPROPERTY", "This is string 1")));
+
+ // Test negative results
+ assertTrue(!set.contains(new TestEntry("foo", "bar")));
+ assertTrue(!set.contains(new TestEntry("FOO", "bar")));
+ assertTrue(!set.contains(new TestEntry("baz", "bop")));
+ assertTrue(!set.contains(new TestEntry("BAZ", "bop")));
+
+ // Test other methods
+ assertTrue(!set.isEmpty());
+
+ // Test updating through the entry set
+ Iterator entries = set.iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if ("stringProperty".equalsIgnoreCase((String) entry.getKey())) {
+ entry.setValue("This is string 1 modified");
+ }
+ }
+ assertEquals("This is string 1 modified",
+ beans[1].getStringProperty());
+ assertEquals("This is string 1 modified",
+ map.get("stringProperty"));
+ assertEquals("This is string 1 modified",
+ map.get("stringPROPERTY"));
+ result.absolute(2); // ResultSet indexing is one-relative
+ assertEquals("This is string 1 modified",
+ result.getObject("stringProperty"));
+ }
+
+ // Test ((Map) getRowData()).get()
+ @Test
+ public void testRowDataGet() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+
+ // Test exact match on column names
+ assertEquals(Boolean.FALSE, map.get("booleanProperty"));
+ assertEquals(Boolean.TRUE, map.get("booleanSecond"));
+ assertEquals(Byte.valueOf((byte) 1), map.get("byteProperty"));
+ assertEquals(Double.valueOf(100.0), map.get("doubleProperty"));
+ assertEquals(Float.valueOf((float) 10.0), map.get("floatProperty"));
+ assertEquals(Integer.valueOf(1000), map.get("intProperty"));
+ assertEquals(Long.valueOf(10000l), map.get("longProperty"));
+ assertEquals("This is string 1", map.get("stringProperty"));
+
+ // Test inexact match on column names
+ assertEquals(Boolean.FALSE, map.get("booleanPROPERTY"));
+ assertEquals(Boolean.TRUE, map.get("booleanSECOND"));
+ assertEquals(Byte.valueOf((byte) 1), map.get("bytePROPERTY"));
+ assertEquals(Double.valueOf(100.0), map.get("doublePROPERTY"));
+ assertEquals(Float.valueOf((float) 10.0), map.get("floatPROPERTY"));
+ assertEquals(Integer.valueOf(1000), map.get("intPROPERTY"));
+ assertEquals(Long.valueOf(10000l), map.get("longPROPERTY"));
+ assertEquals("This is string 1", map.get("stringPROPERTY"));
+
+ // Test null return on non-existent column names
+ assertNull(map.get("foo"));
+ assertNull(map.get("FOO"));
+ assertNull(map.get("bar"));
+ assertNull(map.get("bar"));
+ }
+
+ // Test ((Map) getRowData()).keySet()
+ @Test
+ public void testRowDataKeySet() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+ Set set = map.keySet();
+
+ // Test exact match postive results
+ assertTrue(set.contains("booleanProperty"));
+ assertTrue(set.contains("booleanSecond"));
+ assertTrue(set.contains("byteProperty"));
+ assertTrue(set.contains("doubleProperty"));
+ assertTrue(set.contains("floatProperty"));
+ assertTrue(set.contains("intProperty"));
+ assertTrue(set.contains("longProperty"));
+ assertTrue(set.contains("stringProperty"));
+
+ // Test inexact match positive results
+ assertTrue(set.contains("booleanPROPERTY"));
+ assertTrue(set.contains("booleanSECOND"));
+ assertTrue(set.contains("bytePROPERTY"));
+ assertTrue(set.contains("doublePROPERTY"));
+ assertTrue(set.contains("floatPROPERTY"));
+ assertTrue(set.contains("intPROPERTY"));
+ assertTrue(set.contains("longPROPERTY"));
+ assertTrue(set.contains("stringPROPERTY"));
+
+ // Test negative results
+ assertTrue(!set.contains("foo"));
+ assertTrue(!set.contains("FOO"));
+ assertTrue(!set.contains("bar"));
+ assertTrue(!set.contains("BAR"));
+
+ // Test other methods
+ assertTrue(!set.isEmpty());
+ }
+
+ // Test ((Map) getRowData()).put()
+ @Test
+ public void testRowDataPut() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+ }
+
+ // Test unsupported operations on ((Map) getRowData())
+ @Test
+ public void testRowDataUnsupported() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+
+ // clear()
+ try {
+ map.clear();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // entrySet()
+ Set entrySet = map.entrySet();
+ try {
+ entrySet.add(new TestEntry("foo", "bar"));
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ List mapEntries = new ArrayList();
+ mapEntries.add(new TestEntry("foo", "bar"));
+ mapEntries.add(new TestEntry("baz", "bop"));
+ try {
+ entrySet.addAll(mapEntries);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ entrySet.clear();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ Iterator iterator = entrySet.iterator();
+ iterator.next();
+ iterator.remove();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ entrySet.remove(new TestEntry("foo", "bar"));
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ entrySet.removeAll(mapEntries);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ entrySet.retainAll(mapEntries);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // keySet()
+ Set keySet = map.keySet();
+ try {
+ keySet.add("foo");
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ List mapKeys = new ArrayList();
+ mapKeys.add("foo");
+ mapKeys.add("bar");
+ try {
+ keySet.addAll(mapKeys);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ keySet.clear();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ Iterator iterator = keySet.iterator();
+ iterator.next();
+ iterator.remove();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ keySet.remove(new TestEntry("foo", "bar"));
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ keySet.removeAll(mapKeys);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ keySet.retainAll(mapKeys);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // remove()
+ try {
+ map.remove("foo");
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ // values()
+ Collection values = map.values();
+ try {
+ values.add("foo");
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ List list = new ArrayList();
+ list.add("foo");
+ list.add("bar");
+ try {
+ values.addAll(list);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ values.clear();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ Iterator iterator = values.iterator();
+ iterator.next();
+ iterator.remove();
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ values.remove("foo");
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ values.removeAll(list);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+ try {
+ values.retainAll(list);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // Expected result
+ }
+
+ }
+
+ // Test ((Map) getRowData()).values()
+ @Test
+ public void testRowDataValues() throws Exception {
+ // Position to row 1 and retrieve the corresponding Map
+ model.setRowIndex(1);
+ assertTrue(model.isRowAvailable());
+ Object data = model.getRowData();
+ assertNotNull(data);
+ assertTrue(data instanceof Map);
+ Map map = (Map) data;
+ Collection values = map.values();
+
+ // Test positive results
+ assertTrue(values.contains(Boolean.TRUE));
+ assertTrue(values.contains(Boolean.FALSE));
+ assertTrue(values.contains(Byte.valueOf((byte) 1)));
+ assertTrue(values.contains(Double.valueOf(100.0)));
+ assertTrue(values.contains(Float.valueOf((float) 10.0)));
+ assertTrue(values.contains(Integer.valueOf(1000)));
+ assertTrue(values.contains(Long.valueOf(10000l)));
+ assertTrue(values.contains("This is string 1"));
+
+ // Test negative results
+ assertTrue(!values.contains("foo"));
+ assertTrue(!values.contains(Integer.valueOf(654321)));
+
+ // Test other methods
+ assertTrue(!values.isEmpty());
+ }
+
+ // ------------------------------------------------------- Protected Methods
+ @Override
+ protected BeanTestImpl data() throws Exception {
+ Object data = model.getRowData();
+ assertTrue(data instanceof Map);
+ BeanTestImpl bean = new BeanTestImpl();
+ Map map = (Map) data;
+
+ bean.setBooleanProperty(((Boolean) map.get("booleanProperty")).booleanValue());
+ bean.setBooleanSecond(((Boolean) map.get("booleanSecond")).booleanValue());
+ bean.setByteProperty(((Byte) map.get("byteProperty")).byteValue());
+ bean.setDoubleProperty(((Double) map.get("doubleProperty")).doubleValue());
+ bean.setFloatProperty(((Float) map.get("floatProperty")).floatValue());
+ bean.setIntProperty(((Integer) map.get("intProperty")).intValue());
+ bean.setLongProperty(((Long) map.get("longProperty")).longValue());
+ bean.setNullProperty((String) map.get("nullProperty"));
+ bean.setShortProperty(((Short) map.get("shortProperty")).shortValue());
+ bean.setStringProperty((String) map.get("stringProperty"));
+ bean.setWriteOnlyProperty((String) map.get("writeOnlyPropertyValue"));
+
+ return (bean);
+ }
+
+ class TestEntry implements Map.Entry {
+
+ public TestEntry(Object key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ private Object key;
+ private Object value;
+
+ @Override
+ public Object getKey() {
+ return key;
+ }
+
+ @Override
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ public Object setValue(Object value) {
+ Object previous = this.value;
+ this.value = value;
+ return previous;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Map.Entry)) {
+ return (false);
+ }
+ Map.Entry e = (Map.Entry) o;
+ return (key == null
+ ? e.getKey() == null : key.equals(e.getKey()))
+ && (value == null
+ ? e.getValue() == null : value.equals(e.getValue()));
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/model/ScalarDataModelTestCase.java b/impl/src/test/java/jakarta/faces/model/ScalarDataModelTestCase.java
new file mode 100644
index 0000000000..96d6cba224
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/model/ScalarDataModelTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.model;
+
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ *
+ * Unit tests for {@link ScalarDataModel}.
+ */
+public class ScalarDataModelTestCase extends DataModelTestCaseBase {
+
+ // ------------------------------------------------------ Instance Variables
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @BeforeEach
+ public void setUp() throws Exception {
+ beans = new BeanTestImpl[1];
+ beans[0] = new BeanTestImpl();
+ configure();
+ model = new ScalarDataModel(beans[0]);
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ // ------------------------------------------------------- Protected Methods
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/BeanValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/BeanValidatorTestCase.java
new file mode 100644
index 0000000000..f711dc736a
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/BeanValidatorTestCase.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2022, 2022 Contributors to Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import java.util.Locale;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.UIInput;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+
+/**
+ * Unit tests for {@link BeanValidator}.
+ *
+ * @author rmartinc
+ */
+public class BeanValidatorTestCase extends ValidatorTestCase {
+
+ /**
+ * Test class for the bean validator.
+ */
+ public static class TestBean {
+
+ @NotNull
+ @Size(min = 1, max = 64)
+ private String message;
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+ }
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testMessageOK() {
+ BeanValidator validator = new BeanValidator();
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+ UIInput component = new UIInput();
+ request.setAttribute("test", new TestBean());
+ component.setValueExpression("value", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{test.message}", String.class));
+
+ validator.validate(facesContext, component, "something");
+ }
+
+ @Test
+ public void testMessageKO() {
+ BeanValidator validator = new BeanValidator();
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+ UIInput component = new UIInput();
+ request.setAttribute("test", new TestBean());
+ component.setValueExpression("value", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{test.message}", String.class));
+
+ try {
+ validator.validate(facesContext, component, "");
+ Assertions.fail("ValidatorException expected");
+ } catch (ValidatorException e) {
+ Assertions.assertEquals("size must be between 1 and 64", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNoBase() {
+ BeanValidator validator = new BeanValidator();
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+ UIInput component = new UIInput();
+ component.setValueExpression("value", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{something}", String.class));
+
+ validator.validate(facesContext, component, "something");
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/CastingValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/CastingValidatorTestCase.java
new file mode 100644
index 0000000000..fa9f13042c
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/CastingValidatorTestCase.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * Unit tests for JLS casting rules
+ */
+public class CastingValidatorTestCase extends ValidatorTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ @SuppressWarnings("rawtypes")
+ public void testWithGenericCanCastToRaw() {
+ Validator> validatorWithGeneric = (context, component, value) -> {};
+ Validator validatorRaw = validatorWithGeneric;
+ assertNotNull(validatorRaw);
+ }
+
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/DoubleRangeValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/DoubleRangeValidatorTestCase.java
new file mode 100644
index 0000000000..5daa37ed77
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/DoubleRangeValidatorTestCase.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.Locale;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.UIInput;
+
+/**
+ *
+ * Unit tests for {@link DoubleRangeValidator}.
+ */
+public class DoubleRangeValidatorTestCase extends ValidatorTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testLocaleHonored() {
+ DoubleRangeValidator validator = new DoubleRangeValidator();
+ validator.setMinimum(10.1);
+ validator.setMaximum(20.1);
+ boolean exceptionThrown = false;
+ UIInput component = new UIInput();
+ String message;
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+
+ try {
+ validator.validate(facesContext, component, "5.1");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("10.1"), "message: \"" + message + "\" missing localized chars.");
+ assertTrue(
+ -1 != message.indexOf("20.1"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+
+ exceptionThrown = false;
+ Locale.setDefault(Locale.GERMAN);
+ facesContext.getViewRoot().setLocale(Locale.GERMAN);
+
+ try {
+ validator.validate(facesContext, component, "5");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("10,1"), "message: \"" + message + "\" missing localized chars.");
+ assertTrue(
+ -1 != message.indexOf("20,1"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+ }
+
+ @Test
+ public void testHashCode() {
+ DoubleRangeValidator validator1 = new DoubleRangeValidator();
+ DoubleRangeValidator validator2 = new DoubleRangeValidator();
+
+ validator1.setMinimum(10.0d);
+ validator1.setMaximum(15.1d);
+ validator2.setMinimum(10.0d);
+ validator2.setMaximum(15.1d);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator2.setMaximum(15.2d);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1 = new DoubleRangeValidator();
+ validator2 = new DoubleRangeValidator();
+
+ validator1.setMinimum(10.0d);
+ validator2.setMinimum(10.0d);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator1.setMinimum(11.0d);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1.setMinimum(10.0d);
+ validator1.setMaximum(10.1d);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/LengthValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/LengthValidatorTestCase.java
new file mode 100644
index 0000000000..97e4414b3f
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/LengthValidatorTestCase.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.Locale;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.UIInput;
+
+/**
+ *
+ * Unit tests for {@link LengthValidator}.
+ */
+public class LengthValidatorTestCase extends ValidatorTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testLocaleHonored() {
+ LengthValidator validator = new LengthValidator();
+ validator.setMinimum(1000);
+ validator.setMaximum(2000);
+ boolean exceptionThrown = false;
+ UIInput component = new UIInput();
+ String message;
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+
+ try {
+ validator.validate(facesContext, component,
+ "Not at all long enough");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("1,000"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+
+ exceptionThrown = false;
+ Locale.setDefault(Locale.GERMAN);
+ facesContext.getViewRoot().setLocale(Locale.GERMAN);
+
+ try {
+ validator.validate(facesContext, component,
+ "Still not long enough");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("1.000"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+ }
+
+ @Test
+ public void testHashCode() {
+ LengthValidator validator1 = new LengthValidator();
+ LengthValidator validator2 = new LengthValidator();
+
+ validator1.setMinimum(10);
+ validator1.setMaximum(15);
+ validator2.setMinimum(10);
+ validator2.setMaximum(15);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator2.setMaximum(16);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1 = new LengthValidator();
+ validator2 = new LengthValidator();
+
+ validator1.setMinimum(10);
+ validator2.setMinimum(10);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator1.setMinimum(11);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1.setMinimum(10);
+ validator1.setMaximum(10);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/LongRangeValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/LongRangeValidatorTestCase.java
new file mode 100644
index 0000000000..c59b18fdcc
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/LongRangeValidatorTestCase.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.Locale;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.UIInput;
+
+/**
+ *
+ * Unit tests for {@link LongRangeValidator}.
+ */
+public class LongRangeValidatorTestCase extends ValidatorTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testLocaleHonored() {
+ LongRangeValidator validator = new LongRangeValidator();
+ validator.setMinimum(10100);
+ validator.setMaximum(20100);
+ boolean exceptionThrown = false;
+ UIInput component = new UIInput();
+ String message;
+ Locale.setDefault(Locale.US);
+ facesContext.getViewRoot().setLocale(Locale.US);
+
+ try {
+ validator.validate(facesContext, component, "5100");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("10,100"), "message: \"" + message + "\" missing localized chars.");
+ assertTrue(
+ -1 != message.indexOf("20,100"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+
+ exceptionThrown = false;
+ Locale.setDefault(Locale.GERMAN);
+ facesContext.getViewRoot().setLocale(Locale.GERMAN);
+
+ try {
+ validator.validate(facesContext, component, "5100");
+ fail("Exception not thrown");
+ } catch (ValidatorException e) {
+ exceptionThrown = true;
+ message = e.getMessage();
+ assertTrue(
+ -1 != message.indexOf("10.100"), "message: \"" + message + "\" missing localized chars.");
+ assertTrue(
+ -1 != message.indexOf("20.100"), "message: \"" + message + "\" missing localized chars.");
+ }
+ assertTrue(exceptionThrown);
+ }
+
+ @Test
+ public void testHashCode() {
+ LongRangeValidator validator1 = new LongRangeValidator();
+ LongRangeValidator validator2 = new LongRangeValidator();
+
+ validator1.setMinimum(10l);
+ validator1.setMaximum(15l);
+ validator2.setMinimum(10l);
+ validator2.setMaximum(15l);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator2.setMaximum(16l);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1 = new LongRangeValidator();
+ validator2 = new LongRangeValidator();
+
+ validator1.setMinimum(10l);
+ validator2.setMinimum(10l);
+
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+ assertTrue(validator1.hashCode() == validator2.hashCode());
+
+ validator1.setMinimum(11l);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+
+ validator1.setMinimum(10l);
+ validator1.setMaximum(11l);
+
+ assertTrue(validator1.hashCode() != validator2.hashCode());
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/RegexValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/RegexValidatorTestCase.java
new file mode 100644
index 0000000000..189ae63241
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/RegexValidatorTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.Locale;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.faces.component.UIInput;
+
+/**
+ *
+ * Unit tests for {@link RegexValidator}.
+ */
+public class RegexValidatorTestCase extends ValidatorTestCase {
+
+ // ------------------------------------------------- Individual Test Methods
+ @Test
+ public void testPatternMatch() {
+ String patternStr = "t.*";
+ RegexValidator validator = new RegexValidator();
+ validator.setPattern(patternStr);
+ UIInput component = new UIInput();
+ String checkme = "test";
+ try {
+ validator.validate(facesContext, component, checkme);
+ assertTrue(true);
+ } catch (ValidatorException ve) {
+ fail("Exception thrown " + ve.getMessage());
+ }
+ }
+
+ @Test
+ public void testPatterMismatch() {
+ String patternStr = "t.*";
+ facesContext.getViewRoot().setLocale(Locale.US);
+ RegexValidator validator = new RegexValidator();
+ validator.setPattern(patternStr);
+ UIInput component = new UIInput();
+ String checkme = "jest";
+ try {
+ validator.validate(facesContext, component, checkme);
+ fail("Exception not thrown when tested " + checkme + " against " + patternStr);
+ } catch (ValidatorException ve) {
+ String detail = ve.getFacesMessage().getDetail();
+ System.out.println("Detail in test: " + detail);
+ assertTrue(detail.equalsIgnoreCase("Regex pattern of 't.*' not matched"));
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/RequiredValidatorTest.java b/impl/src/test/java/jakarta/faces/validator/RequiredValidatorTest.java
new file mode 100644
index 0000000000..4ed683411c
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/RequiredValidatorTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * The JUnit tests for the RequiredValidator class.
+ */
+public class RequiredValidatorTest {
+
+ /**
+ * Test validate method.
+ */
+ @Test
+ public void testValidate() {
+ RequiredValidator validator = new RequiredValidator();
+ validator.validate(null, null, "notempty");
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/validator/ValidatorTestCase.java b/impl/src/test/java/jakarta/faces/validator/ValidatorTestCase.java
new file mode 100644
index 0000000000..740b917d76
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/validator/ValidatorTestCase.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.validator;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.sun.faces.junit.JUnitFacesTestCaseBase;
+import com.sun.faces.mock.MockRenderKit;
+
+import jakarta.faces.FactoryFinder;
+import jakarta.faces.component.UIViewRoot;
+import jakarta.faces.render.RenderKit;
+import jakarta.faces.render.RenderKitFactory;
+
+/**
+ *
+ * Base unit tests for all {@link Validator} implementations.
+ */
+public class ValidatorTestCase extends JUnitFacesTestCaseBase {
+
+ // ---------------------------------------------------- Overall Test Methods
+ // Set up instance variables required by this test case.
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+ UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
+ root.setViewId("/viewId");
+ facesContext.setViewRoot(root);
+ RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = new MockRenderKit();
+ try {
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT,
+ renderKit);
+ } catch (IllegalArgumentException e) {
+ }
+
+ }
+
+ @Test
+ public void testNoOp() {
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/webapp/ComponentTestImpl.java b/impl/src/test/java/jakarta/faces/webapp/ComponentTestImpl.java
new file mode 100644
index 0000000000..869fb33325
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/webapp/ComponentTestImpl.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.webapp;
+
+import java.io.IOException;
+
+import jakarta.el.ValueExpression;
+import jakarta.faces.component.UIComponentBase;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.ResponseWriter;
+
+// Test UIComponent Class
+public class ComponentTestImpl extends UIComponentBase {
+
+ public ComponentTestImpl() {
+ }
+
+ public ComponentTestImpl(String id) {
+ setId(id);
+ }
+
+ @Override
+ public String getFamily() {
+ return ("Test");
+ }
+
+ private String label = null;
+
+ public String getLabel() {
+ if (this.label != null) {
+ return (this.label);
+ }
+ ValueExpression vb = getValueExpression("label");
+ if (vb != null) {
+ return ((String) vb.getValue(getFacesContext().getELContext()));
+ } else {
+ return (null);
+ }
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ private boolean rendersChildren = false;
+
+ @Override
+ public boolean getRendersChildren() {
+ return (this.rendersChildren);
+ }
+
+ public void setRendersChildren(boolean rendersChildren) {
+ this.rendersChildren = rendersChildren;
+ }
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException {
+ if (!isRendered()) {
+ return;
+ }
+ ResponseWriter writer = context.getResponseWriter();
+ writer.write("/b");
+ String id = getId();
+ if (id != null) {
+ writer.write(id);
+ }
+ }
+
+ @Override
+ public void encodeChildren(FacesContext context) throws IOException {
+ if (isRendered()) {
+ super.encodeChildren(context);
+ }
+ }
+
+ @Override
+ public void encodeEnd(FacesContext context) throws IOException {
+ if (!isRendered()) {
+ return;
+ }
+ ResponseWriter writer = context.getResponseWriter();
+ writer.write("/e");
+ String id = getId();
+ if (id != null) {
+ writer.write(id);
+ }
+ }
+}
diff --git a/impl/src/test/java/jakarta/faces/webapp/ConfigFileTestCase.java b/impl/src/test/java/jakarta/faces/webapp/ConfigFileTestCase.java
new file mode 100644
index 0000000000..18b6e4594d
--- /dev/null
+++ b/impl/src/test/java/jakarta/faces/webapp/ConfigFileTestCase.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.faces.webapp;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.xml.sax.InputSource;
+
+import com.sun.faces.config.DigesterFactory;
+
+/**
+ *
+ * Unit tests for Configuration File processing.
+ *
+ */
+public class ConfigFileTestCase {
+
+ // The public identifier of our DTD
+ protected String CONFIG_DTD_PUBLIC_ID = "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN";
+
+ // ----------------------------------------------------- Instance Variables
+ /**
+ * The Digester instance we will use to parse configuration files.
+ */
+ protected Digester digester = null;
+
+ // --------------------------------------------------- Overall Test Methods
+ /**
+ * Set up instance variables required by this test case.
+ *
+ * @throws java.lang.Exception
+ */
+ @BeforeEach
+ public void setUp() throws Exception {
+ digester = createDigester();
+ configureRules(digester);
+ }
+
+ // ------------------------------------------------ Individual Test Methods
+ // Test parsing an empty configuration file
+ @Test
+ public void testEmpty() throws Exception {
+ ConfigBase base = parseConfig(relativeURL("src/test/java/jakarta/faces/webapp/config-file-0.xml"));
+ assertNotNull(base);
+ }
+
+ // Test parsing a full configuration file
+ @Test
+ public void testFull() throws Exception {
+ // Retrieve entire configuration metadata instance
+ ConfigBase base = parseConfig(relativeURL("src/test/java/jakarta/faces/webapp/config-file-1.xml"));
+ assertNotNull(base);
+
+ //
+ assertEquals("com.mycompany.MyActionListener", base.getActionListener());
+ assertEquals("com.mycompany.MyNavigationHandler", base.getNavigationHandler());
+
+ //
+ Map, ?> components = base.getComponents();
+ assertNotNull(components);
+ ConfigComponent ccomp1 = (ConfigComponent) components.get("Command");
+ assertNotNull(ccomp1);
+ assertEquals("User Interface Command Component", ccomp1.getDescription());
+ assertEquals("User Interface Command", ccomp1.getDisplayName());
+ assertEquals("Command", ccomp1.getComponentType());
+ assertEquals("jakarta.faces.component.UICommand", ccomp1.getComponentClass());
+ assertNull(ccomp1.getLargeIcon());
+ assertNull(ccomp1.getSmallIcon());
+ assertEquals(0, ccomp1.getAttributes().size());
+ assertEquals(0, ccomp1.getProperties().size());
+
+ //