struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lukaszlen...@apache.org
Subject [19/57] [partial] struts git commit: Merges xwork packages into struts
Date Wed, 17 Jun 2015 21:09:19 GMT
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/LocalizedTextUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/LocalizedTextUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/util/LocalizedTextUtilTest.java
new file mode 100644
index 0000000..540b89d
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/LocalizedTextUtilTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.mockobjects.dynamic.Mock;
+import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.test.ModelDrivenAction2;
+import com.opensymphony.xwork2.test.TestBean2;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+
+/**
+ * Unit test for {@link LocalizedTextUtil}.
+ *
+ * @author jcarreira
+ * @author tm_jee
+ * 
+ * @version $Date$ $Id$
+ */
+public class LocalizedTextUtilTest extends XWorkTestCase {
+
+	public void testNpeWhenClassIsPrimitive() throws Exception {
+		ValueStack stack = ActionContext.getContext().getValueStack();
+		stack.push(new MyObject());
+		String result = LocalizedTextUtil.findText(MyObject.class, "someObj.someI18nKey", Locale.ENGLISH, "default message", null, stack);
+		System.out.println(result);
+	}
+	
+	public static class MyObject extends ActionSupport {
+		public boolean getSomeObj() {
+			return true;
+		}
+	}
+	
+	public void testActionGetTextWithNullObject() throws Exception {
+		MyAction action = new MyAction();
+		
+		Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+		ActionContext.getContext().getValueStack().push(action);
+		
+		String message = action.getText("barObj.title");
+		assertEquals("Title:", message);
+	}
+	
+	
+	public static class MyAction extends ActionSupport {
+		private Bar testBean2;
+		
+		public Bar getBarObj() {
+			return testBean2;
+		}
+		public void setBarObj(Bar testBean2) {
+			this.testBean2 = testBean2;
+		}
+	}
+	
+    public void testActionGetText() throws Exception {
+        ModelDrivenAction2 action = new ModelDrivenAction2();
+        TestBean2 bean = (TestBean2) action.getModel();
+        Bar bar = new Bar();
+        bean.setBarObj(bar);
+
+        Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+        ActionContext.getContext().getValueStack().push(action);
+        ActionContext.getContext().getValueStack().push(action.getModel());
+
+        String message = action.getText("barObj.title");
+        assertEquals("Title:", message);
+    }
+
+    public void testNullKeys() {
+        LocalizedTextUtil.findText(this.getClass(), null, Locale.getDefault());
+    }
+
+    public void testActionGetTextXXX() throws Exception {
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/util/FindMe");
+
+        SimpleAction action = new SimpleAction();
+
+        Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+        ActionContext.getContext().getValueStack().push(action);
+
+        String message = action.getText("bean.name");
+        String foundBean2 = action.getText("bean2.name");
+
+        assertEquals("Okay! You found Me!", foundBean2);
+        assertEquals("Haha you cant FindMe!", message);
+    }
+
+    public void testAddDefaultResourceBundle() {
+        String text = LocalizedTextUtil.findDefaultText("foo.range", Locale.getDefault());
+        assertNull("Found message when it should not be available.", null);
+
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/SimpleAction");
+
+        String message = LocalizedTextUtil.findDefaultText("foo.range", Locale.US);
+        assertEquals("Foo Range Message", message);
+    }
+
+    public void testAddDefaultResourceBundle2() throws Exception {
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/SimpleAction");
+
+        ActionProxy proxy = actionProxyFactory.createActionProxy("/", "packagelessAction", new HashMap<String, Object>(), false, true);
+        proxy.execute();
+    }
+
+    public void testDefaultMessage() throws Exception {
+        String message = LocalizedTextUtil.findDefaultText(XWorkMessages.ACTION_EXECUTION_ERROR, Locale.getDefault());
+        assertEquals("Error during Action invocation", message);
+    }
+
+    public void testDefaultMessageOverride() throws Exception {
+        String message = LocalizedTextUtil.findDefaultText(XWorkMessages.ACTION_EXECUTION_ERROR, Locale.getDefault());
+        assertEquals("Error during Action invocation", message);
+
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/test");
+
+        message = LocalizedTextUtil.findDefaultText(XWorkMessages.ACTION_EXECUTION_ERROR, Locale.getDefault());
+        assertEquals("Testing resource bundle override", message);
+    }
+
+    public void testFindTextInChildProperty() throws Exception {
+        ModelDriven action = new ModelDrivenAction2();
+        TestBean2 bean = (TestBean2) action.getModel();
+        Bar bar = new Bar();
+        bean.setBarObj(bar);
+
+        Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("hashCode", 0);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+        ActionContext.getContext().getValueStack().push(action);
+        ActionContext.getContext().getValueStack().push(action.getModel());
+
+        String message = LocalizedTextUtil.findText(ModelDrivenAction2.class, "invalid.fieldvalue.barObj.title", Locale.getDefault());
+        assertEquals("Title is invalid!", message);
+    }
+
+    public void testFindTextInInterface() throws Exception {
+        Action action = new ModelDrivenAction2();
+        Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+
+        String message = LocalizedTextUtil.findText(ModelDrivenAction2.class, "test.foo", Locale.getDefault());
+        assertEquals("Foo!", message);
+    }
+
+    public void testFindTextInPackage() throws Exception {
+        ModelDriven action = new ModelDrivenAction2();
+
+        Mock mockActionInvocation = new Mock(ActionInvocation.class);
+        mockActionInvocation.expectAndReturn("getAction", action);
+        ActionContext.getContext().setActionInvocation((ActionInvocation) mockActionInvocation.proxy());
+
+        String message = LocalizedTextUtil.findText(ModelDrivenAction2.class, "package.properties", Locale.getDefault());
+        assertEquals("It works!", message);
+    }
+
+    public void testParameterizedDefaultMessage() throws Exception {
+        String message = LocalizedTextUtil.findDefaultText(XWorkMessages.MISSING_ACTION_EXCEPTION, Locale.getDefault(), new String[]{"AddUser"});
+        assertEquals("There is no Action mapped for action name AddUser.", message);
+    }
+
+    public void testParameterizedDefaultMessageWithPackage() throws Exception {
+        String message = LocalizedTextUtil.findDefaultText(XWorkMessages.MISSING_PACKAGE_ACTION_EXCEPTION, Locale.getDefault(), new String[]{"blah", "AddUser"});
+        assertEquals("There is no Action mapped for namespace blah and action name AddUser.", message);
+    }
+
+    public void testLocalizedDateFormatIsUsed() {
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/util/LocalizedTextUtilTest");
+        Object[] params = new Object[]{new Date()};
+        String usDate = LocalizedTextUtil.findDefaultText("test.format.date", Locale.US, params);
+        String germanDate = LocalizedTextUtil.findDefaultText("test.format.date", Locale.GERMANY, params);
+        assertFalse(usDate.equals(germanDate));
+    }
+
+    public void testXW377() {
+        LocalizedTextUtil.addDefaultResourceBundle("com/opensymphony/xwork2/util/LocalizedTextUtilTest");
+
+        String text = LocalizedTextUtil.findText(Bar.class, "xw377", ActionContext.getContext().getLocale(), "xw377", null, ActionContext.getContext().getValueStack());
+        assertEquals("xw377", text); // should not log
+
+        String text2 = LocalizedTextUtil.findText(LocalizedTextUtilTest.class, "notinbundle", ActionContext.getContext().getLocale(), "hello", null, ActionContext.getContext().getValueStack());
+        assertEquals("hello", text2); // should log WARN
+
+        String text3 = LocalizedTextUtil.findText(LocalizedTextUtilTest.class, "notinbundle.key", ActionContext.getContext().getLocale(), "notinbundle.key", null, ActionContext.getContext().getValueStack());
+        assertEquals("notinbundle.key", text3); // should log WARN
+
+        String text4 = LocalizedTextUtil.findText(LocalizedTextUtilTest.class, "xw377", ActionContext.getContext().getLocale(), "hello", null, ActionContext.getContext().getValueStack());
+        assertEquals("xw377", text4); // should not log
+
+        String text5 = LocalizedTextUtil.findText(LocalizedTextUtilTest.class, "username", ActionContext.getContext().getLocale(), null, null, ActionContext.getContext().getValueStack());
+        assertEquals("Santa", text5); // should not log
+    }
+
+    public void testXW404() {
+        // This tests will try to load bundles from the 3 locales but we only have files for France and Germany.
+        // Before this fix loading the bundle for Germany failed since Italy have previously failed and thus the misses cache
+        // contained a false entry
+
+        ResourceBundle rbFrance = LocalizedTextUtil.findResourceBundle("com/opensymphony/xwork2/util/XW404", Locale.FRANCE);
+        ResourceBundle rbItaly = LocalizedTextUtil.findResourceBundle("com/opensymphony/xwork2/util/XW404", Locale.ITALY);
+        ResourceBundle rbGermany = LocalizedTextUtil.findResourceBundle("com/opensymphony/xwork2/util/XW404", Locale.GERMANY);
+
+        assertNotNull(rbFrance);
+        assertEquals("Bonjour", rbFrance.getString("hello"));
+
+        assertNull(rbItaly);
+
+        assertNotNull(rbGermany);
+        assertEquals("Hallo", rbGermany.getString("hello"));
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-sample.xml");
+        container.inject(provider);
+        loadConfigurationProviders(provider);
+
+        ActionContext.getContext().setLocale(Locale.US);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        LocalizedTextUtil.clearDefaultResourceBundles();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/MyBean.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/MyBean.java b/core/src/test/java/com/opensymphony/xwork2/util/MyBean.java
new file mode 100644
index 0000000..eb456fb
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/MyBean.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import java.io.Serializable;
+
+/**
+ * <code>MyBean</code>
+ *
+ * @author Rainer Hermanns
+ */
+public class MyBean implements Serializable {
+
+    private Long id;
+    private String name;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    @Override
+    public String toString() {
+        return "MyBean{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/MyBeanAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/MyBeanAction.java b/core/src/test/java/com/opensymphony/xwork2/util/MyBeanAction.java
new file mode 100644
index 0000000..96fd1e0
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/MyBeanAction.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.Action;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <code>MyBeanAction</code>
+ *
+ * @author Rainer Hermanns
+ */
+public class MyBeanAction implements Action {
+
+    private List beanList = new ArrayList();
+    private Map beanMap = new HashMap();
+
+    public List getBeanList() {
+        return beanList;
+    }
+
+    public void setBeanList(List beanList) {
+        this.beanList = beanList;
+    }
+
+    public Map getBeanMap() {
+        return beanMap;
+    }
+
+    public void setBeanMap(Map beanMap) {
+        this.beanMap = beanMap;
+    }
+
+    public String execute() throws Exception {
+        return SUCCESS;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/MyBeanActionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/MyBeanActionTest.java b/core/src/test/java/com/opensymphony/xwork2/util/MyBeanActionTest.java
new file mode 100644
index 0000000..9289de6
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/MyBeanActionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <code>MyBeanActionTest</code>
+ *
+ * @author Rainer Hermanns
+ */
+public class MyBeanActionTest extends XWorkTestCase {
+
+    public void testIndexedList() {
+        HashMap<String, Object> params = new HashMap<>();
+        params.put("beanList(1234567890).name", "This is the bla bean");
+        params.put("beanList(1234567891).name", "This is the 2nd bla bean");
+
+        HashMap<String, Object> extraContext = new HashMap<>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        try {
+            ActionProxy proxy = actionProxyFactory.createActionProxy("", "MyBean", extraContext);
+            proxy.execute();
+            assertEquals(2, Integer.parseInt(proxy.getInvocation().getStack().findValue("beanList.size").toString()));
+            assertEquals(MyBean.class.getName(), proxy.getInvocation().getStack().findValue("beanList.get(0)").getClass().getName());
+            assertEquals(MyBean.class.getName(), proxy.getInvocation().getStack().findValue("beanList.get(1)").getClass().getName());
+
+            assertEquals("This is the bla bean", proxy.getInvocation().getStack().findValue("beanList.get(0).name"));
+            assertEquals(new Long(1234567890), Long.valueOf(proxy.getInvocation().getStack().findValue("beanList.get(0).id").toString()));
+            assertEquals("This is the 2nd bla bean", proxy.getInvocation().getStack().findValue("beanList.get(1).name"));
+            assertEquals(new Long(1234567891), Long.valueOf(proxy.getInvocation().getStack().findValue("beanList.get(1).id").toString()));
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    public void testIndexedMap() {
+        HashMap<String, Object> params = new HashMap<>();
+        params.put("beanMap[1234567890].id", "1234567890");
+        params.put("beanMap[1234567891].id", "1234567891");
+
+        params.put("beanMap[1234567890].name", "This is the bla bean");
+        params.put("beanMap[1234567891].name", "This is the 2nd bla bean");
+
+        HashMap<String, Object> extraContext = new HashMap<>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+
+        try {
+            ActionProxy proxy = actionProxyFactory.createActionProxy("", "MyBean", extraContext);
+            proxy.execute();
+            MyBeanAction action = (MyBeanAction) proxy.getInvocation().getAction();
+
+            assertEquals(2, Integer.parseInt(proxy.getInvocation().getStack().findValue("beanMap.size").toString()));
+
+            Map map = (Map) proxy.getInvocation().getStack().findValue("beanMap");
+            assertEquals(true, action.getBeanMap().containsKey(1234567890L));
+            assertEquals(true, action.getBeanMap().containsKey(1234567891L));
+
+
+            assertEquals(MyBean.class.getName(), proxy.getInvocation().getStack().findValue("beanMap.get(1234567890L)").getClass().getName());
+            assertEquals(MyBean.class.getName(), proxy.getInvocation().getStack().findValue("beanMap.get(1234567891L)").getClass().getName());
+
+            assertEquals("This is the bla bean", proxy.getInvocation().getStack().findValue("beanMap.get(1234567890L).name"));
+            assertEquals("This is the 2nd bla bean", proxy.getInvocation().getStack().findValue("beanMap.get(1234567891L).name"));
+
+            assertEquals("1234567890", proxy.getInvocation().getStack().findValue("beanMap.get(1234567890L).id").toString());
+            assertEquals("1234567891", proxy.getInvocation().getStack().findValue("beanMap.get(1234567891L).id").toString());
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // ensure we're using the default configuration, not simple config
+        XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-sample.xml");
+        container.inject(provider);
+        loadConfigurationProviders(provider);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java b/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
new file mode 100644
index 0000000..b659731
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.util.NamedVariablePatternMatcher.CompiledPattern;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.*;
+
+public class NamedVariablePatternMatcherTest {
+
+    @Test
+    public void testCompile() {
+        NamedVariablePatternMatcher matcher = new NamedVariablePatternMatcher();
+
+        assertNull(matcher.compilePattern(null));
+        assertNull(matcher.compilePattern(""));
+
+        CompiledPattern pattern = matcher.compilePattern("foo");
+        assertEquals("foo", pattern.getPattern().pattern());
+
+        pattern = matcher.compilePattern("foo{jim}");
+        assertEquals("foo([^/]+)", pattern.getPattern().pattern());
+        assertEquals("jim", pattern.getVariableNames().get(0));
+
+        pattern = matcher.compilePattern("foo{jim}/{bob}");
+        assertEquals("foo([^/]+)/([^/]+)", pattern.getPattern().pattern());
+        assertEquals("jim", pattern.getVariableNames().get(0));
+        assertEquals("bob", pattern.getVariableNames().get(1));
+        assertTrue(pattern.getPattern().matcher("foostar/jie").matches());
+        assertFalse(pattern.getPattern().matcher("foo/star/jie").matches());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCompileWithMismatchedBracketsParses() {
+        NamedVariablePatternMatcher matcher = new NamedVariablePatternMatcher();
+
+        matcher.compilePattern("}");
+    }
+
+    @Test
+    public void testMatch() {
+        NamedVariablePatternMatcher matcher = new NamedVariablePatternMatcher();
+
+        Map<String, String> vars = new HashMap<>();
+        CompiledPattern pattern = new CompiledPattern(Pattern.compile("foo([^/]+)"), Arrays.asList("bar"));
+
+        assertTrue(matcher.match(vars, "foobaz", pattern));
+        assertEquals("baz", vars.get("bar"));
+    }
+
+    @Test
+    public void testIsLiteral() {
+        NamedVariablePatternMatcher matcher = new NamedVariablePatternMatcher();
+
+        assertTrue(matcher.isLiteral("bob"));
+        assertFalse(matcher.isLiteral("bob{jim}"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/Owner.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/Owner.java b/core/src/test/java/com/opensymphony/xwork2/util/Owner.java
new file mode 100644
index 0000000..450e215
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/Owner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class Owner {
+
+    private Dog dog;
+
+
+    public void setDog(Dog dog) {
+        this.dog = dog;
+    }
+
+    public Dog getDog() {
+        return dog;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/ResolverUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/ResolverUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/util/ResolverUtilTest.java
new file mode 100644
index 0000000..791abe7
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/ResolverUtilTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.spring.SpringObjectFactory;
+import junit.framework.TestCase;
+
+import java.net.URL;
+import java.util.Set;
+
+public class ResolverUtilTest extends TestCase {
+
+    public void testSimpleFind() throws Exception {
+        ResolverUtil<ObjectFactory> resolver = new ResolverUtil<>();
+        resolver.findImplementations(ObjectFactory.class, "com");
+        Set<Class<? extends ObjectFactory>> impls = resolver.getClasses();
+        
+        assertTrue(impls.contains(ObjectFactory.class));
+        assertTrue(impls.contains(SpringObjectFactory.class));
+    }
+    
+    public void testMissingSomeFind() throws Exception {
+        ResolverUtil<ObjectFactory> resolver = new ResolverUtil<>();
+        resolver.findImplementations(ObjectFactory.class, "com.opensymphony.xwork2.spring");
+        Set<Class<? extends ObjectFactory>> impls = resolver.getClasses();
+        
+        assertFalse(impls.contains(ObjectFactory.class));
+        assertTrue(impls.contains(SpringObjectFactory.class));
+    }
+    
+    public void testFindNamedResource() throws Exception {
+        ResolverUtil resolver = new ResolverUtil();
+        resolver.findNamedResource("xwork-default.xml", "");
+        Set<URL> impls = resolver.getResources();
+        
+        assertTrue(impls.size() > 0);
+    }
+    
+    public void testFindNamedResourceInDir() throws Exception {
+        ResolverUtil resolver = new ResolverUtil();
+        resolver.findNamedResource("SimpleAction.properties", "com/opensymphony");
+        Set<URL> impls = resolver.getResources();
+        
+        assertTrue(impls.size() > 0);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
new file mode 100644
index 0000000..b6f68d4
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.XWorkTestCase;
+import org.junit.Assert;
+
+import java.util.*;
+
+/**
+ * Unit test of {@link TextParseUtil}.
+ *
+ * @author plightbo
+ * @author tm_jee
+ *
+ * @version $Date$ $Id$
+ */
+public class TextParseUtilTest extends XWorkTestCase {
+
+
+	public void testTranslateVariablesWithEvaluator() throws Exception {
+		ValueStack stack = ActionContext.getContext().getValueStack();
+		stack.push(new Object() {
+			public String getMyVariable() {
+				return "My Variable ";
+			}
+		});
+
+		TextParseUtil.ParsedValueEvaluator evaluator = new TextParseUtil.ParsedValueEvaluator() {
+			public Object evaluate(String parsedValue) {
+                return parsedValue + "Something";
+            }
+		};
+
+		String result = TextParseUtil.translateVariables("Hello ${myVariable}", stack, evaluator);
+
+		assertEquals(result, "Hello My Variable Something");
+	}
+
+    public void testTranslateVariables() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+
+        Object s = TextParseUtil.translateVariables("foo: ${{1, 2, 3}}, bar: %{1}", stack);
+        assertEquals("foo: [1, 2, 3], bar: 1", s);
+
+        s = TextParseUtil.translateVariables("foo: %{{1, 2, 3}}, bar: %{1}", stack);
+        assertEquals("foo: [1, 2, 3], bar: 1", s);
+
+        s = TextParseUtil.translateVariables("foo: %{{1, 2, 3}}, bar: %{1}", stack);
+        assertEquals("foo: [1, 2, 3], bar: 1", s);
+
+        s = TextParseUtil.translateVariables("foo: ${#{1 : 2, 3 : 4}}, bar: ${1}", stack);
+        assertEquals("foo: {1=2, 3=4}, bar: 1", s);
+
+        s = TextParseUtil.translateVariables("foo: %{#{1 : 2, 3 : 4}}, bar: %{1}", stack);
+        assertEquals("foo: {1=2, 3=4}, bar: 1", s);
+
+        s = TextParseUtil.translateVariables("foo: 1}", stack);
+        assertEquals("foo: 1}", s);
+
+        s = TextParseUtil.translateVariables("foo: {1}", stack);
+        assertEquals("foo: {1}", s);
+
+        s = TextParseUtil.translateVariables("foo: ${1", stack);
+        assertEquals("foo: ${1", s);
+
+        s = TextParseUtil.translateVariables("foo: %{1", stack);
+        assertEquals("foo: %{1", s);
+
+        s =  TextParseUtil.translateVariables('$', "${{1, 2, 3}}", stack, Object.class);
+        assertNotNull(s);
+        assertTrue("List not returned when parsing a 'pure' list", s instanceof List);
+        assertEquals(((List)s).size(), 3);
+
+        s = TextParseUtil.translateVariables('$', "${#{'key1':'value1','key2':'value2','key3':'value3'}}", stack, Object.class);
+        assertNotNull(s);
+        assertTrue("Map not returned when parsing a 'pure' map", s instanceof Map);
+        assertEquals(((Map)s).size(), 3);
+
+        s =  TextParseUtil.translateVariables('$', "${1} two ${3}", stack, Object.class);
+        assertEquals("1 two 3", s);
+
+        s = TextParseUtil.translateVariables('$', "count must be between ${123} and ${456}, current value is ${98765}.", stack, Object.class);
+        assertEquals("count must be between 123 and 456, current value is 98765.", s);
+    }
+
+    public void testNestedExpression() throws Exception {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(new HashMap<String, Object>() {{ put("foo", "${%{1+1}}"); }});
+        String s = TextParseUtil.translateVariables("${foo}", stack);
+        assertEquals("${%{1+1}}", s);
+        stack.pop();
+    }
+
+    public void testMixedOpenChars() throws Exception {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(new HashMap<String, Object>() {{ put("foo", "bar"); }});
+        String s = TextParseUtil.translateVariables("${foo}-%{foo}", stack);
+        assertEquals("bar-bar", s);
+        s = TextParseUtil.translateVariables("%{foo}-${foo}", stack);
+        assertEquals("%{foo}-bar", s); // this is bad, but it is the only way not to double evaluate passed expression
+        stack.pop();
+    }
+
+    public void testCommaDelimitedStringToSet() {
+        assertEquals(0, TextParseUtil.commaDelimitedStringToSet("").size());
+        assertEquals(new HashSet<>(Arrays.asList("foo", "bar", "tee")),
+                TextParseUtil.commaDelimitedStringToSet(" foo, bar,tee"));
+    }
+
+    public void testTranslateVariablesOpenChar() {
+        // just a quick test to see if the open char works
+        // most test are done the methods above
+        ValueStack stack = ActionContext.getContext().getValueStack();
+
+        Object s = TextParseUtil.translateVariables('$', "foo: ${{1, 2, 3}}, bar: ${1}", stack);
+        assertEquals("foo: [1, 2, 3], bar: 1", s);
+
+        Object s2 = TextParseUtil.translateVariables('#', "foo: #{{1, 2, 3}}, bar: #{1}", stack);
+        assertEquals("foo: [1, 2, 3], bar: 1", s2);
+    }
+
+    public void testTranslateNoVariables() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+
+        Object s = TextParseUtil.translateVariables('$', "foo: ${}", stack);
+        assertEquals("foo: ", s);
+    }
+
+    public void testTranslateVariablesNoRecursive() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(new HashMap<String, Object>() {{ put("foo", "${1+1}"); }});
+
+        Object s = TextParseUtil.translateVariables('$', "foo: ${foo}", stack, String.class, null, 1);
+        assertEquals("foo: ${1+1}", s);
+    }
+
+    public void testTranslateVariablesRecursive() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(new HashMap<String, Object>() {{ put("foo", "${1+1}"); put("bar", "${${1+2}}"); }});
+
+        Object s = TextParseUtil.translateVariables('$', "foo: ${foo}", stack, String.class, null, 2);
+        assertEquals("foo: 2", s);
+
+        s = TextParseUtil.translateVariables('$', "foo: ${bar}", stack, String.class, null, 1);
+        assertEquals("foo: ${${1+2}}", s);
+    }
+
+    public void testTranslateVariablesWithNull() {
+        // given
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(new HashMap<String, Object>() {{ put("foo", null); }});
+
+        TextParseUtil.ParsedValueEvaluator evaluator = new TextParseUtil.ParsedValueEvaluator() {
+            public Object evaluate(String parsedValue) {
+                return parsedValue;
+            }
+        };
+
+        // when
+        Object s = TextParseUtil.translateVariables('$', "foo: ${foo}", stack, String.class, evaluator, 2);
+
+        // then
+        assertEquals("foo: ", s);
+    }
+
+    public void testTranslateVariablesCollection() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        final List<String> list = new ArrayList<String>() {{
+            add("val 1");
+            add("val 2");
+        }};
+        stack.push(new HashMap<String, Object>() {{ put("list", list); }});
+
+        Collection<String> collection = TextParseUtil.translateVariablesCollection("${list}", stack, true, null);
+
+        Assert.assertNotNull(collection);
+        Assert.assertEquals(2, collection.size());
+    }
+
+    public void testTranslateVariablesCollectionWithExpressions() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        final List<String> list = new ArrayList<String>() {{
+            add("${val1}");
+            add("%{val2}");
+        }};
+        stack.push(new HashMap<String, Object>() {{ put("list", list); put("val1", 1); put("val2", "Value 2"); }});
+
+        Collection<String> collection = TextParseUtil.translateVariablesCollection("${list}", stack, true, null);
+
+        Assert.assertNotNull(collection);
+        Assert.assertEquals(2, collection.size());
+
+        // if this starts passing, probably an double evaluation expression vulnerability was introduced
+        // carefully review changes as this can affect users and allows break in intruders
+        Assert.assertEquals("${val1}", collection.toArray()[0]);
+        Assert.assertEquals("%{val2}", collection.toArray()[1]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/Tiger.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/Tiger.java b/core/src/test/java/com/opensymphony/xwork2/util/Tiger.java
new file mode 100644
index 0000000..2be7783
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/Tiger.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import java.util.List;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class Tiger extends Cat {
+
+    List dogs;
+
+
+    public void setDogs(List dogs) {
+        this.dogs = dogs;
+    }
+
+    public List getDogs() {
+        return dogs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/URLUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/URLUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/util/URLUtilTest.java
new file mode 100644
index 0000000..e0c0096
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/URLUtilTest.java
@@ -0,0 +1,177 @@
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.util.fs.DefaultFileManager;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.*;
+
+public class URLUtilTest extends TestCase {
+
+    private FileManager fileManager;
+
+    public void testSimpleFile() throws MalformedURLException {
+        URL url = new URL("file:c:/somefile.txt");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNull(outputURL);
+    }
+
+    public void testJarFile() throws MalformedURLException {
+        URL url = new URL("jar:file:/c:/somefile.jar!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("jar:file:/c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("jar:file:c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/somefile.jar", outputURL.toExternalForm());
+    }
+
+    public void testJarFileWithJarWordInsidePath() throws MalformedURLException {
+        URL url = new URL("jar:file:/c:/workspace/projar/somefile.jar!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/workspace/projar/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("jar:file:/c:/workspace/projar/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/workspace/projar/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("jar:file:c:/workspace/projar/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/workspace/projar/somefile.jar", outputURL.toExternalForm());
+    }
+
+    public void testZipFile() throws MalformedURLException {
+        URL url = new URL("zip:/c:/somefile.zip!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/somefile.zip", outputURL.toExternalForm());
+
+        url = new URL("zip:/c:/somefile.zip!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.zip", outputURL.toExternalForm());
+
+        url = new URL("zip:c:/somefile.zip!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/somefile.zip", outputURL.toExternalForm());
+    }
+
+    public void testWSJarFile() throws MalformedURLException {
+        URL url = new URL("wsjar:file:/c:/somefile.jar!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("wsjar:file:/c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("wsjar:file:c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/somefile.jar", outputURL.toExternalForm());
+    }
+
+    public void testVsFile() throws MalformedURLException {
+        URL url = new URL("vfsfile:/c:/somefile.jar!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfsfile:/c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfsfile:c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfszip:/c:/somefile.war/somelibrary.jar");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.war/somelibrary.jar", outputURL.toExternalForm());
+    }
+
+    public void testJBossFile() throws MalformedURLException {
+        URL url = new URL("vfszip:/c:/somefile.jar!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(url);
+
+        assertNotNull(outputURL);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfszip:/c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfsmemory:c:/somefile.jar!/somestuf/bla/bla");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:c:/somefile.jar", outputURL.toExternalForm());
+
+        url = new URL("vfsmemory:/c:/somefile.war/somelibrary.jar");
+        outputURL = fileManager.normalizeToFileProtocol(url);
+        assertEquals("file:/c:/somefile.war/somelibrary.jar", outputURL.toExternalForm());
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        try {
+            URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
+                public URLStreamHandler createURLStreamHandler(String protocol) {
+                    return new URLStreamHandler() {
+                        protected URLConnection openConnection(URL u) throws IOException {
+                            return null;
+                        }
+                    };
+                }
+            });
+        } catch (Throwable e) {
+            //the factory cant be set multiple times..just ignore exception no biggie
+        }
+        
+        this.fileManager = new DefaultFileManager();
+    }
+
+    public void testVerifyUrl() {
+        assertEquals(false, URLUtil.verifyUrl(null));
+        assertEquals(false, URLUtil.verifyUrl(""));
+        assertEquals(false, URLUtil.verifyUrl("   "));
+        assertEquals(false, URLUtil.verifyUrl("no url"));
+        assertEquals(false, URLUtil.verifyUrl("http://no url"));
+        assertEquals(false, URLUtil.verifyUrl("https://no url"));
+
+        assertEquals(true, URLUtil.verifyUrl("http://www.opensymphony.com"));
+        assertEquals(true, URLUtil.verifyUrl("https://www.opensymphony.com"));
+        assertEquals(true, URLUtil.verifyUrl("https://www.opensymphony.com:443/login"));
+        assertEquals(true, URLUtil.verifyUrl("http://localhost:8080/myapp"));
+    }
+/*
+
+    TODO lukaszlenart: move to DefaultFileManagerTest (or separate class)
+
+    public void testIsJarURL() throws Exception {
+        assertTrue(fileManager.isJarURL(new URL("jar:file:/c:/somelibrary.jar!/com/opensymphony")));
+        assertTrue(URLUtil.isJarURL(new URL("zip:/c:/somelibrary.jar!/com/opensymphony")));
+        assertTrue(URLUtil.isJarURL(new URL("wsjar:/c:/somelibrary.jar!/com/opensymphony")));
+        assertTrue(URLUtil.isJarURL(new URL("vfsfile:/c:/somelibrary.jar!/com/opensymphony")));
+        assertTrue(URLUtil.isJarURL(new URL("vfszip:/c:/somelibrary.jar/com/opensymphony")));
+    }
+
+    public void testIsJBoss5Url() throws Exception {
+        assertTrue(URLUtil.isJBossUrl(new URL("vfszip:/c:/somewar.war/somelibrary.jar")));
+        assertFalse(URLUtil.isJBossUrl(new URL("vfsfile:/c:/somewar.war/somelibrary.jar")));
+        assertFalse(URLUtil.isJBossUrl(new URL("jar:file:/c:/somelibrary.jar")));
+        assertTrue(URLUtil.isJBossUrl(new URL("vfsmemory:/c:/somewar.war/somelibrary.jar")));
+    }
+*/
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/UnknownHandlerManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/UnknownHandlerManagerTest.java b/core/src/test/java/com/opensymphony/xwork2/util/UnknownHandlerManagerTest.java
new file mode 100644
index 0000000..9533eb0
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/UnknownHandlerManagerTest.java
@@ -0,0 +1,82 @@
+package com.opensymphony.xwork2.util;
+
+import java.util.List;
+
+import com.opensymphony.xwork2.UnknownHandler;
+import com.opensymphony.xwork2.UnknownHandlerManager;
+import com.opensymphony.xwork2.UnknownHandlerManagerMock;
+import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.ConfigurationTestBase;
+import com.opensymphony.xwork2.config.providers.SomeUnknownHandler;
+
+/**
+ * Test UnknownHandlerUtil
+ */
+public class UnknownHandlerManagerTest extends ConfigurationTestBase {
+
+    public void testStack() throws ConfigurationException {
+        final String filename = "com/opensymphony/xwork2/config/providers/xwork-unknownhandler-stack.xml";
+        ConfigurationProvider provider = buildConfigurationProvider(filename);
+        loadConfigurationProviders(provider);
+        configurationManager.reload();
+
+        UnknownHandlerManager unknownHandlerManager = new DefaultUnknownHandlerManager();
+        container.inject(unknownHandlerManager);
+        List<UnknownHandler> unknownHandlers = unknownHandlerManager.getUnknownHandlers();
+
+        assertNotNull(unknownHandlers);
+        assertEquals(2, unknownHandlers.size());
+
+        UnknownHandler uh1 = unknownHandlers.get(0);
+        UnknownHandler uh2 = unknownHandlers.get(1);
+
+        assertTrue(uh1 instanceof SomeUnknownHandler);
+        assertTrue(uh2 instanceof SomeUnknownHandler);
+    }
+
+    public void testEmptyStack() throws ConfigurationException {
+        final String filename = "com/opensymphony/xwork2/config/providers/xwork-unknownhandler-stack-empty.xml";
+        ConfigurationProvider provider = buildConfigurationProvider(filename);
+        loadConfigurationProviders(provider);
+        configurationManager.reload();
+
+        UnknownHandlerManager unknownHandlerManager = new DefaultUnknownHandlerManager();
+        container.inject(unknownHandlerManager);
+        List<UnknownHandler> unknownHandlers = unknownHandlerManager.getUnknownHandlers();
+
+        assertNotNull(unknownHandlers);
+        assertEquals(2, unknownHandlers.size());
+
+        UnknownHandler uh1 = unknownHandlers.get(0);
+        UnknownHandler uh2 = unknownHandlers.get(1);
+
+        assertTrue(uh1 instanceof SomeUnknownHandler);
+        assertTrue(uh2 instanceof SomeUnknownHandler);
+    }
+
+    public void testInvocationOrder() throws ConfigurationException, NoSuchMethodException {
+        SomeUnknownHandler uh1 = new SomeUnknownHandler();
+        uh1.setActionMethodResult("uh1");
+
+        SomeUnknownHandler uh2 = new SomeUnknownHandler();
+        uh2.setActionMethodResult("uh2");
+
+        UnknownHandlerManagerMock uhm = new UnknownHandlerManagerMock();
+        uhm.addUnknownHandler(uh1);
+        uhm.addUnknownHandler(uh2);
+
+        //should pick the first one
+        assertEquals("uh1", uhm.handleUnknownMethod(null, null));
+
+        //should pick the second one
+        uh1.setActionMethodResult(null);
+        assertEquals("uh2", uhm.handleUnknownMethod(null, null));
+
+        //should not pick any
+        uh1.setActionMethodResult(null);
+        uh2.setActionMethodResult(null);
+        assertEquals(null, uhm.handleUnknownMethod(null, null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/UrlUtilTest2.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/UrlUtilTest2.java b/core/src/test/java/com/opensymphony/xwork2/util/UrlUtilTest2.java
new file mode 100644
index 0000000..bfc306b
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/UrlUtilTest2.java
@@ -0,0 +1,35 @@
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.util.fs.DefaultFileManager;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarInputStream;
+
+/**
+ * Keep these test on a separate class, they can't be in UrlUtilTest because the
+ * registered URLStreamHandlerFactory would make them fail
+ */
+public class UrlUtilTest2 extends TestCase {
+
+    public void testOpenWithJarProtocol() throws IOException {
+        FileManager fileManager = new DefaultFileManager();
+
+        URL url = ClassLoaderUtil.getResource("xwork-jar.jar", URLUtil.class);
+        URL jarUrl = new URL("jar", "", url.toExternalForm() + "!/");
+        URL outputURL = fileManager.normalizeToFileProtocol(jarUrl);
+
+        assertNotNull(outputURL);
+        assertUrlCanBeOpened(outputURL);
+    }
+
+    private void assertUrlCanBeOpened(URL url) throws IOException {
+        InputStream is = url.openStream();
+        try (JarInputStream jarStream = new JarInputStream(is)) {
+            assertNotNull(jarStream);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java b/core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java
new file mode 100644
index 0000000..6cbd6d2
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.XWorkTestCase;
+
+import java.util.HashMap;
+
+public class WildcardHelperTest extends XWorkTestCase {
+	
+	public void testMatch() {
+		
+		WildcardHelper wild = new WildcardHelper();
+		HashMap<String, String> matchedPatterns = new HashMap<>();
+		int[] pattern = wild.compilePattern("wes-rules");
+		assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
+		assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
+		
+		pattern = wild.compilePattern("wes-*");
+		assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
+		assertEquals("rules".equals(matchedPatterns.get("1")), true);
+		assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
+		
+		pattern = wild.compilePattern("path/**/file");
+		assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
+		assertEquals("to".equals(matchedPatterns.get("1")), true);
+		assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
+		assertEquals("to/another/location/of".equals(matchedPatterns.get("1")), true);
+		
+		pattern = wild.compilePattern("path/*/file");
+		assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
+		assertEquals("to".equals(matchedPatterns.get("1")), true);
+		assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), false);
+
+		pattern = wild.compilePattern("path/*/another/**/file");
+		assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
+		assertEquals("to".equals(matchedPatterns.get("1")), true);
+		assertEquals("location/of".equals(matchedPatterns.get("2")), true);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java
new file mode 100644
index 0000000..79bb924
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.XWorkTestCase;
+
+import java.util.regex.Pattern;
+
+public class WildcardUtilTest extends XWorkTestCase {
+	
+	public void testPattern() {
+		
+		Pattern p = WildcardUtil.compileWildcardPattern("a*b");
+		assertTrue(p.matcher("ab").matches());
+		assertTrue(p.matcher("axyb").matches());
+		assertFalse(p.matcher("bxyb").matches());
+		
+		p = WildcardUtil.compileWildcardPattern("a\\*b");
+		assertFalse(p.matcher("ab").matches());
+		assertTrue(p.matcher("a*b").matches());
+		
+		p = WildcardUtil.compileWildcardPattern("a.*");
+		assertFalse(p.matcher("ab").matches());
+		assertFalse(p.matcher("ab.b").matches());
+		assertTrue(p.matcher("a.b").matches());
+		assertTrue(p.matcher("a.bc").matches());
+		assertTrue(p.matcher("a.b.c").matches());
+		
+		p = WildcardUtil.compileWildcardPattern("a[*]");
+		assertFalse(p.matcher("ab").matches());
+		assertFalse(p.matcher("ab[b]").matches());
+		assertTrue(p.matcher("a[b]").matches());
+		assertTrue(p.matcher("a[bc]").matches());
+		assertFalse(p.matcher("a[b].c").matches());
+
+		p = WildcardUtil.compileWildcardPattern("a[*].*");
+		assertTrue(p.matcher("a[b].c").matches());
+		assertTrue(p.matcher("a[bc].cd").matches());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/util/XWorkListTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/XWorkListTest.java b/core/src/test/java/com/opensymphony/xwork2/util/XWorkListTest.java
new file mode 100644
index 0000000..412673f
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/util/XWorkListTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import com.opensymphony.xwork2.XWorkTestCase;
+
+import java.util.ArrayList;
+
+
+/**
+ * Test cases for {@link XWorkList}.
+ *
+ * @author Mark Woon
+ */
+public class XWorkListTest extends XWorkTestCase {
+
+    public void testAddAllIndex() {
+        XWorkList xworkList = new XWorkList(String.class);
+        xworkList.add(new String[]{"a"});
+        xworkList.add("b");
+
+        ArrayList<String[]> addList = new ArrayList<>();
+        addList.add(new String[]{"1"});
+        addList.add(new String[]{"2"});
+        addList.add(new String[]{"3"});
+
+        // trim
+        xworkList.addAll(3, addList);
+        assertEquals(6, xworkList.size());
+        assertEquals("a", xworkList.get(0));
+        assertEquals("b", xworkList.get(1));
+        assertEquals("", xworkList.get(2));
+        assertEquals("1", xworkList.get(3));
+        assertEquals("2", xworkList.get(4));
+        assertEquals("3", xworkList.get(5));
+
+        // take 2, no trim
+        xworkList = new XWorkList(String.class);
+        xworkList.add(new String[]{"a"});
+        xworkList.add("b");
+
+        addList = new ArrayList<>();
+        addList.add(new String[]{"1"});
+        addList.add(new String[]{"2"});
+        addList.add(new String[]{"3"});
+
+        xworkList.addAll(2, addList);
+        assertEquals(5, xworkList.size());
+        assertEquals("a", xworkList.get(0));
+        assertEquals("b", xworkList.get(1));
+        assertEquals("1", xworkList.get(2));
+        assertEquals("2", xworkList.get(3));
+        assertEquals("3", xworkList.get(4));
+
+        // take 3, insert
+        xworkList = new XWorkList(String.class);
+        xworkList.add(new String[]{"a"});
+        xworkList.add("b");
+
+        addList = new ArrayList<>();
+        addList.add(new String[]{"1"});
+        addList.add(new String[]{"2"});
+        addList.add(new String[]{"3"});
+
+        xworkList.addAll(1, addList);
+        assertEquals(5, xworkList.size());
+        assertEquals("a", xworkList.get(0));
+        assertEquals("1", xworkList.get(1));
+        assertEquals("2", xworkList.get(2));
+        assertEquals("3", xworkList.get(3));
+        assertEquals("b", xworkList.get(4));
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/validator/ActionValidatorManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/ActionValidatorManagerTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/ActionValidatorManagerTest.java
new file mode 100644
index 0000000..6d7eeeb
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/ActionValidatorManagerTest.java
@@ -0,0 +1,216 @@
+package com.opensymphony.xwork2.validator;
+
+import com.opensymphony.xwork2.ActionSupport;
+import com.opensymphony.xwork2.XWorkTestCase;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.validator.validators.RequiredFieldValidator;
+import com.opensymphony.xwork2.validator.validators.RequiredStringValidator;
+import com.opensymphony.xwork2.validator.validators.VisitorFieldValidator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A test case for ActionValidatorManager.
+ *
+ * @author tmjee
+ * @version $Date$ $Id$
+ */
+public class ActionValidatorManagerTest extends XWorkTestCase {
+
+
+
+    public void testValidate() throws Exception {
+        /* MockAction.class */
+        // reference number
+        ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
+        final RequiredStringValidator referenceNumberRequiredStringValidator = new RequiredStringValidator();
+        referenceNumberRequiredStringValidator.setFieldName("referenceNumber");
+        referenceNumberRequiredStringValidator.setDefaultMessage("Reference number is required");
+        referenceNumberRequiredStringValidator.setValueStack(stack);
+
+        // order
+        final RequiredFieldValidator orderRequiredValidator = new RequiredFieldValidator();
+        orderRequiredValidator.setFieldName("order");
+        orderRequiredValidator.setDefaultMessage("Order is required");
+        orderRequiredValidator.setValueStack(stack);
+
+        // customer
+        final RequiredFieldValidator customerRequiredValidator = new RequiredFieldValidator();
+        customerRequiredValidator.setFieldName("customer");
+        customerRequiredValidator.setDefaultMessage("Customer is required");
+        customerRequiredValidator.setValueStack(stack);
+        final VisitorFieldValidator customerVisitorValidator = new VisitorFieldValidator();
+        customerVisitorValidator.setAppendPrefix(true);
+        customerVisitorValidator.setFieldName("customer");
+        customerVisitorValidator.setValueStack(stack);
+
+        /* Customer.class */
+        // customer -> name
+        final RequiredStringValidator customerNameRequiredStringValidator = new RequiredStringValidator();
+        customerNameRequiredStringValidator.setFieldName("name");
+        customerNameRequiredStringValidator.setDefaultMessage("Name is required");
+        customerNameRequiredStringValidator.setValueStack(stack);
+
+        // customer -> age
+        final RequiredFieldValidator customerAgeRequiredValidator = new RequiredFieldValidator();
+        customerAgeRequiredValidator.setFieldName("age");
+        customerAgeRequiredValidator.setDefaultMessage("Age is required");
+        customerAgeRequiredValidator.setValueStack(stack);
+
+        // customer -> Address
+        final RequiredFieldValidator customerAddressRequiredFieldValidator = new RequiredFieldValidator();
+        customerAddressRequiredFieldValidator.setFieldName("address");
+        customerAddressRequiredFieldValidator.setDefaultMessage("Address is required");
+        customerAddressRequiredFieldValidator.setValueStack(stack);
+
+        final VisitorFieldValidator customerAddressVisitorFieldValidator = new VisitorFieldValidator();
+        customerAddressVisitorFieldValidator.setFieldName("address");
+        customerAddressVisitorFieldValidator.setAppendPrefix(true);
+        //customerAddressVisitorFieldValidator.setDefaultMessage("");
+        customerAddressVisitorFieldValidator.setValueStack(stack);
+
+
+
+        /* Address.class */
+        // customer -> Address -> street
+        final RequiredStringValidator customerAddressStreetRequiredFieldValidator = new RequiredStringValidator();
+        customerAddressStreetRequiredFieldValidator.setFieldName("street");
+        customerAddressStreetRequiredFieldValidator.setDefaultMessage("Street is required");
+        customerAddressStreetRequiredFieldValidator.setShortCircuit(true);
+        customerAddressStreetRequiredFieldValidator.setValueStack(stack);
+
+        final RequiredStringValidator customerAddressStreetRequiredFieldValidator2 = new RequiredStringValidator();
+        customerAddressStreetRequiredFieldValidator2.setFieldName("street");
+        customerAddressStreetRequiredFieldValidator2.setDefaultMessage("Street is required 2");
+        customerAddressStreetRequiredFieldValidator2.setShortCircuit(true);
+        customerAddressStreetRequiredFieldValidator2.setValueStack(stack);
+
+        // customer -> Address -> pobox
+        final RequiredStringValidator customerAddressPoboxRequiredFieldValidator = new RequiredStringValidator();
+        customerAddressPoboxRequiredFieldValidator.setFieldName("pobox");
+        customerAddressPoboxRequiredFieldValidator.setDefaultMessage("PO Box is required");
+        customerAddressPoboxRequiredFieldValidator.setShortCircuit(false);
+        customerAddressPoboxRequiredFieldValidator.setValueStack(stack);
+
+        final RequiredStringValidator customerAddressPoboxRequiredFieldValidator2 = new RequiredStringValidator();
+        customerAddressPoboxRequiredFieldValidator2.setFieldName("pobox");
+        customerAddressPoboxRequiredFieldValidator2.setDefaultMessage("PO Box is required 2");
+        customerAddressPoboxRequiredFieldValidator2.setShortCircuit(false);
+        customerAddressPoboxRequiredFieldValidator2.setValueStack(stack);
+
+
+
+        final List<Validator> validatorsForMockAction = new ArrayList<Validator>() {
+            {
+                add(referenceNumberRequiredStringValidator);
+                add(orderRequiredValidator);
+                add(customerRequiredValidator);
+                add(customerVisitorValidator);
+            }
+        };
+
+        final List<Validator> validatorsForCustomer = new ArrayList<Validator>() {
+            {
+                add(customerNameRequiredStringValidator);
+                add(customerAgeRequiredValidator);
+                add(customerAddressRequiredFieldValidator);
+                add(customerAddressVisitorFieldValidator);
+            }
+        };
+
+        final List<Validator> validatorsForAddress = new ArrayList<Validator>() {
+            {
+                add(customerAddressStreetRequiredFieldValidator);
+                add(customerAddressStreetRequiredFieldValidator2);
+                add(customerAddressPoboxRequiredFieldValidator);
+                add(customerAddressPoboxRequiredFieldValidator2);
+            }
+        };
+
+
+        DefaultActionValidatorManager validatorManager = new DefaultActionValidatorManager() {
+            @Override
+            public List<Validator> getValidators(Class clazz, String context, String method) {
+                if (clazz.isAssignableFrom(MockAction.class)) {
+                    return validatorsForMockAction;
+                }
+                else if (clazz.isAssignableFrom(Customer.class)) {
+                    return validatorsForCustomer;
+                }
+                else if (clazz.isAssignableFrom(Address.class)) {
+                    return validatorsForAddress;
+                }
+                return Collections.emptyList();
+            }
+        };
+        customerVisitorValidator.setActionValidatorManager(validatorManager);
+        customerAddressVisitorFieldValidator.setActionValidatorManager(validatorManager);
+
+        MockAction action = new MockAction();
+        stack.push(action);
+        validatorManager.validate(action, "ctx");
+
+        assertFalse(action.hasActionErrors());
+        assertFalse(action.hasActionMessages());
+        assertTrue(action.hasFieldErrors());
+        assertTrue(action.getFieldErrors().containsKey("referenceNumber"));
+        assertEquals((action.getFieldErrors().get("referenceNumber")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("order"));
+        assertEquals((action.getFieldErrors().get("order")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.name"));
+        assertEquals((action.getFieldErrors().get("customer.name")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.age"));
+        assertEquals((action.getFieldErrors().get("customer.age")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.address.street"));
+        assertEquals((action.getFieldErrors().get("customer.address.street")).size(), 1);
+        assertTrue(action.getFieldErrors().containsKey("customer.address.pobox"));
+        assertEquals((action.getFieldErrors().get("customer.address.pobox")).size(), 2);
+    }
+
+    private class MockAction extends ActionSupport {
+
+        private String referenceNumber;
+        private Integer order;
+        private Customer customer = new Customer();
+
+
+        public String getReferenceNumber() { return referenceNumber; }
+        public void setReferenceNumber(String referenceNumber) { this.referenceNumber = referenceNumber; }
+
+        public Integer getOrder() { return order; }
+        public void setOrder(Integer order) { this.order = order; }
+
+        public Customer getCustomer() { return customer; }
+        public void setCustomer(Customer customer) { this.customer = customer; }
+    }
+
+
+    private class Customer {
+        private String name;
+        private Integer age;
+        private Address address = new Address();
+
+        public String getName() { return name; }
+        public void setName(String name) { this.name = name; }
+
+        public Integer getAge() { return age; }
+        public void setAge(Integer age) { this.age = age; }
+
+        public Address getAddress() { return address; }
+        public void setAddress(Address address) { this.address = address; }
+    }
+
+    private class Address {
+        private String street;
+        private String pobox;
+
+        public String getStreet() { return street; }
+        public void setStreet(String street) { this.street = street; }
+
+        public String getPobox() { return pobox; }
+        public void setPobox(String pobox) { this.pobox = pobox; }
+    }
+}
\ No newline at end of file


Mime
View raw message