001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.binding; 016 017 import ognl.Node; 018 import ognl.enhance.ExpressionAccessor; 019 import org.apache.hivemind.Location; 020 import org.apache.tapestry.BindingException; 021 import org.apache.tapestry.IComponent; 022 import org.apache.tapestry.coerce.ValueConverter; 023 import org.apache.tapestry.services.ExpressionCache; 024 import org.apache.tapestry.services.ExpressionEvaluator; 025 import static org.easymock.EasyMock.expect; 026 import static org.easymock.EasyMock.expectLastCall; 027 import org.testng.annotations.Test; 028 029 /** 030 * Tests for {@link org.apache.tapestry.binding.ExpressionBinding}. 031 * 032 * @author Howard M. Lewis Ship 033 * @since 4.0 034 */ 035 @Test 036 public class TestExpressionBinding extends BindingTestCase 037 { 038 039 public void test_Invariant() 040 { 041 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 042 ExpressionCache ec = newMock(ExpressionCache.class); 043 IComponent component = newMock(IComponent.class); 044 Location l = fabricateLocation(1); 045 046 Node compiled = newMock(Node.class); 047 //ExpressionAccessor accessor = newMock(ExpressionAccessor.class); 048 049 Object expressionValue = "EXPRESSION-VALUE"; 050 051 ValueConverter vc = newValueConverter(); 052 053 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 054 055 expect(compiled.getAccessor()).andReturn(null); 056 057 expect(ev.isConstant("exp")).andReturn(true); 058 059 expect(ec.getCompiledExpression(component, "exp")).andReturn(compiled); 060 061 expect(ev.readCompiled(component, compiled)).andReturn(expressionValue); 062 063 expect(component.getExtendedId()).andReturn("Foo/bar"); 064 065 replay(); 066 067 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, "exp", ev, ec); 068 069 assertEquals(true, b.isInvariant()); 070 071 // A second time, to test the 'already initialized' 072 // code path. 073 074 assertEquals(true, b.isInvariant()); 075 076 // Get the object, which should be cached. 077 078 assertSame(expressionValue, b.getObject()); 079 080 assertSame(component, b.getComponent()); 081 082 assertEquals(b.toString(), "ExpressionBinding[Foo/bar exp]"); 083 084 verify(); 085 } 086 087 public void test_Variant() 088 { 089 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 090 ExpressionCache ec = newMock(ExpressionCache.class); 091 Location l = fabricateLocation(1); 092 093 IComponent component = newComponent(); 094 Node compiled = newMock(Node.class); 095 ExpressionAccessor accessor = newMock(ExpressionAccessor.class); 096 097 Object expressionValue1 = new Object(); 098 Object expressionValue2 = new Object(); 099 100 ValueConverter vc = newValueConverter(); 101 102 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 103 104 expect(ev.isConstant("exp")).andReturn(false); 105 106 expect(ec.getCompiledExpression(component, "exp")).andReturn(compiled); 107 108 expect(compiled.getAccessor()).andReturn(accessor); 109 110 expect(ev.read(component, accessor)).andReturn(expressionValue1); 111 expect(ev.read(component, accessor)).andReturn(expressionValue2); 112 113 replay(); 114 115 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, 116 "exp", ev, ec); 117 118 assertEquals(false, b.isInvariant()); 119 120 // Check that the expression is re-evaluated on 121 // each call to getObject(). 122 123 assertSame(expressionValue1, b.getObject()); 124 assertSame(expressionValue2, b.getObject()); 125 126 verify(); 127 } 128 129 public void test_Set_Object() 130 { 131 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 132 ExpressionCache ec = newMock(ExpressionCache.class); 133 Location l = fabricateLocation(1); 134 135 IComponent component = newComponent(); 136 Node compiled = newMock(Node.class); 137 ValueConverter vc = newValueConverter(); 138 139 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 140 141 expect(ev.isConstant("exp")).andReturn(false); 142 143 Object newValue = new Object(); 144 145 ev.writeCompiled(component, compiled, newValue); 146 147 expect(ec.getCompiledExpression(component, "exp")).andReturn(compiled); 148 expect(compiled.getAccessor()).andReturn(null); 149 150 replay(); 151 152 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, 153 "exp", ev, ec); 154 155 b.setObject(newValue); 156 157 verify(); 158 } 159 160 public void test_Set_Object_Invariant() 161 { 162 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 163 ExpressionCache ec = newMock(ExpressionCache.class); 164 Location l = fabricateLocation(1); 165 166 IComponent component = newComponent(); 167 Node compiled = newMock(Node.class); 168 169 ValueConverter vc = newValueConverter(); 170 171 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 172 expect(ev.isConstant("exp")).andReturn(true); 173 174 expect(component.getExtendedId()).andReturn("Foo/bar.baz"); 175 176 replay(); 177 178 ExpressionBinding b = new ExpressionBinding("parameter foo", l, vc, component, 179 "exp", ev, ec); 180 181 try 182 { 183 b.setObject(new Object()); 184 unreachable(); 185 } 186 catch (BindingException ex) 187 { 188 assertEquals("Binding with value exp (ExpressionBinding[Foo/bar.baz exp]) may not be updated.", 189 ex.getMessage()); 190 } 191 192 verify(); 193 } 194 195 public void test_Set_Object_Failure() 196 { 197 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 198 ExpressionCache ec = newMock(ExpressionCache.class); 199 Location l = fabricateLocation(1); 200 201 IComponent component = newComponent(); 202 Node compiled = newMock(Node.class); 203 204 ValueConverter vc = newValueConverter(); 205 206 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 207 208 expect(ev.isConstant("exp")).andReturn(false); 209 210 Object newValue = new Object(); 211 212 RuntimeException innerException = new RuntimeException("Failure"); 213 214 ev.writeCompiled(component, compiled, newValue); 215 expectLastCall().andThrow(innerException); 216 217 replay(); 218 219 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, 220 "exp", ev, ec); 221 222 try 223 { 224 b.setObject(newValue); 225 unreachable(); 226 } 227 catch (BindingException ex) 228 { 229 assertEquals(ex.getMessage(), "Failure"); 230 assertSame(innerException, ex.getRootCause()); 231 } 232 233 verify(); 234 } 235 236 public void test_Compile_Expression_Failure() 237 { 238 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 239 ExpressionCache ec = newMock(ExpressionCache.class); 240 Location l = fabricateLocation(1); 241 242 IComponent component = newComponent(); 243 ValueConverter vc = newValueConverter(); 244 245 Throwable innerException = new RuntimeException("Failure"); 246 247 expect(ec.getCompiledExpression("exp")).andThrow(innerException); 248 249 replay(); 250 251 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, 252 "exp", ev, ec); 253 254 try 255 { 256 b.isInvariant(); 257 unreachable(); 258 } 259 catch (BindingException ex) 260 { 261 assertEquals("Failure", ex.getMessage()); 262 assertSame(innerException, ex.getRootCause()); 263 } 264 265 verify(); 266 } 267 268 public void test_Resolve_Expression_Failure() 269 { 270 ExpressionEvaluator ev = newMock(ExpressionEvaluator.class); 271 ExpressionCache ec = newMock(ExpressionCache.class); 272 Location l = fabricateLocation(1); 273 274 IComponent component = newComponent(); 275 Node compiled = newMock(Node.class); 276 ValueConverter vc = newValueConverter(); 277 278 expect(ec.getCompiledExpression("exp")).andReturn(compiled); 279 280 expect(ev.isConstant("exp")).andReturn(false); 281 282 Throwable innerException = new RuntimeException("Failure"); 283 284 ec.getCompiledExpression(component, "exp"); 285 expectLastCall().andThrow(innerException); 286 287 replay(); 288 289 ExpressionBinding b = new ExpressionBinding("param", l, vc, component, 290 "exp", ev, ec); 291 292 try 293 { 294 b.getObject(); 295 unreachable(); 296 } 297 catch (BindingException ex) 298 { 299 assertEquals(ex.getMessage(), "Failure"); 300 assertSame(innerException, ex.getRootCause()); 301 } 302 303 verify(); 304 } 305 }