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 2011/12/02 17:33:45 UTC

svn commit: r1209569 [43/50] - in /struts/struts2/branches/STRUTS_3_X: apps/blank/src/main/java/example/ apps/blank/src/test/java/example/ apps/jboss-blank/src/main/java/example/ apps/jboss-blank/src/test/java/example/ apps/mailreader/src/main/java/mai...

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationParameterFilterUnitTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationParameterFilterUnitTest.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationParameterFilterUnitTest.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationParameterFilterUnitTest.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,173 @@
+package org.apache.struts2.xwork2.interceptor.annotations;
+
+import com.mockobjects.dynamic.Mock;
+import org.apache.struts2.xwork2.Action;
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.StubValueStack;
+import org.apache.struts2.xwork2.util.ValueStack;
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author martin.gilday
+ * @author jafl
+ *
+ */
+public class AnnotationParameterFilterUnitTest extends TestCase {
+
+	ValueStack stack;
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		stack = new StubValueStack();
+	}
+
+	/**
+	 * Only "name" should remain in the parameter map.  All others
+	 * should be removed
+	 * @throws Exception
+	 */
+	public void testBlockingByDefault() throws Exception {
+		
+		Map contextMap = new HashMap();
+		Map parameterMap = new HashMap();
+		
+		parameterMap.put("job", "Baker");
+		parameterMap.put("name", "Martin");
+		
+		contextMap.put(ActionContext.PARAMETERS, parameterMap);
+		
+		Action action = new BlockingByDefaultAction();
+		stack.push(action);
+		
+		Mock mockInvocation = new Mock(ActionInvocation.class);
+		mockInvocation.expectAndReturn("getInvocationContext", new ActionContext(contextMap));
+		mockInvocation.matchAndReturn("getAction", action);
+		mockInvocation.matchAndReturn("getStack", stack);
+		mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
+		
+		ActionInvocation invocation = (ActionInvocation) mockInvocation.proxy();
+		
+		AnnotationParameterFilterIntereptor intereptor = new AnnotationParameterFilterIntereptor();
+		intereptor.intercept(invocation);
+		
+		assertEquals("Paramter map should contain one entry", 1, parameterMap.size());
+		assertNull(parameterMap.get("job"));
+		assertNotNull(parameterMap.get("name"));
+		
+	}
+
+	/**
+	 * "name" should be removed from the map, as it is blocked.
+	 * All other parameters should remain
+	 * @throws Exception
+	 */
+	public void testAllowingByDefault() throws Exception {
+		
+		Map contextMap = new HashMap();
+		Map parameterMap = new HashMap();
+		
+		parameterMap.put("job", "Baker");
+		parameterMap.put("name", "Martin");
+		
+		contextMap.put(ActionContext.PARAMETERS, parameterMap);
+		
+		Action action = new AllowingByDefaultAction();
+		stack.push(action);
+		
+		Mock mockInvocation = new Mock(ActionInvocation.class);
+		mockInvocation.expectAndReturn("getInvocationContext", new ActionContext(contextMap));
+		mockInvocation.matchAndReturn("getAction", action);
+		mockInvocation.matchAndReturn("getStack", stack);
+		mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
+		
+		ActionInvocation invocation = (ActionInvocation) mockInvocation.proxy();
+		
+		AnnotationParameterFilterIntereptor intereptor = new AnnotationParameterFilterIntereptor();
+		intereptor.intercept(invocation);
+		
+		assertEquals("Paramter map should contain one entry", 1, parameterMap.size());
+		assertNotNull(parameterMap.get("job"));
+		assertNull(parameterMap.get("name"));
+		
+	}
+
+	/**
+	 * Only "name" should remain in the parameter map.  All others
+	 * should be removed
+	 * @throws Exception
+	 */
+	public void testBlockingByDefaultWithModel() throws Exception {
+		
+		Map contextMap = new HashMap();
+		Map parameterMap = new HashMap();
+		
+		parameterMap.put("job", "Baker");
+		parameterMap.put("name", "Martin");
+		parameterMap.put("m1", "s1");
+		parameterMap.put("m2", "s2");
+		
+		contextMap.put(ActionContext.PARAMETERS, parameterMap);
+		stack.push(new BlockingByDefaultModel());
+		
+		Mock mockInvocation = new Mock(ActionInvocation.class);
+		mockInvocation.expectAndReturn("getInvocationContext", new ActionContext(contextMap));
+		mockInvocation.matchAndReturn("getAction", new BlockingByDefaultAction());
+		mockInvocation.matchAndReturn("getStack", stack);
+		mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
+		
+		ActionInvocation invocation = (ActionInvocation) mockInvocation.proxy();
+		
+		AnnotationParameterFilterIntereptor intereptor = new AnnotationParameterFilterIntereptor();
+		intereptor.intercept(invocation);
+		
+		assertEquals("Paramter map should contain two entries", 2, parameterMap.size());
+		assertNull(parameterMap.get("job"));
+		assertNotNull(parameterMap.get("name"));
+		assertNotNull(parameterMap.get("m1"));
+		assertNull(parameterMap.get("m2"));
+		
+	}
+
+	/**
+	 * "name" should be removed from the map, as it is blocked.
+	 * All other parameters should remain
+	 * @throws Exception
+	 */
+	public void testAllowingByDefaultWithModel() throws Exception {
+		
+		Map contextMap = new HashMap();
+		Map parameterMap = new HashMap();
+		
+		parameterMap.put("job", "Baker");
+		parameterMap.put("name", "Martin");
+		parameterMap.put("m1", "s1");
+		parameterMap.put("m2", "s2");
+		
+		contextMap.put(ActionContext.PARAMETERS, parameterMap);
+		stack.push(new AllowingByDefaultModel());
+		
+		Mock mockInvocation = new Mock(ActionInvocation.class);
+		mockInvocation.expectAndReturn("getInvocationContext", new ActionContext(contextMap));
+		mockInvocation.matchAndReturn("getAction", new AllowingByDefaultAction());
+		mockInvocation.matchAndReturn("getStack", stack);
+		mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
+		
+		ActionInvocation invocation = (ActionInvocation) mockInvocation.proxy();
+		
+		AnnotationParameterFilterIntereptor intereptor = new AnnotationParameterFilterIntereptor();
+		intereptor.intercept(invocation);
+		
+		assertEquals("Paramter map should contain two entries", 2, parameterMap.size());
+		assertNotNull(parameterMap.get("job"));
+		assertNull(parameterMap.get("name"));
+		assertNull(parameterMap.get("m1"));
+		assertNotNull(parameterMap.get("m2"));
+		
+	}
+	
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationWorkflowInterceptorTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationWorkflowInterceptorTest.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationWorkflowInterceptorTest.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/AnnotationWorkflowInterceptorTest.java Fri Dec  2 16:33:03 2011
@@ -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 org.apache.struts2.xwork2.interceptor.annotations;
+
+import org.apache.struts2.xwork2.config.Configuration;
+import org.apache.struts2.xwork2.config.ConfigurationException;
+import org.apache.struts2.xwork2.Action;
+import org.apache.struts2.xwork2.ActionProxy;
+import org.apache.struts2.xwork2.DefaultActionProxyFactory;
+import org.apache.struts2.xwork2.ObjectFactory;
+import org.apache.struts2.xwork2.config.ConfigurationProvider;
+import org.apache.struts2.xwork2.config.entities.ActionConfig;
+import org.apache.struts2.xwork2.ActionProxyFactory;
+import org.apache.struts2.xwork2.XWorkTestCase;
+import org.apache.struts2.xwork2.config.entities.InterceptorMapping;
+import org.apache.struts2.xwork2.config.entities.PackageConfig;
+import org.apache.struts2.xwork2.config.entities.ResultConfig;
+import org.apache.struts2.xwork2.config.providers.XmlConfigurationProvider;
+import org.apache.struts2.xwork2.inject.ContainerBuilder;
+import org.apache.struts2.xwork2.mock.MockResult;
+import org.apache.struts2.xwork2.util.location.LocatableProperties;
+
+import java.util.Arrays;
+
+/**
+ * @author Zsolt Szasz, zsolt at lorecraft dot com
+ * @author Rainer Hermanns
+ */
+public class AnnotationWorkflowInterceptorTest extends XWorkTestCase {
+    private static final String ANNOTATED_ACTION = "annotatedAction";
+    private static final String SHORTCIRCUITED_ACTION = "shortCircuitedAction";
+    private final AnnotationWorkflowInterceptor annotationWorkflow = new AnnotationWorkflowInterceptor();
+
+    @Override
+    public void setUp() {
+        loadConfigurationProviders(new XmlConfigurationProvider("xwork-default.xml"), new MockConfigurationProvider());
+    }
+
+    public void testInterceptsBeforeAndAfter() throws Exception {
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", ANNOTATED_ACTION, null);
+        assertEquals(Action.SUCCESS, proxy.execute());
+        AnnotatedAction action = (AnnotatedAction)proxy.getInvocation().getAction();
+        assertEquals("baseBefore-before-execute-beforeResult-after", action.log);
+    }
+
+    public void testInterceptsShortcircuitedAction() throws Exception {
+        ActionProxy proxy = actionProxyFactory.createActionProxy("", SHORTCIRCUITED_ACTION, null);
+        assertEquals("shortcircuit", proxy.execute());
+        ShortcircuitedAction action = (ShortcircuitedAction)proxy.getInvocation().getAction();
+        assertEquals("baseBefore-before", action.log);
+    }
+
+    private class MockConfigurationProvider implements ConfigurationProvider {
+        private Configuration config;
+
+        public void init(Configuration configuration) throws ConfigurationException {
+            this.config = configuration;
+        }
+
+        public boolean needsReload() {
+            return false;
+        }
+
+        public void destroy() { }
+
+
+        public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
+            if (!builder.contains(ObjectFactory.class)) {
+                builder.factory(ObjectFactory.class);
+            }
+            if (!builder.contains(ActionProxyFactory.class)) {
+                builder.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class);
+            }
+        }
+
+        public void loadPackages() throws ConfigurationException {
+            PackageConfig packageConfig = new PackageConfig.Builder("default")
+                    .addActionConfig(ANNOTATED_ACTION, new ActionConfig.Builder("defaultPackage", ANNOTATED_ACTION, AnnotatedAction.class.getName())
+                            .addInterceptors(Arrays.asList(new InterceptorMapping[]{ new InterceptorMapping("annotationWorkflow", annotationWorkflow) }))
+                            .addResultConfig(new ResultConfig.Builder("success", MockResult.class.getName()).build())
+                            .build())
+                    .addActionConfig(SHORTCIRCUITED_ACTION, new ActionConfig.Builder("defaultPackage", SHORTCIRCUITED_ACTION, ShortcircuitedAction.class.getName())
+                            .addInterceptors(Arrays.asList(new InterceptorMapping[]{ new InterceptorMapping("annotationWorkflow", annotationWorkflow) }))
+                            .addResultConfig(new ResultConfig.Builder("shortcircuit", MockResult.class.getName()).build())
+                            .build())
+                    .build();
+            config.addPackageConfig("defaultPackage", packageConfig);
+            config.addPackageConfig("default", new PackageConfig.Builder(packageConfig).name("default").build());
+        }
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BaseAnnotatedAction.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BaseAnnotatedAction.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BaseAnnotatedAction.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BaseAnnotatedAction.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,32 @@
+/*
+ * 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 org.apache.struts2.xwork2.interceptor.annotations;
+
+/**
+ * @author Zsolt Szasz, zsolt at lorecraft dot com
+ * @author Rainer Hermanns
+ */
+public class BaseAnnotatedAction {
+
+	protected String log = "";
+	
+	@Before
+	public String baseBefore() {
+		log = log + "baseBefore-";
+		return null;
+	}
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultAction.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultAction.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultAction.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultAction.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,24 @@
+package org.apache.struts2.xwork2.interceptor.annotations;
+
+import org.apache.struts2.xwork2.ActionSupport;
+
+/**
+ * @author martin.gilday
+ *
+ */
+@BlockByDefault
+public class BlockingByDefaultAction extends ActionSupport {
+	
+	@Allowed
+	private String name;
+	private String job;
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	public void setJob(String job) {
+		this.job = job;
+	}
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultModel.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultModel.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultModel.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/BlockingByDefaultModel.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,22 @@
+package org.apache.struts2.xwork2.interceptor.annotations;
+
+/**
+ * @author jafl
+ *
+ */
+@BlockByDefault
+public class BlockingByDefaultModel {
+	
+	@Allowed
+	private String m1;
+	private String m2;
+	
+	public void setM1(String s) {
+		m1 = s;
+	}
+	
+	public void setM2(String s) {
+		m2 = s;
+	}
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/ShortcircuitedAction.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/ShortcircuitedAction.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/ShortcircuitedAction.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/interceptor/annotations/ShortcircuitedAction.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,35 @@
+/*
+ * 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 org.apache.struts2.xwork2.interceptor.annotations;
+
+import org.apache.struts2.xwork2.Action;
+
+/**
+ * @author Zsolt Szasz, zsolt at lorecraft dot com
+ * @author Rainer Hermanns
+ */
+public class ShortcircuitedAction extends BaseAnnotatedAction {	
+	@Before(priority=5)
+	public String before() {
+		log = log + "before";
+		return "shortcircuit";
+	}
+	
+	public String execute() {
+		log = log + "-execute-";
+		return Action.SUCCESS;
+	}
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlUtilTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlUtilTest.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlUtilTest.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlUtilTest.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,726 @@
+/*
+ * 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 org.apache.struts2.xwork2.ognl;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.XWorkException;
+import org.apache.struts2.xwork2.XWorkTestCase;
+import org.apache.struts2.xwork2.conversion.impl.XWorkConverter;
+import org.apache.struts2.xwork2.interceptor.ChainingInterceptor;
+import org.apache.struts2.xwork2.test.User;
+import org.apache.struts2.xwork2.util.CompoundRoot;
+import org.apache.struts2.xwork2.util.ValueStack;
+import org.apache.struts2.xwork2.util.reflection.ReflectionContextState;
+import ognl.*;
+import org.apache.struts2.xwork2.util.Bar;
+import org.apache.struts2.xwork2.util.Foo;
+import org.apache.struts2.xwork2.util.Owner;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+
+/**
+ * Unit test of {@link ognlUtil}.
+ * 
+ * @version $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $ $Id: OgnlUtilTest.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ */
+public class OgnlUtilTest extends XWorkTestCase {
+    
+    private OgnlUtil ognlUtil;
+    
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        ognlUtil = container.getInstance(OgnlUtil.class);
+    }
+    
+    public void testCanSetADependentObject() throws Exception {
+        String dogName = "fido";
+
+        OgnlRuntime.setNullHandler(Owner.class, new NullHandler() {
+            public Object nullMethodResult(Map map, Object o, String s, Object[] objects) {
+                return null;
+            }
+
+            public Object nullPropertyValue(Map map, Object o, Object o1) {
+                String methodName = o1.toString();
+                String getter = "set" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
+                Method[] methods = o.getClass().getDeclaredMethods();
+                System.out.println(getter);
+
+                for (Method method : methods) {
+                    String name = method.getName();
+
+                    if (!getter.equals(name) || (method.getParameterTypes().length != 1)) {
+                        continue;
+                    } else {
+                        Class clazz = method.getParameterTypes()[0];
+
+                        try {
+                            Object param = clazz.newInstance();
+                            method.invoke(o, new Object[]{param});
+
+                            return param;
+                        } catch (Exception e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                }
+
+                return null;
+            }
+        });
+
+        Owner owner = new Owner();
+        Map context = Ognl.createDefaultContext(owner);
+        Map props = new HashMap();
+        props.put("dog.name", dogName);
+
+        ognlUtil.setProperties(props, owner, context);
+        assertNotNull("expected Ognl to create an instance of Dog", owner.getDog());
+        assertEquals(dogName, owner.getDog().getName());
+    }
+
+    public void testCacheEnabled() throws OgnlException {
+        OgnlUtil.setEnableExpressionCache("true");
+        Object expr0 = ognlUtil.compile("test");
+        Object expr2 = ognlUtil.compile("test");
+        assertSame(expr0, expr2);
+    }
+
+     public void testCacheDisabled() throws OgnlException {
+        OgnlUtil.setEnableExpressionCache("false");
+        Object expr0 = ognlUtil.compile("test");
+        Object expr2 = ognlUtil.compile("test");
+        assertNotSame(expr0, expr2);
+    }
+
+    public void testCanSetDependentObjectArray() {
+        EmailAction action = new EmailAction();
+        Map<String, Object> context = Ognl.createDefaultContext(action);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("email[0].address", "addr1");
+        props.put("email[1].address", "addr2");
+        props.put("email[2].address", "addr3");
+
+        ognlUtil.setProperties(props, action, context);
+        assertEquals(3, action.email.size());
+        assertEquals("addr1", action.email.get(0).toString());
+        assertEquals("addr2", action.email.get(1).toString());
+        assertEquals("addr3", action.email.get(2).toString());
+    }
+
+    public void testCopySameType() {
+        Foo foo1 = new Foo();
+        Foo foo2 = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo1);
+
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, 12);
+        cal.set(Calendar.YEAR, 1982);
+
+        foo1.setTitle("blah");
+        foo1.setNumber(1);
+        foo1.setPoints(new long[]{1, 2, 3});
+        foo1.setBirthday(cal.getTime());
+        foo1.setUseful(false);
+
+        ognlUtil.copy(foo1, foo2, context);
+
+        assertEquals(foo1.getTitle(), foo2.getTitle());
+        assertEquals(foo1.getNumber(), foo2.getNumber());
+        assertEquals(foo1.getPoints(), foo2.getPoints());
+        assertEquals(foo1.getBirthday(), foo2.getBirthday());
+        assertEquals(foo1.isUseful(), foo2.isUseful());
+    }
+
+
+    public void testIncudeExcludes() {
+
+        Foo foo1 = new Foo();
+        Foo foo2 = new Foo();
+
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, 12);
+        cal.set(Calendar.YEAR, 1982);
+
+        foo1.setPoints(new long[]{1, 2, 3});
+        foo1.setBirthday(cal.getTime());
+        foo1.setUseful(false);
+
+
+        foo1.setTitle("foo1 title");
+        foo1.setNumber(1);
+
+        foo2.setTitle("foo2 title");
+        foo2.setNumber(2);
+
+        Map<String, Object> context = Ognl.createDefaultContext(foo1);
+
+        List<String> excludes = new ArrayList<String>();
+        excludes.add("title");
+        excludes.add("number");
+
+        ognlUtil.copy(foo1, foo2, context, excludes, null);
+        // these values should remain unchanged in foo2
+        assertEquals(foo2.getTitle(), "foo2 title");
+        assertEquals(foo2.getNumber(), 2);
+
+        // these values should be changed/copied
+        assertEquals(foo1.getPoints(), foo2.getPoints());
+        assertEquals(foo1.getBirthday(), foo2.getBirthday());
+        assertEquals(foo1.isUseful(), foo2.isUseful());
+
+
+        Bar b1 = new Bar();
+        Bar b2 = new Bar();
+
+        b1.setTitle("bar1 title");
+        b1.setSomethingElse(10);
+
+
+        b1.setId(new Long(1));
+
+        b2.setTitle("");
+        b2.setId(new Long(2));
+
+        context = Ognl.createDefaultContext(b1);
+        List<String> includes = new ArrayList<String>();
+        includes.add("title");
+        includes.add("somethingElse");
+
+        ognlUtil.copy(b1, b2, context, null, includes);
+        // includes properties got copied
+        assertEquals(b1.getTitle(), b2.getTitle());
+        assertEquals(b1.getSomethingElse(), b2.getSomethingElse());
+
+        // id properties did not
+        assertEquals(b2.getId(), new Long(2));
+
+    }
+
+
+    public void testCopyUnevenObjects() {
+        Foo foo = new Foo();
+        Bar bar = new Bar();
+
+        Map<String, Object> context = Ognl.createDefaultContext(foo);
+
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, 12);
+        cal.set(Calendar.YEAR, 1982);
+
+        foo.setTitle("blah");
+        foo.setNumber(1);
+        foo.setPoints(new long[]{1, 2, 3});
+        foo.setBirthday(cal.getTime());
+        foo.setUseful(false);
+
+        ognlUtil.copy(foo, bar, context);
+
+        assertEquals(foo.getTitle(), bar.getTitle());
+        assertEquals(0, bar.getSomethingElse());
+    }
+
+    public void testDeepSetting() {
+        Foo foo = new Foo();
+        foo.setBar(new Bar());
+
+        Map<String, Object> context = Ognl.createDefaultContext(foo);
+
+        Map<String, Object> props = new HashMap();
+        props.put("bar.title", "i am barbaz");
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(foo.getBar().getTitle(), "i am barbaz");
+    }
+
+    public void testNoExceptionForUnmatchedGetterAndSetterWithThrowPropertyException() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("myIntegerProperty", new Integer(1234));
+
+        TestObject testObject = new TestObject();
+
+        //this used to fail in OGNL versions < 2.7
+        ognlUtil.setProperties(props, testObject, true);
+        assertEquals(1234, props.get("myIntegerProperty"));
+    }
+
+    public void testExceptionForWrongPropertyNameWithThrowPropertyException() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("myStringProperty", "testString");
+
+        TestObject testObject = new TestObject();
+
+        try {
+            ognlUtil.setProperties(props, testObject, true);
+            fail("Should rise NoSuchPropertyException because of wrong property name");
+        } catch (Exception e) {
+            //expected
+        }
+    }
+
+    public void testOgnlHandlesCrapAtTheEndOfANumber() {
+        Foo foo = new Foo();
+        Map<String, Object> context = Ognl.createDefaultContext(foo);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("aLong", "123a");
+
+        ognlUtil.setProperties(props, foo, context);
+        assertEquals(0, foo.getALong());
+    }
+
+    /**
+     * Test that type conversion is performed on indexed collection properties.
+     */
+    public void testSetIndexedValue() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        Map<String, Object> stackContext = stack.getContext();
+        stackContext.put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE);
+        stackContext.put(ReflectionContextState.DENY_METHOD_EXECUTION, Boolean.TRUE);
+        stackContext.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+
+        User user = new User();
+        stack.push(user);
+
+        // indexed string w/ existing array
+        user.setList(new ArrayList<String>());
+        user.getList().add("");
+
+        String[] foo = new String[]{"asdf"};
+        stack.setValue("list[0]", foo);
+        assertNotNull(user.getList());
+        assertEquals(1, user.getList().size());
+        assertEquals(String.class, user.getList().get(0).getClass());
+        assertEquals("asdf", user.getList().get(0));
+    }
+
+    public void testSetPropertiesBoolean() {
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("useful", "true");
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(true, foo.isUseful());
+
+        props = new HashMap();
+        props.put("useful", "false");
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(false, foo.isUseful());
+    }
+
+    public void testSetPropertiesDate() {
+        Locale orig = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("birthday", "02/12/1982");
+        // US style test
+        ognlUtil.setProperties(props, foo, context);
+
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, 12);
+        cal.set(Calendar.YEAR, 1982);
+
+        assertEquals(cal.getTime(), foo.getBirthday());
+        
+        Locale.setDefault(Locale.UK);
+        //UK style test
+        props.put("event", "18/10/2006 14:23:45");
+        props.put("meeting", "09/09/2006 14:30");
+        ognlUtil.setProperties(props, foo, context);
+        
+        cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.OCTOBER);
+        cal.set(Calendar.DAY_OF_MONTH, 18);
+        cal.set(Calendar.YEAR, 2006);
+        cal.set(Calendar.HOUR_OF_DAY, 14);
+        cal.set(Calendar.MINUTE, 23);
+        cal.set(Calendar.SECOND, 45);
+        
+        assertEquals(cal.getTime(), foo.getEvent());
+        
+        cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
+        cal.set(Calendar.DAY_OF_MONTH, 9);
+        cal.set(Calendar.YEAR, 2006);
+        cal.set(Calendar.HOUR_OF_DAY, 14);
+        cal.set(Calendar.MINUTE, 30);
+        
+        assertEquals(cal.getTime(), foo.getMeeting());
+        
+        Locale.setDefault(orig);
+         
+        Locale.setDefault(orig);
+        
+        //test RFC 3339 date format for JSON
+        props.put("event", "1996-12-19T16:39:57Z");
+        ognlUtil.setProperties(props, foo, context);
+        
+        cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(Calendar.MONTH, Calendar.DECEMBER);
+        cal.set(Calendar.DAY_OF_MONTH, 19);
+        cal.set(Calendar.YEAR, 1996);
+        cal.set(Calendar.HOUR_OF_DAY, 16);
+        cal.set(Calendar.MINUTE, 39);
+        cal.set(Calendar.SECOND, 57);
+        
+        assertEquals(cal.getTime(), foo.getEvent());
+        
+        //test setting a calendar property
+        props.put("calendar", "1996-12-19T16:39:57Z");
+        ognlUtil.setProperties(props, foo, context);
+        assertEquals(cal, foo.getCalendar());
+    }
+
+    public void testSetPropertiesInt() {
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("number", "2");
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(2, foo.getNumber());
+    }
+
+    public void testSetPropertiesLongArray() {
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("points", new String[]{"1", "2"});
+        ognlUtil.setProperties(props, foo, context);
+
+        assertNotNull(foo.getPoints());
+        assertEquals(2, foo.getPoints().length);
+        assertEquals(1, foo.getPoints()[0]);
+        assertEquals(2, foo.getPoints()[1]);
+    }
+
+    public void testSetPropertiesString() {
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("title", "this is a title");
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(foo.getTitle(), "this is a title");
+    }
+
+    public void testSetProperty() {
+        Foo foo = new Foo();
+        Map context = Ognl.createDefaultContext(foo);
+        assertFalse(123456 == foo.getNumber());
+        ognlUtil.setProperty("number", "123456", foo, context);
+        assertEquals(123456, foo.getNumber());
+    }
+
+
+    public void testSetList() throws Exception {
+        ChainingInterceptor foo = new ChainingInterceptor();
+        ChainingInterceptor foo2 = new ChainingInterceptor();
+
+        OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
+        SimpleNode expression = (SimpleNode) Ognl.parseExpression("{'a','ruby','b','tom'}");
+
+
+        Ognl.getValue(expression, context, "aksdj");
+
+        final ValueStack stack = ActionContext.getContext().getValueStack();
+
+        Object result = Ognl.getValue(ognlUtil.compile("{\"foo\",'ruby','b','tom'}"), context, foo);
+        foo.setIncludes((Collection) result);
+
+        assertEquals(4, foo.getIncludes().size());
+        assertEquals("foo", foo.getIncludes().toArray()[0]);
+        assertEquals("ruby", foo.getIncludes().toArray()[1]);
+        assertEquals("b", "" + foo.getIncludes().toArray()[2]);
+        assertEquals("tom", foo.getIncludes().toArray()[3]);
+
+        Object result2 = Ognl.getValue(ognlUtil.compile("{\"foo\",'ruby','b','tom'}"), context, foo2);
+        ognlUtil.setProperty("includes", result2, foo2, context);
+
+        assertEquals(4, foo.getIncludes().size());
+        assertEquals("foo", foo.getIncludes().toArray()[0]);
+        assertEquals("ruby", foo.getIncludes().toArray()[1]);
+        assertEquals("b", "" + foo.getIncludes().toArray()[2]);
+        assertEquals("tom", foo.getIncludes().toArray()[3]);
+
+        result = ActionContext.getContext().getValueStack().findValue("{\"foo\",'ruby','b','tom'}");
+
+        foo.setIncludes((Collection) result);
+        assertEquals(ArrayList.class, result.getClass());
+
+        assertEquals(4, foo.getIncludes().size());
+        assertEquals("foo", foo.getIncludes().toArray()[0]);
+        assertEquals("ruby", foo.getIncludes().toArray()[1]);
+        assertEquals("b", "" + foo.getIncludes().toArray()[2]);
+        assertEquals("tom", foo.getIncludes().toArray()[3]);
+    }
+
+
+    public void testStringToLong() {
+        Foo foo = new Foo();
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        Map props = new HashMap();
+        props.put("aLong", "123");
+
+        ognlUtil.setProperties(props, foo, context);
+        assertEquals(123, foo.getALong());
+
+        props.put("aLong", new String[]{"123"});
+
+        foo.setALong(0);
+        ognlUtil.setProperties(props, foo, context);
+        assertEquals(123, foo.getALong());
+    }
+
+    public void testNullProperties() {
+        Foo foo = new Foo();
+        foo.setALong(88);
+
+        Map context = Ognl.createDefaultContext(foo);
+
+        ognlUtil.setProperties(null, foo, context);
+        assertEquals(88, foo.getALong());
+
+        Map props = new HashMap();
+        props.put("aLong", "99");
+        ognlUtil.setProperties(props, foo, context);
+        assertEquals(99, foo.getALong());
+    }
+    
+    public void testCopyNull() {
+        Foo foo = new Foo();
+        Map context = Ognl.createDefaultContext(foo);
+   		ognlUtil.copy(null, null, context);
+
+   		ognlUtil.copy(foo, null, context);
+   		ognlUtil.copy(null, foo, context);
+    }
+    
+    public void testGetTopTarget() throws Exception {
+        Foo foo = new Foo();
+        Map context = Ognl.createDefaultContext(foo);
+
+        CompoundRoot root = new CompoundRoot();
+        Object top = ognlUtil.getRealTarget("top", context, root);
+        assertEquals(root, top); // top should be root
+        
+        root.push(foo);
+        Object val = ognlUtil.getRealTarget("unknown", context, root);
+        assertNull(val); // not found
+    }
+    
+    public void testGetBeanMap() throws Exception {
+    	Bar bar = new Bar();
+    	bar.setTitle("I have beer");
+        
+    	Foo foo = new Foo();
+        foo.setALong(123);
+        foo.setNumber(44);
+        foo.setBar(bar);
+        foo.setTitle("Hello Santa");
+        foo.setUseful(true);
+        
+        // just do some of the 15 tests
+        Map beans = ognlUtil.getBeanMap(foo);
+        assertNotNull(beans);
+        assertEquals(19, beans.size());
+        assertEquals("Hello Santa", beans.get("title"));
+        assertEquals(new Long("123"), beans.get("ALong"));
+        assertEquals(new Integer("44"), beans.get("number"));
+        assertEquals(bar, beans.get("bar"));
+        assertEquals(Boolean.TRUE, beans.get("useful"));
+    }
+
+    public void testGetBeanMapNoReadMethod() throws Exception {
+    	MyWriteBar bar = new MyWriteBar();
+    	bar.setBar("Sams");
+    	
+    	Map beans = ognlUtil.getBeanMap(bar);
+    	assertEquals(2, beans.size());
+    	assertEquals(new Integer("1"), beans.get("id"));
+    	assertEquals("There is no read method for bar", beans.get("bar"));
+    }
+
+    /**
+	 * XW-281
+	 */
+    public void testSetBigIndexedValue() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        Map stackContext = stack.getContext();
+        stackContext.put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.FALSE);
+        stackContext.put(ReflectionContextState.DENY_METHOD_EXECUTION, Boolean.TRUE);
+        stackContext.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+
+        User user = new User();
+        stack.push(user);
+
+        // indexed string w/ existing array
+        user.setList(new ArrayList());
+
+        String[] foo = new String[]{"asdf"};
+        ((OgnlValueStack)stack).setDevMode("true");
+        try {
+            stack.setValue("list.1114778947765", foo);
+            fail("non-valid expression: list.1114778947765"); 
+        }
+        catch(RuntimeException ex) {
+            ; // it's oke
+        }
+        
+        try {
+            stack.setValue("1114778947765", foo);
+            fail("non-valid expression: 1114778947765"); 
+        }
+        catch(RuntimeException ex) {
+            ;
+        }
+        
+        try {
+            stack.setValue("1234", foo);
+            fail("non-valid expression: 1114778947765"); 
+        }
+        catch(RuntimeException ex) {
+            ;
+        }
+        
+        ((OgnlValueStack)stack).setDevMode("false");
+        stack.setValue("list.1114778947765", foo);
+        stack.setValue("1114778947765", foo);
+        stack.setValue("1234", foo);
+    }
+    
+
+    public static class Email {
+        String address;
+
+        public void setAddress(String address) {
+            this.address = address;
+        }
+
+        @Override
+        public String toString() {
+            return address;
+        }
+    }
+
+    static class TestObject {
+        private Integer myIntegerProperty;
+        private Long myLongProperty;
+        private String myStrProperty;
+
+        public void setMyIntegerProperty(Integer myIntegerProperty) {
+            this.myIntegerProperty = myIntegerProperty;
+        }
+
+        public String getMyIntegerProperty() {
+            return myIntegerProperty.toString();
+        }
+
+        public void setMyLongProperty(Long myLongProperty) {
+            this.myLongProperty = myLongProperty;
+        }
+
+        public Long getMyLongProperty() {
+            return myLongProperty;
+        }
+
+        public void setMyStrProperty(String myStrProperty) {
+            this.myStrProperty = myStrProperty;
+        }
+
+        public String getMyStrProperty() {
+            return myStrProperty;
+        }
+    }
+
+    class EmailAction {
+        public List email = new OgnlList(Email.class);
+
+        public List getEmail() {
+            return this.email;
+        }
+    }
+
+    class OgnlList extends ArrayList {
+        private Class clazz;
+
+        public OgnlList(Class clazz) {
+            this.clazz = clazz;
+        }
+
+        @Override
+        public synchronized Object get(int index) {
+            while (index >= this.size()) {
+                try {
+                    this.add(clazz.newInstance());
+                } catch (Exception e) {
+                    throw new XWorkException(e);
+                }
+            }
+
+            return super.get(index);
+        }
+    }
+    
+    private class MyWriteBar {
+    	private int id;
+    	
+    	public int getId() {
+    		return id;
+    	}
+    	
+    	public void setBar(String name) {
+    		if ("Sams".equals(name))
+    			id = 1;
+    		else
+    			id = 999;
+    	}
+    	
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlValueStackTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlValueStackTest.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlValueStackTest.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/test/java/org/apache/struts2/xwork2/ognl/OgnlValueStackTest.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,1037 @@
+/*
+ * 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 org.apache.struts2.xwork2.ognl;
+
+import junit.framework.Assert;
+import org.apache.struts2.xwork2.conversion.impl.XWorkConverter;
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.TextProvider;
+import org.apache.struts2.xwork2.XWorkException;
+import org.apache.struts2.xwork2.XWorkTestCase;
+import org.apache.struts2.xwork2.ognl.accessor.CompoundRootAccessor;
+import org.apache.struts2.xwork2.test.TestBean2;
+import org.apache.struts2.xwork2.util.Bar;
+import org.apache.struts2.xwork2.util.Foo;
+import org.apache.struts2.xwork2.util.CompoundRoot;
+import org.apache.struts2.xwork2.util.reflection.ReflectionContextState;
+import ognl.PropertyAccessor;
+import org.apache.struts2.xwork2.SimpleAction;
+import org.apache.struts2.xwork2.TestBean;
+import org.apache.struts2.xwork2.util.BarJunior;
+import org.apache.struts2.xwork2.util.Cat;
+import org.apache.struts2.xwork2.util.Dog;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * Unit test for OgnlValueStack.
+ */
+public class OgnlValueStackTest extends XWorkTestCase {
+
+    public static Integer staticNullMethod() {
+        return null;
+    }
+
+    private OgnlUtil ognlUtil;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        ognlUtil = container.getInstance(OgnlUtil.class);
+    }
+
+    private OgnlValueStack createValueStack() {
+        return createValueStack(true);
+    }
+
+    private OgnlValueStack createValueStack(boolean allowStaticMethodAccess) {
+        OgnlValueStack stack = new OgnlValueStack(
+                container.getInstance(XWorkConverter.class),
+                (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
+                container.getInstance(TextProvider.class, "system"), allowStaticMethodAccess);
+        container.inject(stack);
+        return stack;
+    }
+
+    public void testExpOverridesCanStackExpUp() throws Exception {
+        Map expr1 = new LinkedHashMap();
+        expr1.put("expr1", "'expr1value'");
+
+        OgnlValueStack vs = createValueStack();
+        vs.setExprOverrides(expr1);
+
+        assertEquals(vs.findValue("expr1"), "expr1value");
+
+        Map expr2 = new LinkedHashMap();
+        expr2.put("expr2", "'expr2value'");
+        expr2.put("expr3", "'expr3value'");
+        vs.setExprOverrides(expr2);
+
+        assertEquals(vs.findValue("expr2"), "expr2value");
+        assertEquals(vs.findValue("expr3"), "expr3value");
+    }
+
+
+    public void testArrayAsString() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+        dog.setChildAges(new int[]{1, 2});
+
+        vs.push(dog);
+        assertEquals("1, 2", vs.findValue("childAges", String.class));
+    }
+
+    public void testFailOnException() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        vs.push(dog);
+        try {
+            vs.findValue("bite", true);
+            fail("Failed to throw exception on EL error");
+        } catch (Exception ex) {
+            //ok
+        }
+    }
+
+    public void testFailOnErrorOnInheritedProperties() {
+        //this shuld not fail as the property is defined on a parent class
+        OgnlValueStack vs = createValueStack();
+
+        Foo foo = new Foo();
+        BarJunior barjr = new BarJunior();
+        foo.setBarJunior(barjr);
+        vs.push(foo);
+
+        assertNull(barjr.getTitle());
+        vs.findValue("barJunior.title", true);
+    }
+
+     public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
+        //this shuld not fail as the property is defined on a parent class
+        OgnlValueStack vs = createValueStack();
+
+        Foo foo = new Foo();
+        BarJunior barjr = new BarJunior();
+        foo.setBarJunior(barjr);
+        vs.push(foo);
+
+        assertNull(barjr.getTitle());
+        vs.findValue("getBarJunior().title", true);
+    }
+
+    public void testFailFailOnErrorOnInheritedPropertiesWithMethods() {
+        OgnlValueStack vs = createValueStack();
+
+        Foo foo = new Foo();
+        BarJunior barjr = new BarJunior();
+        foo.setBarJunior(barjr);
+        vs.push(foo);
+
+        assertNull(barjr.getTitle());
+        try {
+            vs.findValue("getBarJunior().title2", true);
+            fail("should have failed on missing property");
+        } catch (Exception e) {
+        }
+    }
+
+    public void testFailOnMissingProperty() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        vs.push(dog);
+        try {
+            vs.findValue("someprop", true);
+            fail("Failed to throw exception on EL missing property");
+        } catch (Exception ex) {
+            //ok
+        }
+    }
+
+    public void testFailOnMissingMethod() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        vs.push(dog);
+        try {
+            vs.findValue("someprop()", true);
+            fail("Failed to throw exception on EL missing method");
+        } catch (Exception ex) {
+            //ok
+        }
+    }
+
+    public void testFailsOnMethodThatThrowsException() {
+        SimpleAction action = new SimpleAction();
+        OgnlValueStack stack = createValueStack();
+        stack.push(action);
+
+        action.setThrowException(true);
+        try {
+            stack.findValue("exceptionMethod12()", true);
+            fail("Failed to throw exception on EL method exception");
+        } catch (Exception ex) {
+            //ok
+        }
+    }
+
+
+    public void testDoesNotFailOnNonActionObjects() {
+        //if a value is not found, then it will check for missing properties
+        //it needs to check in all objects in the stack, not only actions, see WW-3306
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setHates(null);
+        vs.push(dog);
+        vs.findValue("hates", true);
+    }
+
+
+    public void testFailOnMissingNestedProperty() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setHates(new Cat());
+        vs.push(dog);
+        try {
+            vs.findValue("hates.someprop", true);
+            fail("Failed to throw exception on EL missing nested property");
+        } catch (Exception ex) {
+            //ok
+        }
+    }
+
+    public void testBasic() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+
+        vs.push(dog);
+        assertEquals("Rover", vs.findValue("name", String.class));
+    }
+
+    public void testStatic() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setDeity("fido");
+        vs.push(dog);
+        assertEquals("fido", vs.findValue("@org.apache.struts2.xwork2.util.Dog@getDeity()", String.class));
+    }
+
+    public void testStaticMethodDisallow() {
+        OgnlValueStack vs = createValueStack(false);
+
+        Dog dog = new Dog();
+        dog.setDeity("fido");
+        vs.push(dog);
+        assertNull(vs.findValue("@org.apache.struts2.xwork2.util.Dog@getDeity()", String.class));
+    }
+
+    public void testBasicSet() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+
+        vs.set("dog", dog);
+        assertEquals("Rover", vs.findValue("dog.name", String.class));
+    }
+
+    public void testCallMethodOnNullObject() {
+        OgnlValueStack stack = createValueStack();
+        assertNull(stack.findValue("foo.size()"));
+    }
+
+    public void testCallMethodThatThrowsExceptionTwice() {
+        SimpleAction action = new SimpleAction();
+        OgnlValueStack stack = createValueStack();
+        stack.push(action);
+
+        action.setThrowException(true);
+        assertNull(stack.findValue("exceptionMethod1()"));
+        action.setThrowException(false);
+        assertEquals("OK", stack.findValue("exceptionMethod()"));
+    }
+
+
+    public void testCallMethodWithNullArg() {
+        SimpleAction action = new SimpleAction();
+        OgnlValueStack stack = createValueStack();
+        stack.push(action);
+
+        stack.findValue("setName(blah)");
+        assertNull(action.getName());
+
+        action.setBlah("blah");
+        stack.findValue("setName(blah)");
+        assertEquals("blah", action.getName());
+    }
+
+    public void testConvertStringArrayToList() {
+        Foo foo = new Foo();
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        vs.setValue("strings", new String[]{"one", "two"});
+
+        assertNotNull(foo.getStrings());
+        assertEquals("one", foo.getStrings().get(0));
+        assertEquals("two", foo.getStrings().get(1));
+    }
+
+    public void testFindValueWithConversion() {
+
+        // register converter
+        TestBean2 tb2 = new TestBean2();
+
+        OgnlValueStack stack = createValueStack();
+        stack.push(tb2);
+        Map myContext = stack.getContext();
+
+        Map props = new HashMap();
+        props.put("cat", "Kitty");
+        ognlUtil.setProperties(props, tb2, myContext);
+        // expect String to be converted into a Cat
+        Assert.assertEquals("Kitty", tb2.getCat().getName());
+
+        // findValue should be able to access the name
+        Object value = stack.findValue("cat.name == 'Kitty'", Boolean.class);
+        assertNotNull(value);
+        assertEquals(Boolean.class, value.getClass());
+        assertEquals(Boolean.TRUE, value);
+
+        value = stack.findValue("cat == null", Boolean.class);
+        assertNotNull(value);
+        assertEquals(Boolean.class, value.getClass());
+        assertEquals(Boolean.FALSE, value);
+    }
+
+
+    public void testDeepProperties() {
+        OgnlValueStack vs = createValueStack();
+
+        Cat cat = new Cat();
+        cat.setName("Smokey");
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+        dog.setChildAges(new int[]{1, 2});
+        dog.setHates(cat);
+
+        vs.push(dog);
+        assertEquals("Smokey", vs.findValue("hates.name", String.class));
+    }
+
+    public void testFooBarAsString() {
+        OgnlValueStack vs = createValueStack();
+        Foo foo = new Foo();
+        Bar bar = new Bar();
+        bar.setTitle("blah");
+        bar.setSomethingElse(123);
+        foo.setBar(bar);
+
+        vs.push(foo);
+        assertEquals("blah:123", vs.findValue("bar", String.class));
+    }
+
+    public void testGetBarAsString() {
+        Foo foo = new Foo();
+        Bar bar = new Bar();
+        bar.setTitle("bar");
+        bar.setSomethingElse(123);
+        foo.setBar(bar);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        String output = (String) vs.findValue("bar", String.class);
+        assertEquals("bar:123", output);
+    }
+
+    public void testGetComplexBarAsString() {
+        // children foo->foo->foo
+        Foo foo = new Foo();
+        Foo foo2 = new Foo();
+        foo.setChild(foo2);
+
+        Foo foo3 = new Foo();
+        foo2.setChild(foo3);
+
+        // relatives
+        Foo fooA = new Foo();
+        foo.setRelatives(new Foo[]{fooA});
+
+        Foo fooB = new Foo();
+        foo2.setRelatives(new Foo[]{fooB});
+
+        Foo fooC = new Foo();
+        foo3.setRelatives(new Foo[]{fooC});
+
+        // the bar
+        Bar bar = new Bar();
+        bar.setTitle("bar");
+        bar.setSomethingElse(123);
+
+        // now place the bar all over
+        foo.setBar(bar);
+        foo2.setBar(bar);
+        foo3.setBar(bar);
+        fooA.setBar(bar);
+        fooB.setBar(bar);
+        fooC.setBar(bar);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        vs.getContext().put("foo", foo);
+
+        assertEquals("bar:123", vs.findValue("#foo.bar", String.class));
+        assertEquals("bar:123", vs.findValue("bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.child.bar", String.class));
+        assertEquals("bar:123", vs.findValue("relatives[0].bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.relatives[0].bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.child.relatives[0].bar", String.class));
+
+        vs.push(vs.findValue("child"));
+        assertEquals("bar:123", vs.findValue("bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.bar", String.class));
+        assertEquals("bar:123", vs.findValue("relatives[0].bar", String.class));
+        assertEquals("bar:123", vs.findValue("child.relatives[0].bar", String.class));
+    }
+
+    public void testGetNullValue() {
+        Dog dog = new Dog();
+        OgnlValueStack stack = createValueStack();
+        stack.push(dog);
+        assertNull(stack.findValue("name"));
+    }
+
+    public void testMapEntriesAvailableByKey() {
+        Foo foo = new Foo();
+        String title = "a title";
+        foo.setTitle(title);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        Map map = new HashMap();
+        String a_key = "a";
+        String a_value = "A";
+        map.put(a_key, a_value);
+
+        String b_key = "b";
+        String b_value = "B";
+        map.put(b_key, b_value);
+
+        vs.push(map);
+
+        assertEquals(title, vs.findValue("title"));
+        assertEquals(a_value, vs.findValue(a_key));
+        assertEquals(b_value, vs.findValue(b_key));
+    }
+
+    public void testMethodCalls() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog1 = new Dog();
+        dog1.setAge(12);
+        dog1.setName("Rover");
+
+        Dog dog2 = new Dog();
+        dog2.setAge(1);
+        dog2.setName("Jack");
+        vs.push(dog1);
+        vs.push(dog2);
+
+        //assertEquals(new Boolean(false), vs.findValue("'Rover'.endsWith('Jack')"));
+        //assertEquals(new Boolean(false), vs.findValue("'Rover'.endsWith(name)"));
+        //assertEquals("RoverJack", vs.findValue("[1].name + name"));
+        assertEquals(new Boolean(false), vs.findValue("[1].name.endsWith(name)"));
+
+        assertEquals(new Integer(1 * 7), vs.findValue("computeDogYears()"));
+        assertEquals(new Integer(1 * 2), vs.findValue("multiplyAge(2)"));
+        assertEquals(new Integer(12 * 7), vs.findValue("[1].computeDogYears()"));
+        assertEquals(new Integer(12 * 5), vs.findValue("[1].multiplyAge(5)"));
+        assertNull(vs.findValue("thisMethodIsBunk()"));
+        assertEquals(new Integer(12 * 1), vs.findValue("[1].multiplyAge(age)"));
+
+        assertEquals("Jack", vs.findValue("name"));
+        assertEquals("Rover", vs.findValue("[1].name"));
+
+        //hates will be null
+        assertEquals(Boolean.TRUE, vs.findValue("nullSafeMethod(hates)"));
+    }
+
+    public void testMismatchedGettersAndSettersCauseExceptionInSet() {
+        OgnlValueStack vs = createValueStack();
+
+        BadJavaBean bean = new BadJavaBean();
+        vs.push(bean);
+
+        //this used to fail in OGNl versdion < 2.7
+        vs.setValue("count", "1", true);
+        assertEquals("1", bean.getCount());
+
+        try {
+            vs.setValue("count2", "a", true);
+            fail("Expected an exception for mismatched getter and setter");
+        } catch (XWorkException e) {
+            //expected
+        }
+    }
+
+    public void testNoExceptionInSetForDefault() {
+        OgnlValueStack vs = createValueStack();
+
+        BadJavaBean bean = new BadJavaBean();
+        vs.push(bean);
+
+        //this used to fail in OGNl versdion < 2.7
+        vs.setValue("count", "1", true);
+        assertEquals("1", bean.getCount());
+
+        try {
+            vs.setValue("count2", "a", true);
+            fail("Expected an exception for mismatched getter and setter");
+        } catch (XWorkException e) {
+            //expected
+        }
+    }
+
+    public void testNullEntry() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setName("Rover");
+
+        vs.push(dog);
+        assertEquals("Rover", vs.findValue("name", String.class));
+
+        vs.push(null);
+        assertEquals("Rover", vs.findValue("name", String.class));
+    }
+
+    public void testNullMethod() {
+        Dog dog = new Dog();
+        OgnlValueStack stack = createValueStack();
+        stack.push(dog);
+        assertNull(stack.findValue("nullMethod()"));
+        assertNull(stack.findValue("@org.apache.struts2.xwork2.util.OgnlValueStackTest@staticNullMethod()"));
+    }
+
+    public void testPetSoarBug() {
+        Cat cat = new Cat();
+        cat.setFoo(new Foo());
+
+        Bar bar = new Bar();
+        bar.setTitle("bar");
+        bar.setSomethingElse(123);
+        cat.getFoo().setBar(bar);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(cat);
+
+        assertEquals("bar:123", vs.findValue("foo.bar", String.class));
+    }
+
+    public void testPrimitiveSettingWithInvalidValueAddsFieldErrorInDevMode() {
+        SimpleAction action = new SimpleAction();
+        OgnlValueStack stack = createValueStack();
+        stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+        stack.setDevMode("true");
+        stack.push(action);
+
+        try {
+            stack.setValue("bar", "3x");
+            fail("Attempt to set 'bar' int property to '3x' should result in RuntimeException");
+        }
+        catch (RuntimeException re) {
+            assertTrue(true);
+        }
+
+        Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
+        assertTrue(conversionErrors.containsKey("bar"));
+    }
+
+    public void testPrimitiveSettingWithInvalidValueAddsFieldErrorInNonDevMode() {
+        SimpleAction action = new SimpleAction();
+        OgnlValueStack stack = createValueStack();
+        stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+        stack.setDevMode("false");
+        stack.push(action);
+        stack.setValue("bar", "3x");
+
+        Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
+        assertTrue(conversionErrors.containsKey("bar"));
+    }
+
+
+    public void testObjectSettingWithInvalidValueDoesNotCauseSetCalledWithNull() {
+        SimpleAction action = new SimpleAction();
+        action.setBean(new TestBean());
+        OgnlValueStack stack = createValueStack();
+        stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+        stack.push(action);
+        try {
+            stack.setValue("bean", "foobar", true);
+            fail("Should have thrown a type conversion exception");
+        } catch (XWorkException e) {
+            // expected
+        }
+
+        Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
+        assertTrue(conversionErrors.containsKey("bean"));
+        assertNotNull(action.getBean());
+    }
+
+
+    public void testSerializable() throws IOException, ClassNotFoundException {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+
+        vs.push(dog);
+        assertEquals("Rover", vs.findValue("name", String.class));
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+
+        oos.writeObject(vs);
+        oos.flush();
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream ois = new ObjectInputStream(bais);
+
+        OgnlValueStack newVs = (OgnlValueStack) ois.readObject();
+        assertEquals("Rover", newVs.findValue("name", String.class));
+    }
+
+    public void testSetAfterPush() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog d = new Dog();
+        d.setName("Rover");
+        vs.push(d);
+
+        vs.set("name", "Bill");
+
+        assertEquals("Bill", vs.findValue("name"));
+
+    }
+
+    public void testSetBarAsString() {
+        Foo foo = new Foo();
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        vs.setValue("bar", "bar:123");
+
+        assertEquals("bar", foo.getBar().getTitle());
+        assertEquals(123, foo.getBar().getSomethingElse());
+    }
+
+    public void testSetBeforePush() {
+        OgnlValueStack vs = createValueStack();
+
+        vs.set("name", "Bill");
+        Dog d = new Dog();
+        d.setName("Rover");
+        vs.push(d);
+
+        assertEquals("Rover", vs.findValue("name"));
+
+    }
+
+    public void testSetDeepBarAsString() {
+        Foo foo = new Foo();
+        Foo foo2 = new Foo();
+        foo.setChild(foo2);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        vs.setValue("child.bar", "bar:123");
+
+        assertEquals("bar", foo.getChild().getBar().getTitle());
+        assertEquals(123, foo.getChild().getBar().getSomethingElse());
+    }
+
+    public void testSetNullList() {
+        Foo foo = new Foo();
+        OgnlValueStack vs = createValueStack();
+        vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE);
+        vs.push(foo);
+
+        vs.setValue("cats[0].name", "Cat One");
+        vs.setValue("cats[1].name", "Cat Two");
+
+        assertNotNull(foo.getCats());
+        assertEquals(2, foo.getCats().size());
+        assertEquals("Cat One", ((Cat) foo.getCats().get(0)).getName());
+        assertEquals("Cat Two", ((Cat) foo.getCats().get(1)).getName());
+
+        vs.setValue("cats[0].foo.cats[1].name", "Deep null cat");
+        assertNotNull(((Cat) foo.getCats().get(0)).getFoo());
+        assertNotNull(((Cat) foo.getCats().get(0)).getFoo().getCats());
+        assertNotNull(((Cat) foo.getCats().get(0)).getFoo().getCats().get(1));
+        assertEquals("Deep null cat", ((Cat) ((Cat) foo.getCats().get(0)).getFoo().getCats().get(1)).getName());
+    }
+
+    public void testSetMultiple() {
+        OgnlValueStack vs = createValueStack();
+        int origSize = vs.getRoot().size();
+        vs.set("something", new Object());
+        vs.set("somethingElse", new Object());
+        vs.set("yetSomethingElse", new Object());
+        assertEquals(origSize + 1, vs.getRoot().size());
+
+    }
+
+    public void testSetNullMap() {
+        Foo foo = new Foo();
+        OgnlValueStack vs = createValueStack();
+        vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE);
+        vs.push(foo);
+
+        vs.setValue("catMap['One'].name", "Cat One");
+        vs.setValue("catMap['Two'].name", "Cat Two");
+
+        assertNotNull(foo.getCatMap());
+        assertEquals(2, foo.getCatMap().size());
+        assertEquals("Cat One", ((Cat) foo.getCatMap().get("One")).getName());
+        assertEquals("Cat Two", ((Cat) foo.getCatMap().get("Two")).getName());
+
+        vs.setValue("catMap['One'].foo.catMap['Two'].name", "Deep null cat");
+        assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo());
+        assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo().getCatMap());
+        assertNotNull(((Cat) foo.getCatMap().get("One")).getFoo().getCatMap().get("Two"));
+        assertEquals("Deep null cat", ((Cat) ((Cat) foo.getCatMap().get("One")).getFoo().getCatMap().get("Two")).getName());
+    }
+
+    public void testSetReallyDeepBarAsString() {
+        Foo foo = new Foo();
+        Foo foo2 = new Foo();
+        foo.setChild(foo2);
+
+        Foo foo3 = new Foo();
+        foo2.setChild(foo3);
+
+        OgnlValueStack vs = createValueStack();
+        vs.push(foo);
+
+        vs.setValue("child.child.bar", "bar:123");
+
+        assertEquals("bar", foo.getChild().getChild().getBar().getTitle());
+        assertEquals(123, foo.getChild().getChild().getBar().getSomethingElse());
+    }
+
+    public void testSettingDogGender() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog = new Dog();
+        vs.push(dog);
+
+        vs.setValue("male", "false");
+
+        assertEquals(false, dog.isMale());
+    }
+
+    public void testStatics() {
+        OgnlValueStack vs = createValueStack();
+
+        Cat cat = new Cat();
+        vs.push(cat);
+
+        Dog dog = new Dog();
+        dog.setAge(12);
+        dog.setName("Rover");
+        vs.push(dog);
+
+        assertEquals("Canine", vs.findValue("@vs@SCIENTIFIC_NAME"));
+        assertEquals("Canine", vs.findValue("@vs1@SCIENTIFIC_NAME"));
+        assertEquals("Feline", vs.findValue("@vs2@SCIENTIFIC_NAME"));
+        assertEquals(new Integer(BigDecimal.ROUND_HALF_DOWN), vs.findValue("@java.math.BigDecimal@ROUND_HALF_DOWN"));
+        assertNull(vs.findValue("@vs3@BLAH"));
+        assertNull(vs.findValue("@com.nothing.here.Nothing@BLAH"));
+    }
+
+    public void testTop() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog1 = new Dog();
+        dog1.setAge(12);
+        dog1.setName("Rover");
+
+        Dog dog2 = new Dog();
+        dog2.setAge(1);
+        dog2.setName("Jack");
+        vs.push(dog1);
+        vs.push(dog2);
+
+        assertEquals(dog2, vs.findValue("top"));
+        assertEquals("Jack", vs.findValue("top.name"));
+    }
+
+    public void testTopIsDefaultTextProvider() {
+        OgnlValueStack vs = createValueStack();
+
+        assertEquals(container.getInstance(TextProvider.class, "system"), vs.findValue("top"));
+    }
+
+    public void testTwoDogs() {
+        OgnlValueStack vs = createValueStack();
+
+        Dog dog1 = new Dog();
+        dog1.setAge(12);
+        dog1.setName("Rover");
+
+        Dog dog2 = new Dog();
+        dog2.setAge(1);
+        dog2.setName("Jack");
+        vs.push(dog1);
+        vs.push(dog2);
+
+        assertEquals("Jack", vs.findValue("name"));
+        assertEquals("Rover", vs.findValue("[1].name"));
+
+        assertEquals(dog2, vs.pop());
+        assertEquals("Rover", vs.findValue("name"));
+    }
+
+    public void testTypeConversionError() {
+        TestBean bean = new TestBean();
+        OgnlValueStack stack = createValueStack();
+        stack.push(bean);
+        stack.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
+        try {
+            stack.setValue("count", "a", true);
+            fail("Should have thrown a type conversion exception");
+        } catch (XWorkException e) {
+            // expected
+        }
+
+        Map conversionErrors = (Map) stack.getContext().get(ActionContext.CONVERSION_ERRORS);
+        assertTrue(conversionErrors.containsKey("count"));
+    }
+
+    public void testConstructorWithAStack() {
+        OgnlValueStack stack = createValueStack();
+        stack.push("Hello World");
+
+        OgnlValueStack stack2 = new OgnlValueStack(stack,
+                container.getInstance(XWorkConverter.class),
+                (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true);
+        container.inject(stack2);
+
+        assertEquals(stack.getRoot(), stack2.getRoot());
+        assertEquals(stack.peek(), stack2.peek());
+        assertEquals("Hello World", stack2.pop());
+
+    }
+
+    public void testDefaultType() {
+        OgnlValueStack stack = createValueStack();
+        stack.setDefaultType(String.class);
+        stack.push("Hello World");
+
+        assertEquals("Hello World", stack.findValue("top"));
+        assertEquals(null, stack.findValue(null));
+
+        stack.setDefaultType(Integer.class);
+        stack.push(new Integer(123));
+        assertEquals(new Integer(123), stack.findValue("top"));
+    }
+
+    public void testFindString() {
+        OgnlValueStack stack = createValueStack();
+        stack.setDefaultType(Integer.class);
+        stack.push("Hello World");
+
+        assertEquals("Hello World", stack.findString("top"));
+        assertEquals(null, stack.findString(null));
+    }
+
+    public void testExpOverrides() {
+        Map overrides = new HashMap();
+        overrides.put("claus", "top");
+
+        OgnlValueStack stack = createValueStack();
+        stack.setExprOverrides(overrides);
+        stack.push("Hello World");
+
+        assertEquals("Hello World", stack.findValue("claus"));
+        assertEquals("Hello World", stack.findString("claus"));
+        assertEquals("Hello World", stack.findValue("top"));
+        assertEquals("Hello World", stack.findString("top"));
+
+        assertEquals("Hello World", stack.findValue("claus", String.class));
+        assertEquals("Hello World", stack.findValue("top", String.class));
+
+        stack.getContext().put("santa", "Hello Santa");
+        assertEquals("Hello Santa", stack.findValue("santa", String.class));
+        assertEquals(null, stack.findValue("unknown", String.class));
+    }
+
+    public void testWarnAboutInvalidProperties() {
+        OgnlValueStack stack = createValueStack();
+        MyAction action = new MyAction();
+        action.setName("Don");
+        stack.push(action);
+
+        // how to test the warning was logged?
+        assertEquals("Don", stack.findValue("name", String.class));
+        assertEquals(null, stack.findValue("address", String.class));
+        // should log warning
+        assertEquals(null, stack.findValue("address.invalidProperty", String.class));
+
+        // if country is null, OGNL throws an exception
+        /*action.setAddress(new Address());
+        stack.push(action);*/
+        // should log warning
+        assertEquals(null, stack.findValue("address.country.id", String.class));
+        assertEquals(null, stack.findValue("address.country.name", String.class));
+    }
+
+    class BadJavaBean {
+        private int count;
+        private int count2;
+
+        public void setCount(int count) {
+            this.count = count;
+        }
+
+        public String getCount() {
+            return "" + count;
+        }
+
+        public void setCount2(String count2) {
+            this.count2 = Integer.parseInt(count2);
+        }
+
+        public int getCount2() {
+            return count2;
+        }
+    }
+
+    class MyAction {
+        private Long id;
+        private String name;
+        private Address address;
+
+        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;
+        }
+
+        public Address getAddress() {
+            return address;
+        }
+
+        public void setAddress(Address address) {
+            this.address = address;
+        }
+    }
+
+    class Address {
+        private String address;
+        private Country country;
+        private String city;
+
+        public String getAddress() {
+            return address;
+        }
+
+        public void setAddress(String address) {
+            this.address = address;
+        }
+
+        public String getCity() {
+            return city;
+        }
+
+        public void setCity(String city) {
+            this.city = city;
+        }
+
+        public Country getCountry() {
+            return country;
+        }
+
+        public void setCountry(Country country) {
+            this.country = country;
+        }
+    }
+
+    class Country {
+        private String iso;
+        private String name;
+        private String displayName;
+
+        public String getIso() {
+            return iso;
+        }
+
+        public void setIso(String iso) {
+            this.iso = iso;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getDisplayName() {
+            return displayName;
+        }
+
+        public void setDisplayName(String displayName) {
+            this.displayName = displayName;
+        }
+    }
+}