http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java new file mode 100644 index 0000000..612435d --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java @@ -0,0 +1,1069 @@ +/* + * 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.ognl; + +import com.opensymphony.xwork2.*; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor; +import com.opensymphony.xwork2.test.TestBean2; +import com.opensymphony.xwork2.util.*; +import com.opensymphony.xwork2.util.Foo; +import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import ognl.PropertyAccessor; + +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); + ognlUtil.setAllowStaticMethodAccess(Boolean.toString(allowStaticMethodAccess)); + 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 testValuesFromContextAreConverted() { + testValuesFromContextAreConverted("dogName"); + testValuesFromContextAreConverted("dog.name"); + } + + private void testValuesFromContextAreConverted(String propertyName) { + final OgnlValueStack vs = createValueStack(); + final String propertyValue = "Rover"; + vs.getContext().put(propertyName, new String[]{propertyValue}); + + assertEquals(propertyValue, vs.findValue(propertyName, String.class)); + } + + public void testNullValueFromContextGetsConverted() { + testNullValueFromContextGetsConverted("dogName"); + testNullValueFromContextGetsConverted("dog.name"); + } + + private void testNullValueFromContextGetsConverted(String propertyName) { + final OgnlValueStack vs = createValueStack(); + final String propertyValue = null; + vs.getContext().put(propertyName, propertyValue); + + assertEquals(propertyValue, vs.findValue(propertyName, 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("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class)); + } + + /** + * Allow access Enums without enabling access to static methods + */ + public void testEnum() throws Exception { + OgnlValueStack vs = createValueStack(); + + assertEquals("ONE", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[0]", String.class)); + assertEquals("TWO", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[1]", String.class)); + assertEquals("THREE", vs.findValue("@com.opensymphony.xwork2.ognl.MyNumbers@values()[2]", String.class)); + } + + public void testStaticMethodDisallow() { + OgnlValueStack vs = createValueStack(false); + + Dog dog = new Dog(); + dog.setDeity("fido"); + vs.push(dog); + assertNull(vs.findValue("@com.opensymphony.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 + 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("@com.opensymphony.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; + } + } +} + +enum MyNumbers { + ONE, TWO, THREE +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ognl/SecurityMemberAccessTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/SecurityMemberAccessTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/SecurityMemberAccessTest.java new file mode 100644 index 0000000..5db20fc --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/ognl/SecurityMemberAccessTest.java @@ -0,0 +1,366 @@ +package com.opensymphony.xwork2.ognl; + +import junit.framework.TestCase; + +import java.lang.reflect.Member; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +public class SecurityMemberAccessTest extends TestCase { + + private Map context; + private FooBar target; + + @Override + public void setUp() throws Exception { + context = new HashMap(); + target = new FooBar(); + } + + public void testWithoutClassExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "stringField"; + Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertTrue(accessible); + } + + public void testClassExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "stringField"; + Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)); + + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(FooBar.class); + sma.setExcludedClasses(excluded); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse(accessible); + } + + public void testObjectClassExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "toString"; + Member member = FooBar.class.getMethod(propertyName); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse("toString() from Object is accessible!!!", accessible); + } + + public void testObjectOverwrittenMethodsExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "hashCode"; + Member member = FooBar.class.getMethod(propertyName); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertTrue("hashCode() from FooBar isn't accessible!!!", accessible); + } + + public void testInterfaceInheritanceExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "barLogic"; + Member member = BarInterface.class.getMethod(propertyName); + + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(BarInterface.class); + sma.setExcludedClasses(excluded); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse("barLogic() from BarInterface is accessible!!!", accessible); + } + + public void testMiddleOfInheritanceExclusion1() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "fooLogic"; + Member member = FooBar.class.getMethod(propertyName); + + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(BarInterface.class); + sma.setExcludedClasses(excluded); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertTrue("fooLogic() from FooInterface isn't accessible!!!", accessible); + } + + public void testMiddleOfInheritanceExclusion2() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "barLogic"; + Member member = BarInterface.class.getMethod(propertyName); + + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(BarInterface.class); + sma.setExcludedClasses(excluded); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse("barLogic() from BarInterface is accessible!!!", accessible); + } + + public void testMiddleOfInheritanceExclusion3() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "barLogic"; + Member member = BarInterface.class.getMethod(propertyName); + +/* + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(BarInterface.class); + sma.setExcludedClasses(excluded); +*/ + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertTrue("barLogic() from BarInterface isn't accessible!!!", accessible); + } + + public void testMiddleOfInheritanceExclusion4() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "barLogic"; + Member member = BarInterface.class.getMethod(propertyName); + + Set<Class<?>> excluded = new HashSet<Class<?>>(); + excluded.add(FooBarInterface.class); + sma.setExcludedClasses(excluded); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse("barLogic() from BarInterface is accessible!!!", accessible); + } + + public void testPackageExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + Set<Pattern> excluded = new HashSet<Pattern>(); + excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*")); + sma.setExcludedPackageNamePatterns(excluded); + + String propertyName = "stringField"; + Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)); + + // when + boolean actual = sma.isAccessible(context, target, member, propertyName); + + // then + assertFalse("stringField is accessible!", actual); + } + + public void testDefaultPackageExclusion() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + Set<Pattern> excluded = new HashSet<Pattern>(); + excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*")); + sma.setExcludedPackageNamePatterns(excluded); + + // when + boolean actual = sma.isPackageExcluded(null, null); + + // then + assertFalse("default package is excluded!", actual); + } + + public void testDefaultPackageExclusion2() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + Set<Pattern> excluded = new HashSet<Pattern>(); + excluded.add(Pattern.compile("^$")); + sma.setExcludedPackageNamePatterns(excluded); + + // when + boolean actual = sma.isPackageExcluded(null, null); + + // then + assertTrue("default package isn't excluded!", actual); + } + + public void testAccessEnum() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + // when + Member values = MyValues.class.getMethod("values"); + boolean actual = sma.isAccessible(context, MyValues.class, values, null); + + // then + assertTrue("Access to enums is blocked!", actual); + } + + public void testAccessStatic() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(true); + sma.setExcludedClasses(new HashSet<Class<?>>(Arrays.<Class<?>>asList(Class.class))); + + // when + Member method = StaticTester.class.getMethod("sayHello"); + boolean actual = sma.isAccessible(context, Class.class, method, null); + + // then + assertTrue("Access to static is blocked!", actual); + } + + public void testBlockStaticAccess() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + sma.setExcludedClasses(new HashSet<Class<?>>(Arrays.<Class<?>>asList(Class.class))); + + // when + Member method = StaticTester.class.getMethod("sayHello"); + boolean actual = sma.isAccessible(context, Class.class, method, null); + + // then + assertFalse("Access to static isn't blocked!", actual); + } + + public void testBlockStaticAccessIfClassIsExcluded() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + sma.setExcludedClasses(new HashSet<Class<?>>(Arrays.<Class<?>>asList(Class.class))); + + // when + Member method = Class.class.getMethod("getClassLoader"); + boolean actual = sma.isAccessible(context, Class.class, method, null); + + // then + assertFalse("Access to static method of excluded class isn't blocked!", actual); + } + + public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + sma.setExcludedClasses(new HashSet<Class<?>>(Arrays.<Class<?>>asList(ClassLoader.class))); + + // when + Member method = Class.class.getMethod("getClassLoader"); + boolean actual = sma.isAccessible(context, Class.class, method, null); + + // then + assertTrue("Invalid test! Access to static method of excluded class is blocked!", actual); + } + + public void testAccessPrimitiveInt() throws Exception { + // given + SecurityMemberAccess sma = new SecurityMemberAccess(false); + + String propertyName = "intField"; + Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)); + + // when + boolean accessible = sma.isAccessible(context, target, member, propertyName); + + // then + assertTrue(accessible); + } + +} + +class FooBar implements FooBarInterface { + + private String stringField; + + private int intField; + + public String getStringField() { + return stringField; + } + + public void setStringField(String stringField) { + this.stringField = stringField; + } + + public String fooLogic() { + return "fooLogic"; + } + + public String barLogic() { + return "barLogic"; + } + + @Override + public int hashCode() { + return 1; + } + + public int getIntField() { + return intField; + } + + public void setIntField(int intField) { + this.intField = intField; + } +} + +interface FooInterface { + + String fooLogic(); + +} + +interface BarInterface { + + String barLogic(); + +} + +interface FooBarInterface extends FooInterface, BarInterface { + +} + +enum MyValues { + ONE, TWO, THREE +} + +class StaticTester { + + public static String sayHello() { + return "Hello"; + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/ognl/SetPropertiesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/SetPropertiesTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/SetPropertiesTest.java new file mode 100644 index 0000000..271a98d --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/ognl/SetPropertiesTest.java @@ -0,0 +1,334 @@ +/* + * 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 6/10/2003 + * + */ +package com.opensymphony.xwork2.ognl; + +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.XWorkTestCase; +import com.opensymphony.xwork2.config.ConfigurationException; +import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer; +import com.opensymphony.xwork2.conversion.impl.FooBarConverter; +import com.opensymphony.xwork2.conversion.impl.XWorkConverter; +import com.opensymphony.xwork2.inject.ContainerBuilder; +import com.opensymphony.xwork2.inject.Context; +import com.opensymphony.xwork2.inject.Factory; +import com.opensymphony.xwork2.inject.Scope; +import com.opensymphony.xwork2.mock.MockObjectTypeDeterminer; +import com.opensymphony.xwork2.test.StubConfigurationProvider; +import com.opensymphony.xwork2.util.Bar; +import com.opensymphony.xwork2.util.Cat; +import com.opensymphony.xwork2.util.Foo; +import com.opensymphony.xwork2.util.ValueStack; +import com.opensymphony.xwork2.util.location.LocatableProperties; +import com.opensymphony.xwork2.util.reflection.ReflectionContextState; +import ognl.Ognl; + +import java.util.*; + + +/** + * @author CameronBraid and Gabe + * @author tm_jee + */ +public class SetPropertiesTest extends XWorkTestCase { + + private OgnlUtil ognlUtil; + + @Override + public void setUp() throws Exception { + super.setUp(); + ognlUtil = container.getInstance(OgnlUtil.class); + ((OgnlValueStack)ActionContext.getContext().getValueStack()).setDevMode("true"); + } + public void testOgnlUtilEmptyStringAsLong() { + Bar bar = new Bar(); + Map context = Ognl.createDefaultContext(bar); + context.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + bar.setId(null); + + HashMap props = new HashMap(); + props.put("id", ""); + + ognlUtil.setProperties(props, bar, context); + assertNull(bar.getId()); + assertEquals(0, bar.getFieldErrors().size()); + + props.put("id", new String[]{""}); + + bar.setId(null); + ognlUtil.setProperties(props, bar, context); + assertNull(bar.getId()); + assertEquals(0, bar.getFieldErrors().size()); + } + + public void testSetCollectionByConverterFromArray() { + Foo foo = new Foo(); + ValueStack vs = ActionContext.getContext().getValueStack(); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + + XWorkConverter c = (XWorkConverter)((OgnlTypeConverterWrapper) Ognl.getTypeConverter(vs.getContext())).getTarget(); + c.registerConverter(Cat.class.getName(), new FooBarConverter()); + vs.push(foo); + + vs.setValue("cats", new String[]{"1", "2"}); + assertNotNull(foo.getCats()); + assertEquals(2, foo.getCats().size()); + assertEquals(Cat.class, foo.getCats().get(0).getClass()); + assertEquals(Cat.class, foo.getCats().get(1).getClass()); + } + + public void testSetCollectionByConverterFromCollection() { + Foo foo = new Foo(); + ValueStack vs = ActionContext.getContext().getValueStack(); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + + XWorkConverter c = (XWorkConverter)((OgnlTypeConverterWrapper) Ognl.getTypeConverter(vs.getContext())).getTarget(); + c.registerConverter(Cat.class.getName(), new FooBarConverter()); + vs.push(foo); + + HashSet s = new HashSet(); + s.add("1"); + s.add("2"); + vs.setValue("cats", s); + assertNotNull(foo.getCats()); + assertEquals(2, foo.getCats().size()); + assertEquals(Cat.class, foo.getCats().get(0).getClass()); + assertEquals(Cat.class, foo.getCats().get(1).getClass()); + } + + public void testValueStackSetValueEmptyStringAsLong() { + Bar bar = new Bar(); + ValueStack vs = ActionContext.getContext().getValueStack(); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + vs.push(bar); + + vs.setValue("id", ""); + assertNull(bar.getId()); + assertEquals(0, bar.getFieldErrors().size()); + + bar.setId(null); + + vs.setValue("id", new String[]{""}); + assertNull(bar.getId()); + assertEquals(0, bar.getFieldErrors().size()); + } + public void testAddingToListsWithObjectsTrue() { + doTestAddingToListsWithObjects(true); + } + public void testAddingToListsWithObjectsFalse() { + doTestAddingToListsWithObjects(false); + + } + public void doTestAddingToListsWithObjects(final boolean allowAdditions) { + + loadConfigurationProviders(new StubConfigurationProvider() { + @Override + public void register(ContainerBuilder builder, + LocatableProperties props) throws ConfigurationException { + builder.factory(ObjectTypeDeterminer.class, new Factory() { + public Object create(Context context) throws Exception { + return new MockObjectTypeDeterminer(null,Cat.class,null,allowAdditions); + } + + }); + } + }); + + Foo foo = new Foo(); + foo.setMoreCats(new ArrayList()); + String spielname = "Spielen"; + ValueStack vs = ActionContext.getContext().getValueStack(); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE); + vs.push(foo); + try { + vs.setValue("moreCats[2].name", spielname); + } catch (IndexOutOfBoundsException e) { + if (allowAdditions) { + throw e; + } + } + Object setCat = null; + if (allowAdditions) { + setCat = foo.getMoreCats().get(2); + + + assertNotNull(setCat); + assertTrue(setCat instanceof Cat); + assertTrue(((Cat) setCat).getName().equals(spielname)); + } else { + assertTrue(foo.getMoreCats()==null || foo.getMoreCats().size()==0); + } + + //now try to set a lower number + //to test setting after a higher one + //has been created + if (allowAdditions) { + spielname = "paws"; + vs.setValue("moreCats[0].name", spielname); + setCat = foo.getMoreCats().get(0); + assertNotNull(setCat); + assertTrue(setCat instanceof Cat); + assertTrue(((Cat) setCat).getName().equals(spielname)); + } + + } + + + public void testAddingToMapsWithObjectsTrue() throws Exception { + doTestAddingToMapsWithObjects(true); + } + + public void testAddingToMapsWithObjectsFalse() throws Exception { + doTestAddingToMapsWithObjects(false); + + } + + public void doTestAddingToMapsWithObjects(boolean allowAdditions) throws Exception { + + loadButAdd(ObjectTypeDeterminer.class, new MockObjectTypeDeterminer(Long.class,Cat.class,null,allowAdditions)); + + Foo foo = new Foo(); + foo.setAnotherCatMap(new HashMap()); + String spielname = "Spielen"; + ValueStack vs = ActionContext.getContext().getValueStack(); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + vs.getContext().put(ReflectionContextState.CREATE_NULL_OBJECTS, Boolean.TRUE); + vs.push(foo); + vs.getContext().put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE); + vs.setValue("anotherCatMap[\"3\"].name", spielname); + Object setCat = foo.getAnotherCatMap().get(new Long(3)); + if (allowAdditions) { + assertNotNull(setCat); + assertTrue(setCat instanceof Cat); + assertTrue(((Cat) setCat).getName().equals(spielname)); + } else { + assertNull(setCat); + } + + + } + + + public void testAddingAndModifyingCollectionWithObjectsSet() { + doTestAddingAndModifyingCollectionWithObjects(new HashSet()); + } + public void testAddingAndModifyingCollectionWithObjectsList() { + doTestAddingAndModifyingCollectionWithObjects(new ArrayList()); + + } + public void doTestAddingAndModifyingCollectionWithObjects(Collection barColl) { + + ValueStack vs = ActionContext.getContext().getValueStack(); + Foo foo = new Foo(); + + foo.setBarCollection(barColl); + Bar bar1 = new Bar(); + bar1.setId(new Long(11)); + barColl.add(bar1); + Bar bar2 = new Bar(); + bar2.setId(new Long(22)); + barColl.add(bar2); + //try modifying bar1 and bar2 + //check the logs here to make sure + //the Map is being created + ReflectionContextState.setCreatingNullObjects(vs.getContext(), true); + ReflectionContextState.setReportingConversionErrors(vs.getContext(), true); + vs.push(foo); + String bar1Title = "The Phantom Menace"; + String bar2Title = "The Clone Wars"; + vs.setValue("barCollection(22).title", bar2Title); + vs.setValue("barCollection(11).title", bar1Title); + for (Object aBarColl : barColl) { + Bar next = (Bar) aBarColl; + if (next.getId().intValue() == 22) { + assertEquals(bar2Title, next.getTitle()); + } else { + assertEquals(bar1Title, next.getTitle()); + } + } + //now test adding to a collection + String bar3Title = "Revenge of the Sith"; + String bar4Title = "A New Hope"; + vs.setValue("barCollection.makeNew[4].title", bar4Title, true); + vs.setValue("barCollection.makeNew[0].title", bar3Title, true); + + assertEquals(4, barColl.size()); + + for (Object aBarColl : barColl) { + Bar next = (Bar) aBarColl; + if (next.getId() == null) { + assertNotNull(next.getTitle()); + assertTrue(next.getTitle().equals(bar4Title) + || next.getTitle().equals(bar3Title)); + } + } + + } + public void testAddingToCollectionBasedOnPermission() { + final MockObjectTypeDeterminer determiner = new MockObjectTypeDeterminer(Long.class,Bar.class,"id",true); + loadConfigurationProviders(new StubConfigurationProvider() { + @Override + public void register(ContainerBuilder builder, + LocatableProperties props) throws ConfigurationException { + builder.factory(ObjectTypeDeterminer.class, new Factory() { + public Object create(Context context) throws Exception { + return determiner; + } + + }, Scope.SINGLETON); + } + }); + + Collection barColl=new HashSet(); + + ValueStack vs = ActionContext.getContext().getValueStack(); + ReflectionContextState.setCreatingNullObjects(vs.getContext(), true); + ReflectionContextState.setReportingConversionErrors(vs.getContext(), true); + Foo foo = new Foo(); + + foo.setBarCollection(barColl); + + vs.push(foo); + + String bar1Title="title"; + vs.setValue("barCollection(11).title", bar1Title); + + assertEquals(1, barColl.size()); + Object bar=barColl.iterator().next(); + assertTrue(bar instanceof Bar); + assertEquals(((Bar)bar).getTitle(), bar1Title); + assertEquals(((Bar)bar).getId(), new Long(11)); + + //now test where there is no permission + determiner.setShouldCreateIfNew(false); + + String bar2Title="another title"; + vs.setValue("barCollection(22).title", bar1Title); + + assertEquals(1, barColl.size()); + bar=barColl.iterator().next(); + assertTrue(bar instanceof Bar); + assertEquals(((Bar)bar).getTitle(), bar1Title); + assertEquals(((Bar)bar).getId(), new Long(11)); + + + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/security/DefaultAcceptedPatternsCheckerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/security/DefaultAcceptedPatternsCheckerTest.java b/core/src/test/java/com/opensymphony/xwork2/security/DefaultAcceptedPatternsCheckerTest.java new file mode 100644 index 0000000..e956d1a --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/security/DefaultAcceptedPatternsCheckerTest.java @@ -0,0 +1,67 @@ +package com.opensymphony.xwork2.security; + +import com.opensymphony.xwork2.XWorkTestCase; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultAcceptedPatternsCheckerTest extends XWorkTestCase { + + public void testHardcodedAcceptedPatterns() throws Exception { + // given + List<String> params = new ArrayList<String>() { + { + add("%{#application['test']}"); + add("%{#application.test}"); + add("%{#Application['test']}"); + add("%{#Application.test}"); + add("%{#session['test']}"); + add("%{#session.test}"); + add("%{#Session['test']}"); + add("%{#Session.test}"); + add("%{#struts['test']}"); + add("%{#struts.test}"); + add("%{#Struts['test']}"); + add("%{#Struts.test}"); + add("%{#request['test']}"); + add("%{#request.test}"); + add("%{#Request['test']}"); + add("%{#Request.test}"); + add("%{#servletRequest['test']}"); + add("%{#servletRequest.test}"); + add("%{#ServletRequest['test']}"); + add("%{#ServletRequest.test}"); + add("%{#servletResponse['test']}"); + add("%{#servletResponse.test}"); + add("%{#ServletResponse['test']}"); + add("%{#ServletResponse.test}"); + add("%{#parameters['test']}"); + add("%{#parameters.test}"); + add("%{#Parameters['test']}"); + add("%{#Parameters.test}"); + } + }; + + AcceptedPatternsChecker checker = new DefaultAcceptedPatternsChecker(); + + for (String param : params) { + // when + AcceptedPatternsChecker.IsAccepted actual = checker.isAccepted(param); + + // then + assertFalse("Access to " + param + " is possible!", actual.isAccepted()); + } + } + + public void testUnderscoreInParamName() throws Exception { + // given + AcceptedPatternsChecker checker = new DefaultAcceptedPatternsChecker(); + + // when + AcceptedPatternsChecker.IsAccepted actual = checker.isAccepted("mapParam['param_1']"); + + // then + assertTrue("Param with underscore wasn't accepted!", actual.isAccepted()); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java b/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java new file mode 100644 index 0000000..367e199 --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/security/DefaultExcludedPatternsCheckerTest.java @@ -0,0 +1,106 @@ +package com.opensymphony.xwork2.security; + +import com.opensymphony.xwork2.XWorkTestCase; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase { + + public void testHardcodedPatterns() throws Exception { + // given + List<String> params = new ArrayList<String>() { + { + add("%{#application['test']}"); + add("%{#application.test}"); + add("%{#Application['test']}"); + add("%{#Application.test}"); + add("%{#session['test']}"); + add("%{#session.test}"); + add("%{#Session['test']}"); + add("%{#Session.test}"); + add("%{#struts['test']}"); + add("%{#struts.test}"); + add("%{#Struts['test']}"); + add("%{#Struts.test}"); + add("%{#request['test']}"); + add("%{#request.test}"); + add("%{#Request['test']}"); + add("%{#Request.test}"); + add("%{#servletRequest['test']}"); + add("%{#servletRequest.test}"); + add("%{#ServletRequest['test']}"); + add("%{#ServletRequest.test}"); + add("%{#servletResponse['test']}"); + add("%{#servletResponse.test}"); + add("%{#ServletResponse['test']}"); + add("%{#ServletResponse.test}"); + add("%{#parameters['test']}"); + add("%{#parameters.test}"); + add("%{#Parameters['test']}"); + add("%{#Parameters.test}"); + add("#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse')"); + add("%{#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse')}"); + add("#_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true)"); + add("%{#_memberAccess[\"allowStaticMethodAccess\"]= new java.lang.Boolean(true)}"); + add("form.class.classLoader"); + add("form[\"class\"][\"classLoader\"]"); + add("form['class']['classLoader']"); + add("class['classLoader']"); + add("class[\"classLoader\"]"); + add("class.classLoader.resources.dirContext.docBase=tttt"); + add("Class.classLoader.resources.dirContext.docBase=tttt"); + } + }; + + DefaultExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker(); + checker.setAdditionalExcludePatterns(".*(^|\\.|\\[|'|\")class(\\.|\\[|'|\").*"); + + for (String param : params) { + // when + ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(param); + + // then + assertTrue("Access to " + param + " is possible!", actual.isExcluded()); + } + } + + public void testParamWithClassInName() throws Exception { + // given + List<String> properParams = new ArrayList<>(); + properParams.add("eventClass"); + properParams.add("form.eventClass"); + properParams.add("form[\"eventClass\"]"); + properParams.add("form['eventClass']"); + properParams.add("[email protected]"); + properParams.add("[email protected]"); + + ExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker(); + + for (String properParam : properParams) { + // when + ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(properParam); + + // then + assertFalse("Param '" + properParam + "' is excluded!", actual.isExcluded()); + } + } + + public void testStrutsTokenIsExcluded() throws Exception { + // given + List<String> tokens = new ArrayList<>(); + tokens.add("struts.token.name"); + tokens.add("struts.token"); + + ExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker(); + + for (String token : tokens) { + // when + ExcludedPatternsChecker.IsExcluded actual = checker.isExcluded(token); + + // then + assertTrue("Param '" + token + "' is not excluded!", actual.isExcluded()); + } + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java b/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java new file mode 100644 index 0000000..f6cbecd --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/spring/ActionsFromSpringTest.java @@ -0,0 +1,80 @@ +/* + * Created on Jun 12, 2004 + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.*; +import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider; +import org.springframework.context.ApplicationContext; + +/** + * Test loading actions from the Spring Application Context. + * + * @author Simon Stewart + */ +public class ActionsFromSpringTest extends XWorkTestCase { + private ApplicationContext appContext; + + @Override public void setUp() throws Exception { + super.setUp(); + + // Set up XWork + XmlConfigurationProvider provider = new XmlConfigurationProvider("com/opensymphony/xwork2/spring/actionContext-xwork.xml"); + container.inject(provider); + loadConfigurationProviders(provider); + appContext = ((SpringObjectFactory)container.getInstance(ObjectFactory.class)).appContext; + } + + public void testLoadSimpleAction() throws Exception { + ActionProxy proxy = actionProxyFactory.createActionProxy(null, "simpleAction", null); + Object action = proxy.getAction(); + + Action expected = (Action) appContext.getBean("simple-action"); + + assertEquals(expected.getClass(), action.getClass()); + } + + public void testLoadActionWithDependencies() throws Exception { + ActionProxy proxy = actionProxyFactory.createActionProxy(null, "dependencyAction", null); + SimpleAction action = (SimpleAction) proxy.getAction(); + + assertEquals("injected", action.getBlah()); + } + + public void testProxiedActionIsNotStateful() throws Exception { + ActionProxy proxy = actionProxyFactory.createActionProxy(null, "proxiedAction", null); + SimpleAction action = (SimpleAction) proxy.getAction(); + + action.setBlah("Hello World"); + + proxy = actionProxyFactory.createActionProxy(null, "proxiedAction", null); + action = (SimpleAction) proxy.getAction(); + + // If the action is a singleton, this test will fail + SimpleAction sa = new SimpleAction(); + assertEquals(sa.getBlah(), action.getBlah()); + + // And if the advice is not being applied, this will be SUCCESS. + String result = action.execute(); + assertEquals(Action.INPUT, result); + } + + public void testAutoProxiedAction() throws Exception { + ActionProxy proxy = actionProxyFactory.createActionProxy(null, "autoProxiedAction", null); + + SimpleAction action = (SimpleAction) proxy.getAction(); + + String result = action.execute(); + assertEquals(Action.INPUT, result); + } + + public void testActionWithSpringResult() throws Exception { + ActionProxy proxy = actionProxyFactory.createActionProxy(null, "simpleActionSpringResult", null); + + proxy.execute(); + + SpringResult springResult = (SpringResult) proxy.getInvocation().getResult(); + assertTrue(springResult.isInitialize()); + assertNotNull(springResult.getStringParameter()); + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/spring/Bar.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/Bar.java b/core/src/test/java/com/opensymphony/xwork2/spring/Bar.java new file mode 100644 index 0000000..9328550 --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/spring/Bar.java @@ -0,0 +1,56 @@ +/* + * Created on Nov 12, 2003 + */ +package com.opensymphony.xwork2.spring; + +/** + * @author Mike + */ +public class Bar { + + private Foo foo; + private String thing; + private int value; + + /** + * @return Returns the foo. + */ + public Foo getFoo() { + return foo; + } + + /** + * @param foo The foo to set. + */ + public void setFoo(Foo foo) { + this.foo = foo; + } + + /** + * @return Returns the thing. + */ + public String getThing() { + return thing; + } + + /** + * @param thing The thing to set. + */ + public void setThing(String thing) { + this.thing = thing; + } + + /** + * @return Returns the value. + */ + public int getValue() { + return value; + } + + /** + * @param value The value to set. + */ + public void setValue(int value) { + this.value = value; + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/spring/ExecuteInterceptor.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/ExecuteInterceptor.java b/core/src/test/java/com/opensymphony/xwork2/spring/ExecuteInterceptor.java new file mode 100644 index 0000000..6f618a3 --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/spring/ExecuteInterceptor.java @@ -0,0 +1,21 @@ +/* + * Created on Jun 12, 2004 + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.Action; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + + +/** + * @author Simon Stewart + */ +public class ExecuteInterceptor implements MethodInterceptor { + public Object invoke(MethodInvocation mi) throws Throwable { + if ("execute".equals(mi.getMethod().getName())) + return Action.INPUT; + return mi.proceed(); + } + +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/spring/ExternalReferenceAction.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/ExternalReferenceAction.java b/core/src/test/java/com/opensymphony/xwork2/spring/ExternalReferenceAction.java new file mode 100644 index 0000000..c5068cd --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/spring/ExternalReferenceAction.java @@ -0,0 +1,49 @@ +/* + * Created on Nov 11, 2003 + */ +package com.opensymphony.xwork2.spring; + +import com.opensymphony.xwork2.Action; + +/** + * @author Mike + */ +public class ExternalReferenceAction implements Action +{ + private Foo foo; + private Bar bar; + + public String execute() throws Exception { + return SUCCESS; + } + + /** + * @return Returns the foo. + */ + public Foo getFoo() { + return foo; + } + + /** + * @param foo + * The foo to set. + */ + public void setFoo(Foo foo) { + this.foo = foo; + } + + /** + * @return Returns the bar. + */ + public Bar getBar() { + return bar; + } + + /** + * @param bar + * The bar to set. + */ + public void setBar(Bar bar) { + this.bar = bar; + } +} http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/test/java/com/opensymphony/xwork2/spring/Foo.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/spring/Foo.java b/core/src/test/java/com/opensymphony/xwork2/spring/Foo.java new file mode 100644 index 0000000..87502c7 --- /dev/null +++ b/core/src/test/java/com/opensymphony/xwork2/spring/Foo.java @@ -0,0 +1,30 @@ +/* + * Created on Nov 11, 2003 + */ +package com.opensymphony.xwork2.spring; + +/** + * @author Mike + */ +public class Foo +{ + String name = null; + + public Foo() { + name = "not set"; + } + + public Foo(String name) { + this.name = name; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } +}
