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    }