You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2015/06/17 23:09:25 UTC

[25/57] [partial] struts git commit: Merges xwork packages into struts

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ChainResultTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ChainResultTest.java b/core/src/test/java/com/opensymphony/xwork2/ChainResultTest.java
new file mode 100644
index 0000000..73d10a8
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ChainResultTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+/*
+ * Created on 28/02/2004
+ *
+ * To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package com.opensymphony.xwork2;
+
+import com.mockobjects.dynamic.Mock;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.util.ValueStack;
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @author CameronBraid
+ */
+public class ChainResultTest extends XWorkTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // ensure we're using the default configuration, not simple config
+        XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-sample.xml");
+        container.inject(configurationProvider);
+        loadConfigurationProviders(configurationProvider);
+    }
+
+    public void testNamespaceAndActionExpressionEvaluation() throws Exception {
+        ActionChainResult result = new ActionChainResult();
+        result.setActionName("${actionName}");
+        result.setNamespace("${namespace}");
+
+        String expectedActionName = "testActionName";
+        String expectedNamespace = "testNamespace";
+        Map<String, Object> values = new HashMap<>();
+        values.put("actionName", expectedActionName);
+        values.put("namespace", expectedNamespace);
+
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        stack.push(values);
+
+        Mock actionProxyMock = new Mock(ActionProxy.class);
+        actionProxyMock.expect("execute");
+
+        ActionProxyFactory testActionProxyFactory = new NamespaceActionNameTestActionProxyFactory(expectedNamespace, expectedActionName, (ActionProxy) actionProxyMock.proxy());
+        result.setActionProxyFactory(testActionProxyFactory);
+        try {
+
+            ActionContext testContext = new ActionContext(stack.getContext());
+            ActionContext.setContext(testContext);
+            result.execute(null);
+            actionProxyMock.verify();
+        } finally {
+            ActionContext.setContext(null);
+        }
+    }
+
+    public void testRecursiveChain() throws Exception {
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", "InfiniteRecursionChain", null);
+
+        try {
+            proxy.execute();
+            fail("did not detected repeated chain to an action");
+        } catch (XWorkException e) {
+        }
+    }
+
+    private class NamespaceActionNameTestActionProxyFactory implements ActionProxyFactory {
+        private ActionProxy returnVal;
+        private String expectedActionName;
+        private String expectedNamespace;
+
+        public NamespaceActionNameTestActionProxyFactory(String expectedNamespace, String expectedActionName, ActionProxy returnVal) {
+            this.expectedNamespace = expectedNamespace;
+            this.expectedActionName = expectedActionName;
+            this.returnVal = returnVal;
+        }
+
+        public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext) {
+            TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext) {
+            TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
+            TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
+             TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(ActionInvocation actionInvocation, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
+             TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(String namespace, String actionName, String method, boolean executeResult, boolean cleanupContext) {
+            TestCase.assertEquals(expectedNamespace, namespace);
+            TestCase.assertEquals(expectedActionName, actionName);
+
+            return returnVal;
+        }
+
+        public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName,
+                Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/CompositeTextProviderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/CompositeTextProviderTest.java b/core/src/test/java/com/opensymphony/xwork2/CompositeTextProviderTest.java
new file mode 100644
index 0000000..5778898
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/CompositeTextProviderTest.java
@@ -0,0 +1,102 @@
+package com.opensymphony.xwork2;
+
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * <code>CompositeTextProviderTest</code>
+ *
+ * @author <a href="mailto:hermanns@aixcept.de">Rainer Hermanns</a>
+ * @version $Id$
+ */
+public class CompositeTextProviderTest extends XWorkTestCase {
+
+
+    private CompositeTextProvider textProvider = null;
+
+
+    public void testGetText() throws Exception {
+        // we should get the text from the 1st text provider
+        assertEquals(textProvider.getText("name"), "1 name");
+        assertEquals(textProvider.getText("age"), "1 age");
+        assertEquals(textProvider.getText("dog"), "This is a dog");
+        assertEquals(textProvider.getText("cat"), "This is a cat");
+        assertEquals(textProvider.getText("car"), "This is a car");
+        assertEquals(textProvider.getText("bike"), "This is a bike");
+        assertEquals(textProvider.getText("someNonExistingKey"), "someNonExistingKey");
+    }
+
+
+    public void testGetTextWithDefaultValues() throws Exception {
+        assertEquals(textProvider.getText("name", "some default name"), "1 name");
+        assertEquals(textProvider.getText("age", "some default age"), "1 age");
+        assertEquals(textProvider.getText("no_such_key", "default value"), "default value");
+        assertEquals(textProvider.getText("dog", "some default dog"), "This is a dog");
+        assertEquals(textProvider.getText("cat", "some default cat"), "This is a cat");
+        assertEquals(textProvider.getText("car", "some default car"), "This is a car");
+        assertEquals(textProvider.getText("bike", "some default bike"), "This is a bike");
+    }
+
+
+    public void testGetTextWithDefaultValuesAndArgs() throws Exception {
+        assertEquals(textProvider.getText("goodnight", "say good night", "Adam"), "1 good night Adam");
+        assertEquals(textProvider.getText("goodnight", "say good night", new String[] { "Adam" }), "1 good night Adam");
+        assertEquals(textProvider.getText("goodnight", "say good night", new ArrayList<Object>() { {add("Adam");} }), "1 good night Adam");
+        assertEquals(textProvider.getText("goodmorning", "say good morning", new String[] { "Jack", "Jim" }), "1 good morning Jack and Jim");
+        assertEquals(textProvider.getText("goodmorning", "say good morning", new ArrayList<Object>() { { add("Jack"); add("Jim"); }}), "1 good morning Jack and Jim");
+    }
+
+    public void testHasKey() throws Exception {
+        assertTrue(textProvider.hasKey("name"));
+        assertTrue(textProvider.hasKey("age"));
+        assertTrue(textProvider.hasKey("cat"));
+        assertTrue(textProvider.hasKey("dog"));
+        assertTrue(textProvider.hasKey("car"));
+        assertTrue(textProvider.hasKey("bike"));
+        assertTrue(textProvider.hasKey("goodnight"));
+        assertTrue(textProvider.hasKey("goodmorning"));
+        assertFalse(textProvider.hasKey("nosuchkey"));
+    }
+
+    public void testGetResourceBundleByName() throws Exception {
+        assertNotNull(textProvider.getTexts("com.opensymphony.xwork2.validator.CompositeTextProviderTestResourceBundle1"));
+        assertNotNull(textProvider.getTexts("com.opensymphony.xwork2.validator.CompositeTextProviderTestResourceBundle2"));
+        assertNull(textProvider.getTexts("com.opensymphony.xwork2.validator.CompositeTextProviderTestResourceBundle3"));
+    }
+
+    public void testGetResourceBundle() throws Exception {
+        assertNotNull(textProvider.getTexts());
+        // we should get the first resource bundle where 'car' and 'bike' has a i18n msg
+        assertNotNull(textProvider.getTexts().getString("car"));
+        assertNotNull(textProvider.getTexts().getString("bike"));
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        textProvider = new CompositeTextProvider(new TextProvider[] {
+                new TextProviderSupport(ResourceBundle.getBundle("com.opensymphony.xwork2.validator.CompositeTextProviderTestResourceBundle1"),
+                        new LocaleProvider() {
+                            public Locale getLocale() {
+                                return Locale.ENGLISH;
+                            }
+                        }),
+                new TextProviderSupport(ResourceBundle.getBundle("com.opensymphony.xwork2.validator.CompositeTextProviderTestResourceBundle2"),
+                        new LocaleProvider() {
+                            public Locale getLocale() {
+                                return Locale.ENGLISH;
+                            }
+                        })
+
+        });
+    }
+
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        textProvider = null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
new file mode 100644
index 0000000..23e1904
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/DefaultActionInvocationTest.java
@@ -0,0 +1,354 @@
+package com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.config.entities.InterceptorMapping;
+import com.opensymphony.xwork2.mock.MockActionProxy;
+import com.opensymphony.xwork2.mock.MockContainer;
+import com.opensymphony.xwork2.mock.MockInterceptor;
+import com.opensymphony.xwork2.ognl.OgnlUtil;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+
+/**
+ * A partial test of DefaultActionInvocation.
+ * Created to change interceptor chain logic.
+ *
+ * @author <a href="mailto:kristian at zenior.no">Kristian Rosenvold</a>
+ */
+public class DefaultActionInvocationTest extends XWorkTestCase {
+
+    /**
+     * Tests interceptor chain invoke.
+     *
+     * @throws Exception when action throws exception
+     */
+    public void testInvoke() throws Exception {
+        List<InterceptorMapping> interceptorMappings = new ArrayList<>();
+        MockInterceptor mockInterceptor1 = new MockInterceptor();
+        mockInterceptor1.setFoo("test1");
+        mockInterceptor1.setExpectedFoo("test1");
+        interceptorMappings.add(new InterceptorMapping("test1", mockInterceptor1));
+        MockInterceptor mockInterceptor2 = new MockInterceptor();
+        interceptorMappings.add(new InterceptorMapping("test2", mockInterceptor2));
+        mockInterceptor2.setFoo("test2");
+        mockInterceptor2.setExpectedFoo("test2");
+        MockInterceptor mockInterceptor3 = new MockInterceptor();
+        interceptorMappings.add(new InterceptorMapping("test3", mockInterceptor3));
+        mockInterceptor3.setFoo("test3");
+        mockInterceptor3.setExpectedFoo("test3");
+
+        DefaultActionInvocation defaultActionInvocation = new DefaultActionInvocationTester(interceptorMappings);
+        container.inject(defaultActionInvocation);
+        defaultActionInvocation.stack = container.getInstance(ValueStackFactory.class).createValueStack();
+
+        defaultActionInvocation.invoke();
+        assertTrue(mockInterceptor1.isExecuted());
+        assertTrue(mockInterceptor2.isExecuted());
+        assertTrue(mockInterceptor3.isExecuted());
+    }
+
+    public void testSerialization() throws Exception {
+        // given
+        DefaultActionInvocation actionInvocation = new DefaultActionInvocation(new HashMap<String, Object>(), false);
+        actionInvocation.setContainer(new MockContainer());
+
+        // when
+        DefaultActionInvocation serializable = (DefaultActionInvocation) actionInvocation.serialize();
+
+        // then
+        assertNull(actionInvocation.container);
+        assertNull(serializable.container);
+    }
+
+    public void testDeserialization() throws Exception {
+        // given
+        DefaultActionInvocation actionInvocation = new DefaultActionInvocation(new HashMap<String, Object>(), false);
+        MockContainer mockContainer = new MockContainer();
+        ActionContext.getContext().setContainer(mockContainer);
+
+        // when
+        DefaultActionInvocation deserializable = (DefaultActionInvocation) actionInvocation.deserialize(ActionContext.getContext());
+
+        // then
+        assertNotNull(actionInvocation.container);
+        assertNotNull(deserializable.container);
+        assertEquals(mockContainer, deserializable.container);
+    }
+
+    public void testInvokingExistingExecuteMethod() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String execute() throws Exception {
+                return SUCCESS;
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("execute");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+
+        // when
+        String result = dai.invokeAction(action, null);
+
+        // then
+        assertEquals("success", result);
+    }
+
+    public void testInvokingExistingDoInputMethod() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        SimpleAction action = new SimpleAction();
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("with");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+
+        // when
+        String result = dai.invokeAction(action, null);
+
+        // then
+        assertEquals("with", result);
+    }
+
+    public void testInvokingMissingMethod() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String execute() throws Exception {
+                return ERROR;
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("notExists");
+
+        UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
+            @Override
+            public boolean hasUnknownHandlers() {
+                return false;
+            }
+        };
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+        dai.unknownHandlerManager = uhm;
+
+        // when
+        Throwable actual = null;
+        try {
+            dai.invokeAction(action, null);
+        } catch (Exception e) {
+            actual = e;
+        }
+
+        // then
+        assertNotNull(actual);
+        assertTrue(actual instanceof NoSuchMethodException);
+    }
+
+    public void testInvokingExistingMethodThatThrowsException() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String execute() throws Exception {
+                throw new IllegalArgumentException();
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("execute");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+
+        // when
+        Throwable actual = null;
+        try {
+            dai.invokeAction(action, null);
+        } catch (Exception e) {
+            actual = e;
+        }
+
+        // then
+        assertNotNull(actual);
+        assertTrue(actual instanceof IllegalArgumentException);
+    }
+
+    public void testInvokingExistingDoMethodThatThrowsException() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
+            @Override
+            public boolean hasUnknownHandlers() {
+                return false;
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String doWith() throws Exception {
+                throw new IllegalArgumentException();
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("with");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+        dai.unknownHandlerManager = uhm;
+
+        // when
+        // when
+        Throwable actual = null;
+        try {
+            dai.invokeAction(action, null);
+        } catch (Exception e) {
+            actual = e;
+        }
+
+        // then
+        assertNotNull(actual);
+        assertTrue(actual instanceof IllegalArgumentException);
+    }
+
+    @Deprecated
+    public void testUnknownHandlerManagerThatThrowsException() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
+            @Override
+            public boolean hasUnknownHandlers() {
+                return true;
+            }
+
+            @Override
+            public Object handleUnknownMethod(Object action, String methodName) throws NoSuchMethodException {
+                throw new NoSuchMethodException();
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String doWith() throws Exception {
+                throw new IllegalArgumentException();
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("notExists");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+        dai.unknownHandlerManager = uhm;
+
+        // when
+        // when
+        Throwable actual = null;
+        try {
+            dai.invokeAction(action, null);
+        } catch (Exception e) {
+            actual = e;
+        }
+
+        // then
+        assertNotNull(actual);
+        assertTrue(actual instanceof NoSuchMethodException);
+    }
+
+    @Deprecated
+    public void testUnknownHandlerManagerThatReturnsNull() throws Exception {
+        // given
+        DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
+            public ValueStack getStack() {
+                return new StubValueStack();
+            }
+        };
+
+        UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
+            @Override
+            public boolean hasUnknownHandlers() {
+                return true;
+            }
+
+            @Override
+            public Object handleUnknownMethod(Object action, String methodName) throws NoSuchMethodException {
+                return null;
+            }
+        };
+
+        SimpleAction action = new SimpleAction() {
+            @Override
+            public String doWith() throws Exception {
+                throw new IllegalArgumentException();
+            }
+        };
+        MockActionProxy proxy = new MockActionProxy();
+        proxy.setMethod("notExists");
+
+        dai.proxy = proxy;
+        dai.ognlUtil = new OgnlUtil();
+        dai.unknownHandlerManager = uhm;
+
+        // when
+        // when
+        Throwable actual = null;
+        try {
+            dai.invokeAction(action, null);
+        } catch (Exception e) {
+            actual = e;
+        }
+
+        // then
+        assertNotNull(actual);
+        assertTrue(actual instanceof NoSuchMethodException);
+    }
+
+}
+
+class DefaultActionInvocationTester extends DefaultActionInvocation {
+    DefaultActionInvocationTester(List<InterceptorMapping> interceptorMappings) {
+        super(new HashMap<String, Object>(), false);
+        interceptors = interceptorMappings.iterator();
+        MockActionProxy actionProxy = new MockActionProxy();
+        actionProxy.setMethod("execute");
+        proxy = actionProxy;
+        action = new ActionSupport();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/DefaultClasstTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultClasstTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultClasstTest.java
new file mode 100644
index 0000000..dd2bb06
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/DefaultClasstTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-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;
+
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+
+/**
+ * <code>WildCardResultTest</code>
+ *
+ * @author <a href="mailto:hermanns@aixcept.de">Rainer Hermanns</a>
+ * @version $Id$
+ */
+public class DefaultClasstTest extends XWorkTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // ensure we're using the default configuration, not simple config
+        XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-sample.xml");
+        container.inject(configurationProvider);
+        loadConfigurationProviders(configurationProvider);
+    }
+
+    public void testWildCardEvaluation() throws Exception {
+        ActionProxy proxy = actionProxyFactory.createActionProxy("Abstract-crud", "edit", null);
+        assertEquals("com.opensymphony.xwork2.SimpleAction", proxy.getConfig().getClassName());
+        
+        proxy = actionProxyFactory.createActionProxy("/example", "edit", null);
+        assertEquals("com.opensymphony.xwork2.ModelDrivenAction", proxy.getConfig().getClassName());
+         
+
+        proxy = actionProxyFactory.createActionProxy("/example2", "override", null);
+        assertEquals("com.opensymphony.xwork2.ModelDrivenAction", proxy.getConfig().getClassName());
+        
+        proxy = actionProxyFactory.createActionProxy("/example2/subItem", "save", null);
+        assertEquals("com.opensymphony.xwork2.ModelDrivenAction", proxy.getConfig().getClassName());
+        
+        proxy = actionProxyFactory.createActionProxy("/example2", "list", null);
+        assertEquals("com.opensymphony.xwork2.ModelDrivenAction", proxy.getConfig().getClassName());
+        
+        proxy = actionProxyFactory.createActionProxy("/example3", "list", null);
+        assertEquals("com.opensymphony.xwork2.SimpleAction", proxy.getConfig().getClassName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/DefaultTextProviderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultTextProviderTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultTextProviderTest.java
new file mode 100644
index 0000000..37d6dce
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/DefaultTextProviderTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.util.LocalizedTextUtil;
+import junit.framework.TestCase;
+
+import java.util.*;
+
+/**
+ * Unit test for {@link DefaultTextProvider}.
+ *
+ * @author Claus Ibsen
+ */
+public class DefaultTextProviderTest extends TestCase {
+
+    private DefaultTextProvider tp;
+
+    public void testSimpleGetTexts() throws Exception {
+        assertEquals("Hello World", tp.getText("hello"));
+        assertEquals(null, tp.getText("not.in.bundle"));
+
+        assertEquals("Hello World", tp.getText("hello", "this is default"));
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default"));
+
+        List<Object> nullList = null;
+        assertEquals("Hello World", tp.getText("hello", nullList));
+
+        String[] nullStrings = null;
+        assertEquals("Hello World", tp.getText("hello", nullStrings));
+    }
+
+   public void testGetTextsWithArgs() throws Exception {
+        assertEquals("Hello World", tp.getText("hello", "this is default", "from me")); // no args in bundle
+        assertEquals("Hello World from me", tp.getText("hello.0", "this is default", "from me"));
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", "from me"));
+        assertEquals("this is default from me", tp.getText("not.in.bundle", "this is default {0}", "from me"));
+
+        assertEquals(null, tp.getText("not.in.bundle"));
+    }
+
+    public void testGetTextsWithListArgs() throws Exception {
+        List<Object> args = new ArrayList<>();
+        args.add("Santa");
+        args.add("loud");
+        assertEquals("Hello World", tp.getText("hello", "this is default", args)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", "this is default", args));
+
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", args));
+        assertEquals("this is default Santa", tp.getText("not.in.bundle", "this is default {0}", args));
+        assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args));
+
+        assertEquals("Hello World", tp.getText("hello", args)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", args)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", args));
+
+        assertEquals(null, tp.getText("not.in.bundle", args));
+
+        assertEquals("Hello World", tp.getText("hello", "this is default", (List) null));
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", (List) null));
+    }
+
+    public void testGetTextsWithArrayArgs() throws Exception {
+        String[] args = { "Santa", "loud" };
+        assertEquals("Hello World", tp.getText("hello", "this is default", args)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", "this is default", args));
+
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", args));
+        assertEquals("this is default Santa", tp.getText("not.in.bundle", "this is default {0}", args));
+        assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args));
+
+        assertEquals("Hello World", tp.getText("hello", args)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", args)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", args));
+
+        assertEquals(null, tp.getText("not.in.bundle", args));
+
+        assertEquals("Hello World", tp.getText("hello", "this is default", (String[]) null));
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", (String[]) null));
+    }
+
+    public void testGetTextsWithListAndStack() throws Exception {
+        List<Object> args = new ArrayList<>();
+        args.add("Santa");
+        args.add("loud");
+        assertEquals("Hello World", tp.getText("hello", "this is default", args, null)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args, null)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", "this is default", args, null));
+
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", args, null));
+        assertEquals("this is default Santa", tp.getText("not.in.bundle", "this is default {0}", args, null));
+        assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args, null));
+    }
+
+    public void testGetTextsWithArrayAndStack() throws Exception {
+        String[] args = { "Santa", "loud" };
+        assertEquals("Hello World", tp.getText("hello", "this is default", args, null)); // no args in bundle
+        assertEquals("Hello World Santa", tp.getText("hello.0", "this is default", args, null)); // only 1 arg in bundle
+        assertEquals("Hello World. This is Santa speaking loud", tp.getText("hello.1", "this is default", args, null));
+
+        assertEquals("this is default", tp.getText("not.in.bundle", "this is default", args, null));
+        assertEquals("this is default Santa", tp.getText("not.in.bundle", "this is default {0}", args, null));
+        assertEquals("this is default Santa speaking loud", tp.getText("not.in.bundle", "this is default {0} speaking {1}", args, null));
+    }
+
+    public void testGetBundle() throws Exception {
+        assertNull(tp.getTexts()); // always returns null
+
+        ResourceBundle rb = ResourceBundle.getBundle(TextProviderSupportTest.class.getName(), Locale.CANADA);
+        assertEquals(rb, tp.getTexts(TextProviderSupportTest.class.getName()));
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        ActionContext ctx = new ActionContext(new HashMap<String, Object>());
+        ActionContext.setContext(ctx);
+        ctx.setLocale(Locale.CANADA);
+
+        LocalizedTextUtil.clearDefaultResourceBundles();
+        LocalizedTextUtil.addDefaultResourceBundle(DefaultTextProviderTest.class.getName());
+
+        tp = new DefaultTextProvider();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        ActionContext.setContext(null);
+        tp = null;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ExternalReferenceAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ExternalReferenceAction.java b/core/src/test/java/com/opensymphony/xwork2/ExternalReferenceAction.java
new file mode 100644
index 0000000..ecf2ceb
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ExternalReferenceAction.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+/*
+ * Created on Nov 11, 2003
+ *
+ * To change the template for this generated file go to Window - Preferences -
+ * Java - Code Generation - Code and Comments
+ */
+package com.opensymphony.xwork2;
+
+
+/**
+ * @author Mike
+ *         <p/>
+ *         To change the template for this generated type comment go to Window -
+ *         Preferences - Java - Code Generation - Code and Comments
+ */
+public class ExternalReferenceAction implements Action {
+
+    private Foo foo;
+
+
+    /**
+     * @param foo The foo to set.
+     */
+    public void setFoo(Foo foo) {
+        this.foo = foo;
+    }
+
+    /**
+     * @return Returns the foo.
+     */
+    public Foo getFoo() {
+        return foo;
+    }
+
+    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/Foo.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/Foo.java b/core/src/test/java/com/opensymphony/xwork2/Foo.java
new file mode 100644
index 0000000..25d5bb0
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/Foo.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+/*
+ * Created on Nov 11, 2003
+ *
+ * To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package com.opensymphony.xwork2;
+
+
+/**
+ * @author Mike
+ *         <p/>
+ *         To change the template for this generated type comment go to
+ *         Window - Preferences - Java - Code Generation - Code and Comments
+ */
+public class Foo {
+
+    String name = null;
+
+
+    public Foo() {
+        name = "not set";
+    }
+
+    public Foo(String name) {
+        this.name = name;
+    }
+
+
+    public String getName() {
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/GenericsBean.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/GenericsBean.java b/core/src/test/java/com/opensymphony/xwork2/GenericsBean.java
new file mode 100644
index 0000000..b1d432b
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/GenericsBean.java
@@ -0,0 +1,57 @@
+package com.opensymphony.xwork2;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <code>GenericsBean</code>
+ *
+ * @author <a href="mailto:hermanns@aixcept.de">Rainer Hermanns</a>
+ * @version $Id$
+ */
+public class GenericsBean {
+    private List<Double> blubb;
+    private List<Double> getterList;
+    private Map<Double, Integer> genericMap = new HashMap<>();
+    private Map<Double, List<Integer>> extendedMap = new HashMap<>();
+
+    /**
+     * @return Returns the doubles.
+     */
+    public List<Double> getDoubles() {
+        return blubb;
+    }
+
+    /**
+     * @param doubles The doubles to set.
+     */
+    public void setDoubles(List<Double> doubles) {
+        this.blubb = doubles;
+    }
+
+    public Map<Double, Integer> getGenericMap() {
+        return genericMap;
+    }
+
+    public void setGenericMap(Map<Double, Integer> genericMap) {
+        this.genericMap = genericMap;
+    }
+
+    public List<Double> getGetterList() {
+        if ( getterList == null ) {
+            getterList = new ArrayList<>(1);
+            getterList.add(42.42);
+        }
+        return getterList;
+    }
+
+    public Map<Double, List<Integer>> getExtendedMap() {
+        return extendedMap;
+    }
+
+    public void setExtendedMap(Map<Double, List<Integer>> extendedMap) {
+        this.extendedMap = extendedMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/LocaleAwareTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/LocaleAwareTest.java b/core/src/test/java/com/opensymphony/xwork2/LocaleAwareTest.java
new file mode 100644
index 0000000..15b1050
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/LocaleAwareTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.config.providers.MockConfigurationProvider;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+
+import java.util.Locale;
+
+
+/**
+ * LocaleAwareTest
+ *
+ * @author Jason Carreira
+ *         Created Feb 10, 2003 6:13:13 PM
+ */
+public class LocaleAwareTest extends XWorkTestCase {
+
+    public void testGetText() {
+        try {
+            ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.FOO_ACTION_NAME, null);
+            ActionContext.getContext().setLocale(Locale.US);
+
+            TextProvider localeAware = (TextProvider) proxy.getAction();
+            assertEquals("Foo Range Message", localeAware.getText("foo.range"));
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    public void testLocaleGetText() {
+        try {
+            ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.FOO_ACTION_NAME, null);
+            ActionContext.getContext().setLocale(Locale.GERMANY);
+
+            TextProvider localeAware = (TextProvider) proxy.getAction();
+            assertEquals("I don't know German", localeAware.getText("foo.range"));
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-test-beans.xml");
+        container.inject(configurationProvider);
+        loadConfigurationProviders(configurationProvider, new MockConfigurationProvider());
+
+        ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
+        stack.getContext().put(ActionContext.CONTAINER, container);
+        ActionContext.setContext(new ActionContext(stack.getContext()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
new file mode 100644
index 0000000..525c34b
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAction.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+
+/**
+ * ModelDrivenAction
+ *
+ * @author Jason Carreira
+ *         Created Apr 8, 2003 6:27:29 PM
+ */
+public class ModelDrivenAction extends ActionSupport implements ModelDriven {
+
+    private String foo;
+    private TestBean model = new TestBean();
+
+
+    public void setFoo(String foo) {
+        this.foo = foo;
+    }
+
+    public String getFoo() {
+        return foo;
+    }
+
+    /**
+     * @return the model to be pushed onto the ValueStack after the Action itself
+     */
+    public Object getModel() {
+        return model;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
new file mode 100644
index 0000000..279208c
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ModelDrivenAnnotationAction.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * ModelDrivenAnnotationAction
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ *         Created Apr 8, 2003 6:27:29 PM
+ */
+public class ModelDrivenAnnotationAction extends ActionSupport implements ModelDriven {
+
+    private String foo;
+    private AnnotatedTestBean model = new AnnotatedTestBean();
+
+
+    public void setFoo(String foo) {
+        this.foo = foo;
+    }
+
+    public String getFoo() {
+        return foo;
+    }
+
+    /**
+     * @return the model to be pushed onto the ValueStack after the Action itself
+     */
+    public Object getModel() {
+        return model;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/NestedAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/NestedAction.java b/core/src/test/java/com/opensymphony/xwork2/NestedAction.java
new file mode 100644
index 0000000..5d743f2
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/NestedAction.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.util.ValueStack;
+import junit.framework.Assert;
+
+
+/**
+ * NestedAction
+ *
+ * @author Jason Carreira
+ *         Created Mar 5, 2003 3:08:19 PM
+ */
+public class NestedAction implements Action {
+
+    private String nestedProperty = ActionNestingTest.NESTED_VALUE;
+
+
+    public NestedAction() {
+    }
+
+
+    public String getNestedProperty() {
+        return nestedProperty;
+    }
+
+    public String execute() throws Exception {
+        Assert.fail();
+
+        return null;
+    }
+
+    public String noStack() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        // Action + DefaultTextProvider on the stack
+        Assert.assertEquals(2, stack.size());
+        Assert.assertNull(stack.findValue(ActionNestingTest.KEY));
+        Assert.assertEquals(ActionNestingTest.NESTED_VALUE, stack.findValue(ActionNestingTest.NESTED_KEY));
+
+        return SUCCESS;
+    }
+
+    public String stack() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        //DefaultTextProvider, NestedActionTest pushed on by the test, and the NestedAction
+        Assert.assertEquals(3, stack.size());
+        Assert.assertNotNull(stack.findValue(ActionNestingTest.KEY));
+        Assert.assertEquals(ActionContext.getContext().getValueStack().findValue(ActionNestingTest.KEY), ActionNestingTest.VALUE);
+        Assert.assertEquals(ActionNestingTest.NESTED_VALUE, stack.findValue(ActionNestingTest.NESTED_KEY));
+
+        return SUCCESS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationAction.java b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationAction.java
new file mode 100644
index 0000000..60f8ae8
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationAction.java
@@ -0,0 +1,10 @@
+package com.opensymphony.xwork2;
+
+/**
+ * Need by the ProxyInvocationTest
+ */
+public class ProxyInvocationAction extends ActionSupport implements ProxyInvocationInterface {
+    public String show() {
+        return "proxyResult";
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationInterface.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationInterface.java b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationInterface.java
new file mode 100644
index 0000000..e548a78
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationInterface.java
@@ -0,0 +1,8 @@
+package com.opensymphony.xwork2;
+
+/**
+ * Need by the ProxyInvocationTest
+ */
+public interface ProxyInvocationInterface {
+    public String show();
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationTest.java b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationTest.java
new file mode 100644
index 0000000..0e7e208
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ProxyInvocationTest.java
@@ -0,0 +1,51 @@
+package com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Contribed by: Ruben Inoto
+ */
+public class ProxyInvocationTest extends XWorkTestCase {
+
+    /**
+     * Sets a ProxyObjectFactory as ObjectFactory (so the FooAction will always be retrieved
+     * as a FooProxy), and it tries to call invokeAction on the TestActionInvocation.
+     * 
+     * It should fail, because the Method got from the action (actually a FooProxy) 
+     * will be executed on the InvocationHandler of the action (so, in the action itself). 
+     */
+    public void testProxyInvocation() throws Exception {
+
+        ActionProxy proxy = actionProxyFactory
+            .createActionProxy("", "ProxyInvocation", createDummyContext());
+        ActionInvocation invocation = proxy.getInvocation();
+        
+        String result = invocation.invokeActionOnly();
+        assertEquals("proxyResult", result);
+
+    }
+
+    /** 
+     * Needed for the creation of the action proxy
+     */
+    private Map<String, Object> createDummyContext() {
+        Map<String, Object> params = new HashMap<>();
+        params.put("blah", "this is blah");
+        Map<String, Object> extraContext = new HashMap<>();
+        extraContext.put(ActionContext.PARAMETERS, params);
+        return extraContext;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // ensure we're using the default configuration, not simple config
+        XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-proxyinvoke.xml");
+        container.inject(configurationProvider);
+        loadConfigurationProviders(configurationProvider);
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ProxyObjectFactory.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/ProxyObjectFactory.java b/core/src/test/java/com/opensymphony/xwork2/ProxyObjectFactory.java
new file mode 100644
index 0000000..37821c8
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/ProxyObjectFactory.java
@@ -0,0 +1,46 @@
+package com.opensymphony.xwork2;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+
+/**
+ * ObjectFactory that returns a FooProxy in the buildBean if the clazz is FooAction 
+ */
+public class ProxyObjectFactory extends ObjectFactory {
+
+    /**
+     * It returns an instance of the bean except if the class is FooAction. 
+     * In this case, it returns a FooProxy of it.
+     */
+    @Override
+    public Object buildBean(Class clazz, Map<String, Object> extraContext)
+        throws Exception {
+        Object bean = super.buildBean(clazz, extraContext);
+        if(clazz.equals(ProxyInvocationAction.class)) {
+            return Proxy.newProxyInstance(bean.getClass()
+                .getClassLoader(), bean.getClass().getInterfaces(),
+                new ProxyInvocationProxy(bean));
+
+        }
+        return bean;
+    }
+    
+    /**
+     * Simple proxy that just invokes the method on the target on the invoke method
+     */
+    public class ProxyInvocationProxy implements InvocationHandler {
+
+        private Object target;
+
+        public ProxyInvocationProxy(Object target) {
+            this.target = target;
+        }
+
+        public Object invoke(Object proxy, Method m, Object[] args)
+            throws Throwable {
+            return m.invoke(target, args);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/SimpleAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/SimpleAction.java b/core/src/test/java/com/opensymphony/xwork2/SimpleAction.java
new file mode 100644
index 0000000..d563ebf
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/SimpleAction.java
@@ -0,0 +1,272 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.inject.Inject;
+
+import java.util.*;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class SimpleAction extends ActionSupport {
+
+    public static final String COMMAND_RETURN_CODE = "com.opensymphony.xwork2.SimpleAction.CommandInvoked";
+
+
+    private ArrayList<String> someList = new ArrayList<>();
+    private Date date = new Date();
+    private Properties settings = new Properties();
+    private String blah;
+    private String name;
+    private TestBean bean = new TestBean();
+    private boolean throwException;
+    private int bar;
+    private int baz;
+    private int foo;
+    private long longFoo;
+    private short shortFoo;
+    private double percentage;
+    private Map<Integer, String> indexedProps = new HashMap<>();
+
+    private String aliasSource;
+    private String aliasDest;
+    private Map<String, String> protectedMap = new HashMap<>();
+    private Map<String, String> existingMap = new HashMap<>();
+    
+    public static boolean resultCalled;
+
+
+    public SimpleAction() {
+        resultCalled = false;
+        existingMap.put("existingKey", "value");
+    }
+    
+    public Map<String,String> getTheProtectedMap() {
+        return protectedMap;
+    }
+    
+    protected Map<String,String> getTheSemiProtectedMap() {
+        return protectedMap;
+    }
+
+    public void setExistingMap(Map<String,String> map) {
+        this.existingMap = map;
+    }
+
+    public Map<String,String> getTheExistingMap() {
+        return existingMap;
+    }
+
+
+    public void setBar(int bar) {
+        this.bar = bar;
+    }
+
+    public int getBar() {
+        return bar;
+    }
+
+    public double getPercentage() {
+        return percentage;
+    }
+
+    public void setPercentage(double percentage) {
+        this.percentage = percentage;
+    }
+
+    public void setBaz(int baz) {
+        this.baz = baz;
+    }
+
+    public int getBaz() {
+        return baz;
+    }
+
+    public void setBean(TestBean bean) {
+        this.bean = bean;
+    }
+
+    public TestBean getBean() {
+        return bean;
+    }
+
+    public void setBlah(String blah) {
+        this.blah = blah;
+    }
+
+    public String getBlah() {
+        return blah;
+    }
+
+    public Boolean getBool(String b) {
+        return new Boolean(b);
+    }
+
+    public boolean[] getBools() {
+        return new boolean[]{true, false, false, true};
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setFoo(int foo) {
+        this.foo = foo;
+    }
+
+    public int getFoo() {
+        return foo;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setSettings(Properties settings) {
+        this.settings = settings;
+    }
+
+    public Properties getSettings() {
+        return settings;
+    }
+
+
+    public String getAliasDest() {
+        return aliasDest;
+    }
+
+    public void setAliasDest(String aliasDest) {
+        this.aliasDest = aliasDest;
+    }
+
+    public String getAliasSource() {
+        return aliasSource;
+    }
+
+    public void setAliasSource(String aliasSource) {
+        this.aliasSource = aliasSource;
+    }
+
+
+    public void setSomeList(ArrayList<String> someList) {
+        this.someList = someList;
+    }
+
+    public ArrayList<String> getSomeList() {
+        return someList;
+    }
+    
+    public String getIndexedProp(int index) {
+    	return indexedProps.get(index);
+    }
+    
+    public void setIndexedProp(int index, String val) {
+    	indexedProps.put(index, val);
+    }
+    
+
+    public void setThrowException(boolean   throwException) {
+        this.throwException = throwException;
+    }
+
+    public String commandMethod() throws Exception {
+        return COMMAND_RETURN_CODE;
+    }
+    
+    public Result resultAction() throws Exception {
+    	return new Result() {
+            public Configuration configuration;
+
+            @Inject
+            public void setConfiguration(Configuration config) {
+                this.configuration = config;
+            }
+            public void execute(ActionInvocation invocation) throws Exception {
+                if (configuration != null)
+                    resultCalled = true;
+            }
+    	    
+    	};
+    }
+
+    public String exceptionMethod() throws Exception {
+        if (throwException) {
+            throw new Exception("We're supposed to throw this");
+        }
+
+        return "OK";
+    }
+
+    @Override
+    public String execute() throws Exception {
+        if (foo == bar) {
+            return ERROR;
+        }
+
+        baz = foo + bar;
+
+        name = "HelloWorld";
+        settings.put("foo", "bar");
+        settings.put("black", "white");
+
+        someList.add("jack");
+        someList.add("bill");
+        someList.add("kerry");
+
+        return SUCCESS;
+    }
+    
+    public String doInput() throws Exception {
+        return INPUT;
+    }
+
+    public String doWith() throws Exception {
+        return "with";
+    }
+
+    public long getLongFoo() {
+        return longFoo;
+    }
+
+
+    public void setLongFoo(long longFoo) {
+        this.longFoo = longFoo;
+    }
+
+
+    public short getShortFoo() {
+        return shortFoo;
+    }
+
+
+    public void setShortFoo(short shortFoo) {
+        this.shortFoo = shortFoo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/SimpleAnnotationAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/SimpleAnnotationAction.java b/core/src/test/java/com/opensymphony/xwork2/SimpleAnnotationAction.java
new file mode 100644
index 0000000..35f0f55
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/SimpleAnnotationAction.java
@@ -0,0 +1,231 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.validator.annotations.*;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Properties;
+
+
+/**
+ * Simple Test Action for annotaton processing.
+ *
+ * @author Rainer Hermanns
+ * @version $Revision$
+ */
+@Validation()
+public class SimpleAnnotationAction extends ActionSupport {
+    //~ Static fields/initializers /////////////////////////////////////////////
+
+    public static final String COMMAND_RETURN_CODE = "com.opensymphony.xwork2.SimpleAnnotationAction.CommandInvoked";
+
+    //~ Instance fields ////////////////////////////////////////////////////////
+
+    private ArrayList<String> someList = new ArrayList<>();
+    private Date date = new Date();
+    private Properties settings = new Properties();
+    private String blah;
+    private String name;
+    private AnnotatedTestBean bean = new AnnotatedTestBean();
+    private boolean throwException;
+    private int bar;
+    private int baz;
+    private int foo;
+    private double percentage;
+
+    private String aliasSource;
+    private String aliasDest;
+    
+    
+
+    //~ Constructors ///////////////////////////////////////////////////////////
+
+    public SimpleAnnotationAction() {
+    }
+
+    //~ Methods ////////////////////////////////////////////////////////////////
+
+    @RequiredFieldValidator(type = ValidatorType.FIELD, message = "You must enter a value for bar.")
+    @IntRangeFieldValidator(type = ValidatorType.FIELD, min = "6", max = "10", message = "bar must be between ${min} and ${max}, current value is ${bar}.")
+    public void setBar(int bar) {
+        this.bar = bar;
+    }
+
+    public int getBar() {
+        return bar;
+    }
+
+    @IntRangeFieldValidator(min = "0", key = "baz.range", message = "Could not find baz.range!")
+    public void setBaz(int baz) {
+        this.baz = baz;
+    }
+
+    public int getBaz() {
+        return baz;
+    }
+
+    public double getPercentage() {
+        return percentage;
+    }
+
+    @DoubleRangeFieldValidator(minInclusive = "0.123", key = "baz.range", message = "Could not find percentage.range!")
+    public void setPercentage(double percentage) {
+        this.percentage = percentage;
+    }
+
+    public void setBean(AnnotatedTestBean bean) {
+        this.bean = bean;
+    }
+
+    public AnnotatedTestBean getBean() {
+        return bean;
+    }
+
+    public void setBlah(String blah) {
+        this.blah = blah;
+    }
+
+    public String getBlah() {
+        return blah;
+    }
+
+    public Boolean getBool(String b) {
+        return new Boolean(b);
+    }
+
+    public boolean[] getBools() {
+        return new boolean[] {true, false, false, true};
+    }
+
+    @DateRangeFieldValidator(min = "12/22/2002", max = "12/25/2002", message = "The date must be between 12-22-2002 and 12-25-2002.")
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setFoo(int foo) {
+        this.foo = foo;
+    }
+
+    public int getFoo() {
+        return foo;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setSettings(Properties settings) {
+        this.settings = settings;
+    }
+
+    public Properties getSettings() {
+        return settings;
+    }
+
+
+    public String getAliasDest() {
+        return aliasDest;
+    }
+
+    public void setAliasDest(String aliasDest) {
+        this.aliasDest = aliasDest;
+    }
+
+    public String getAliasSource() {
+        return aliasSource;
+    }
+
+    public void setAliasSource(String aliasSource) {
+        this.aliasSource = aliasSource;
+    }
+
+    
+    public void setSomeList(ArrayList<String> someList) {
+        this.someList = someList;
+    }
+
+    public ArrayList<String> getSomeList() {
+        return someList;
+    }
+
+    public void setThrowException(boolean throwException) {
+        this.throwException = throwException;
+    }
+
+    public String commandMethod() throws Exception {
+        return COMMAND_RETURN_CODE;
+    }
+
+    public String exceptionMethod() throws Exception {
+        if (throwException) {
+            throw new Exception("We're supposed to throw this");
+        }
+
+        return "OK";
+    }
+
+    @Override
+    @Validations(
+            requiredFields =
+                    {@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "customfield", message = "You must enter a value for field.")},
+            requiredStrings =
+                    {@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = "stringisrequired", message = "You must enter a value for string.")},
+            emails =
+                    { @EmailValidator(type = ValidatorType.SIMPLE, fieldName = "emailaddress", message = "You must enter a value for email.")},
+            urls =
+                    { @UrlValidator(type = ValidatorType.SIMPLE, fieldName = "hreflocation", message = "You must enter a value for email.")},
+            stringLengthFields =
+                    {@StringLengthFieldValidator(type = ValidatorType.SIMPLE, trim = true, minLength="10" , maxLength = "12", fieldName = "needstringlength", message = "You must enter a stringlength.")},
+            intRangeFields =
+                    { @IntRangeFieldValidator(type = ValidatorType.SIMPLE, fieldName = "intfield", min = "6", max = "10", message = "bar must be between ${min} and ${max}, current value is ${bar}.")},
+            dateRangeFields =
+                    {@DateRangeFieldValidator(type = ValidatorType.SIMPLE, fieldName = "datefield", min = "-1", max = "99", message = "bar must be between ${min} and ${max}, current value is ${bar}.")},
+            expressions = {
+                @ExpressionValidator(expression = "foo &gt; 1", message = "Foo must be greater than Bar 1. Foo = ${foo}, Bar = ${bar}."),
+                @ExpressionValidator(expression = "foo &gt; 2", message = "Foo must be greater than Bar 2. Foo = ${foo}, Bar = ${bar}."),
+                @ExpressionValidator(expression = "foo &gt; 3", message = "Foo must be greater than Bar 3. Foo = ${foo}, Bar = ${bar}."),
+                @ExpressionValidator(expression = "foo &gt; 4", message = "Foo must be greater than Bar 4. Foo = ${foo}, Bar = ${bar}."),
+                @ExpressionValidator(expression = "foo &gt; 5", message = "Foo must be greater than Bar 5. Foo = ${foo}, Bar = ${bar}.")
+    }
+    )
+    public String execute() throws Exception {
+        if (foo == bar) {
+            return ERROR;
+        }
+
+        baz = foo + bar;
+
+        name = "HelloWorld";
+        settings.put("foo", "bar");
+        settings.put("black", "white");
+
+        someList.add("jack");
+        someList.add("bill");
+        someList.add("kerry");
+
+        return SUCCESS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/SimpleFooAction.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/SimpleFooAction.java b/core/src/test/java/com/opensymphony/xwork2/SimpleFooAction.java
new file mode 100644
index 0000000..7198359
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/SimpleFooAction.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class SimpleFooAction implements Action {
+
+    private Integer id;
+
+    public String execute() throws Exception {
+        return SUCCESS;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java b/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java
new file mode 100644
index 0000000..1856c7c
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/StubValueStack.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;
+
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.xwork2.util.ValueStack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Stub value stack for testing
+ */
+public class StubValueStack implements ValueStack {
+    Map<String, Object> ctx = new HashMap<>();
+    CompoundRoot root = new CompoundRoot();
+    
+    public Map<String, Object> getContext() {
+        return ctx;
+    }
+
+    public void setDefaultType(Class defaultType) {
+    }
+
+    public void setExprOverrides(Map<Object, Object> overrides) {
+    }
+
+    public Map<Object, Object> getExprOverrides() {
+        return null;
+    }
+
+    public CompoundRoot getRoot() {
+        return root;
+    }
+
+    public void setValue(String expr, Object value) {
+        ctx.put(expr, value);
+    }
+
+    public void setParameter(String expr, Object value) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public void setValue(String expr, Object value, boolean throwExceptionOnFailure) {
+        ctx.put(expr, value);
+    }
+
+    public String findString(String expr) {
+        return (String) ctx.get(expr);
+    }
+
+    public String findString(String expr, boolean throwExceptionOnFailure) {
+        return findString(expr, false);
+    }
+
+    public Object findValue(String expr) {
+        return findValue(expr, false);
+    }
+
+    public Object findValue(String expr, boolean throwExceptionOnFailure) {
+        return ctx.get(expr);
+    }
+
+    public Object findValue(String expr, Class asType) {
+        return findValue(expr, asType, false);
+    }
+
+    public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) {
+        return ctx.get(expr);
+    }
+
+    public Object peek() {
+        return root.peek();
+    }
+
+    public Object pop() {
+        return root.pop();
+    }
+
+    public void push(Object o) {
+        root.push(o);
+    }
+
+    public void set(String key, Object o) {
+        ctx.put(key, o);
+    }
+
+    public int size() {
+        return root.size();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/TestBean.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/TestBean.java b/core/src/test/java/com/opensymphony/xwork2/TestBean.java
new file mode 100644
index 0000000..3be8e18
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/TestBean.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import java.util.Date;
+
+
+/**
+ * TestBean
+ *
+ * @author Jason Carreira
+ *         Created Aug 4, 2003 12:39:53 AM
+ */
+public class TestBean {
+
+    private Date birth;
+    private String name;
+    private int count;
+    
+    private TestChildBean child = new TestChildBean();
+
+    public TestBean() {
+    }
+
+
+    public void setBirth(Date birth) {
+        this.birth = birth;
+    }
+
+    public Date getBirth() {
+        return birth;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+
+    public TestChildBean getChild() {
+        return child;
+    }
+
+
+    public void setChild(TestChildBean child) {
+        this.child = child;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/TestChildBean.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/TestChildBean.java b/core/src/test/java/com/opensymphony/xwork2/TestChildBean.java
new file mode 100644
index 0000000..4a01668
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/TestChildBean.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+
+/**
+ * TestBean
+ */
+public class TestChildBean {
+
+    private Date birth;
+    private String name;
+    private int count;
+
+
+    public TestChildBean() {
+        Calendar cal = new GregorianCalendar(1900, 01, 01);
+        setBirth(cal.getTime());
+    }
+
+
+    public void setBirth(Date birth) {
+        this.birth = birth;
+    }
+
+    public Date getBirth() {
+        return birth;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/TestInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/TestInterceptor.java b/core/src/test/java/com/opensymphony/xwork2/TestInterceptor.java
new file mode 100644
index 0000000..fb71a06
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/TestInterceptor.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;
+
+import com.opensymphony.xwork2.interceptor.Interceptor;
+import junit.framework.Assert;
+
+
+/**
+ * TestInterceptor
+ *
+ * @author Jason Carreira
+ *         Created Apr 21, 2003 9:04:06 PM
+ */
+public class TestInterceptor implements Interceptor {
+
+    public static final String DEFAULT_FOO_VALUE = "fooDefault";
+
+
+    private String expectedFoo = DEFAULT_FOO_VALUE;
+    private String foo = DEFAULT_FOO_VALUE;
+    private boolean executed = false;
+
+
+    public boolean isExecuted() {
+        return executed;
+    }
+
+    public void setExpectedFoo(String expectedFoo) {
+        this.expectedFoo = expectedFoo;
+    }
+
+    public String getExpectedFoo() {
+        return expectedFoo;
+    }
+
+    public void setFoo(String foo) {
+        this.foo = foo;
+    }
+
+    public String getFoo() {
+        return foo;
+    }
+
+    /**
+     * Called to let an interceptor clean up any resources it has allocated.
+     */
+    public void destroy() {
+    }
+
+    /**
+     * Called after an Interceptor is created, but before any requests are processed using the intercept() methodName. This
+     * gives the Interceptor a chance to initialize any needed resources.
+     */
+    public void init() {
+    }
+
+    /**
+     * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
+     * request by the DefaultActionInvocation or to short-circuit the processing and just return a String return code.
+     *
+     * @param invocation
+     * @return
+     * @throws Exception
+     */
+    public String intercept(ActionInvocation invocation) throws Exception {
+        executed = true;
+        Assert.assertNotSame(DEFAULT_FOO_VALUE, foo);
+        Assert.assertEquals(expectedFoo, foo);
+
+        return invocation.invoke();
+    }
+}

http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/TestNGXWorkTestCaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/com/opensymphony/xwork2/TestNGXWorkTestCaseTest.java b/core/src/test/java/com/opensymphony/xwork2/TestNGXWorkTestCaseTest.java
new file mode 100644
index 0000000..d13ac13
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/TestNGXWorkTestCaseTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import junit.framework.TestCase;
+import org.testng.TestListenerAdapter;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+
+public class TestNGXWorkTestCaseTest extends TestCase {
+
+    public void testSimpleTest() throws Exception {
+        TestListenerAdapter tla = new TestListenerAdapter();
+        TestNG testng = new TestNG();
+        testng.setTestClasses(new Class[] { RunTest.class });
+        testng.setOutputDirectory("target/surefire-reports");
+        testng.addListener(tla);
+        try {
+            testng.run();
+            assertEquals(1, tla.getPassedTests().size());
+            assertEquals(0, tla.getFailedTests().size());
+            assertTrue(RunTest.ran);
+            assertNotNull(RunTest.mgr);
+        } finally {
+            RunTest.mgr = null;
+        }
+    }
+    
+    @Test
+    public static class RunTest extends TestNGXWorkTestCase {
+        public static boolean ran = false;
+        public static ConfigurationManager mgr;
+        
+        public void testRun() {
+            ran = true;
+            mgr = this.configurationManager;
+        }
+    }
+}