1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.velocity.introspection

File ChainingUberspectorTest.java

 

Code metrics

0
95
12
1
293
216
12
0.13
7.92
12
1

Classes

Class Line # Actions
ChainingUberspectorTest 54 95 0% 12 0
1.0100%
 

Contributing tests

This file is covered by 8 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.velocity.introspection;
21   
22    import java.io.StringReader;
23    import java.io.StringWriter;
24    import java.util.Date;
25    import java.util.Properties;
26   
27    import org.apache.velocity.VelocityContext;
28    import org.apache.velocity.runtime.RuntimeConstants;
29    import org.apache.velocity.util.introspection.UberspectImpl;
30    import org.jmock.Expectations;
31    import org.jmock.States;
32    import org.junit.Assert;
33    import org.junit.Before;
34    import org.junit.Rule;
35    import org.junit.Test;
36    import org.slf4j.Logger;
37    import org.xwiki.component.util.ReflectionUtils;
38    import org.xwiki.test.ComponentManagerRule;
39    import org.xwiki.test.annotation.ComponentList;
40    import org.xwiki.test.jmock.JMockRule;
41    import org.xwiki.velocity.VelocityEngine;
42    import org.xwiki.velocity.internal.DefaultVelocityConfiguration;
43    import org.xwiki.velocity.internal.DefaultVelocityContextFactory;
44    import org.xwiki.velocity.internal.DefaultVelocityEngine;
45   
46    /**
47    * Unit tests for {@link ChainingUberspector}.
48    */
49    @ComponentList({
50    DefaultVelocityEngine.class,
51    DefaultVelocityConfiguration.class,
52    DefaultVelocityContextFactory.class
53    })
 
54    public class ChainingUberspectorTest
55    {
56    @Rule
57    public final ComponentManagerRule componentManager = new ComponentManagerRule();
58   
59    @Rule
60    public final JMockRule mockery = new JMockRule();
61   
62    private VelocityEngine engine;
63   
64    private Logger mockLogger;
65   
66    private States loggingVerification = this.mockery.states("loggingVerification");
67   
 
68  8 toggle @Before
69    public void setUp() throws Exception
70    {
71    // Register in-memory configuration sources for the test.
72  8 this.componentManager.registerMemoryConfigurationSource();
73   
74  8 this.engine = this.componentManager.getInstance(VelocityEngine.class);
75   
76  8 this.mockLogger = this.mockery.mock(Logger.class);
77  8 this.mockery.checking(new Expectations()
78    {
 
79  8 toggle {
80  8 ignoring(ChainingUberspectorTest.this.mockLogger);
81  8 when(ChainingUberspectorTest.this.loggingVerification.isNot("on"));
82    }
83    });
84   
85  8 ReflectionUtils.setFieldValue(this.engine, "logger", this.mockLogger);
86    }
87   
88    /*
89    * Tests that the uberspectors in the chain are called, and without a real uberspector no methods are found.
90    */
 
91  1 toggle @Test
92    public void testEmptyChain() throws Exception
93    {
94  1 Properties prop = new Properties();
95  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
96    .getCanonicalName());
97  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, TestingUberspector.class
98    .getCanonicalName());
99  1 TestingUberspector.methodCalls = 0;
100  1 this.engine.initialize(prop);
101  1 StringWriter writer = new StringWriter();
102  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
103    new StringReader("#set($foo = 'hello')#set($bar = $foo.toString())$bar"));
104  1 Assert.assertEquals("$bar", writer.toString());
105  1 Assert.assertEquals(1, TestingUberspector.methodCalls);
106    }
107   
108    /*
109    * Tests that using several uberspectors in the chain works, and methods are correctly found by the last uberspector
110    * in the chain.
111    */
 
112  1 toggle @Test
113    public void testBasicChaining() throws Exception
114    {
115  1 Properties prop = new Properties();
116  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
117    .getCanonicalName());
118  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, UberspectImpl.class
119    .getCanonicalName()
120    + "," + TestingUberspector.class.getCanonicalName());
121  1 TestingUberspector.methodCalls = 0;
122  1 TestingUberspector.getterCalls = 0;
123  1 this.engine.initialize(prop);
124  1 StringWriter writer = new StringWriter();
125  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
126    new StringReader("#set($foo = 'hello')#set($bar = $foo.toString())$bar"));
127  1 Assert.assertEquals("hello", writer.toString());
128  1 Assert.assertEquals(1, TestingUberspector.methodCalls);
129  1 Assert.assertEquals(0, TestingUberspector.getterCalls);
130    }
131   
132    /*
133    * Tests that invalid uberspectors classnames are ignored.
134    */
 
135  1 toggle @Test
136    public void testInvalidUberspectorsAreIgnored() throws Exception
137    {
138  1 Properties prop = new Properties();
139  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
140    .getCanonicalName());
141  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, UberspectImpl.class
142    .getCanonicalName()
143    + ","
144    + AbstractChainableUberspector.class.getCanonicalName()
145    + ","
146    + InvalidUberspector.class.getCanonicalName()
147    + ","
148    + TestingUberspector.class.getCanonicalName() + "," + Date.class.getCanonicalName());
149  1 TestingUberspector.methodCalls = 0;
150  1 InvalidUberspector.methodCalls = 0;
151  1 this.engine.initialize(prop);
152  1 StringWriter writer = new StringWriter();
153  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
154    new StringReader("#set($foo = 'hello')#set($bar = $foo.toString())$bar"));
155  1 Assert.assertEquals("hello", writer.toString());
156  1 Assert.assertEquals(1, TestingUberspector.methodCalls);
157  1 Assert.assertEquals(0, InvalidUberspector.methodCalls);
158    }
159   
160    /*
161    * Tests that a non-chainable entry in the chain does not forward calls.
162    */
 
163  1 toggle @Test
164    public void testChainBreakingOnNonChainableEntry() throws Exception
165    {
166  1 Properties prop = new Properties();
167  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
168    .getCanonicalName());
169  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, TestingUberspector.class
170    .getCanonicalName()
171    + "," + UberspectImpl.class.getCanonicalName());
172  1 TestingUberspector.methodCalls = 0;
173  1 this.engine.initialize(prop);
174  1 StringWriter writer = new StringWriter();
175  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
176    new StringReader("#set($foo = 'hello')#set($bar = $foo.toString())$bar"));
177  1 Assert.assertEquals("hello", writer.toString());
178  1 Assert.assertEquals(0, TestingUberspector.methodCalls);
179    }
180   
181    /*
182    * Checks that the default (non-secure) uberspector works and allows calling restricted methods.
183    */
 
184  1 toggle @Test
185    public void testDefaultUberspectorWorks() throws Exception
186    {
187  1 Properties prop = new Properties();
188  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
189    .getCanonicalName());
190  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, UberspectImpl.class
191    .getCanonicalName());
192  1 this.engine.initialize(prop);
193  1 StringWriter writer = new StringWriter();
194  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
195    new StringReader("#set($foo = 'hello')"
196    + "#set($bar = $foo.getClass().getConstructors())$bar"));
197  1 Assert.assertTrue(writer.toString().startsWith("[Ljava.lang.reflect.Constructor"));
198    }
199   
200    /*
201    * Checks that the secure uberspector works and does not allow calling restricted methods.
202    */
 
203  1 toggle @Test
204    public void testSecureUberspectorWorks() throws Exception
205    {
206  1 Properties prop = new Properties();
207  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
208    .getCanonicalName());
209  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, SecureUberspector.class
210    .getCanonicalName());
211  1 this.engine.initialize(prop);
212  1 StringWriter writer = new StringWriter();
213   
214  1 this.loggingVerification.become("on");
215  1 this.mockery.checking(new Expectations()
 
216  1 toggle {{
217    // Get rid of debug log
218  1 allowing(mockLogger).isDebugEnabled();
219  1 returnValue(false);
220   
221    // Allow one warning for getConstructors since it's forbidden
222  1 oneOf(mockLogger).warn("Cannot retrieve method getConstructors from object of class java.lang.Class due to security restrictions.");
223    }});
224   
225  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
226    new StringReader("#set($foo = 'hello')"
227    + "#set($bar = $foo.getClass().getConstructors())$foo $foo.class.name $bar"));
228  1 Assert.assertEquals("hello java.lang.String $bar", writer.toString());
229    }
230   
231    /*
232    * Checks that when the chain property is not configured, by default the secure ubespector is used.
233    */
 
234  1 toggle @Test
235    public void testSecureUberspectorEnabledByDefault() throws Exception
236    {
237  1 Properties prop = new Properties();
238  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
239    .getCanonicalName());
240  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, "");
241  1 this.engine.initialize(prop);
242  1 StringWriter writer = new StringWriter();
243  1 this.engine.evaluate(new org.apache.velocity.VelocityContext(), writer, "mytemplate",
244    new StringReader("#set($foo = 'hello')"
245    + "#set($bar = $foo.getClass().getConstructors())$foo $foo.class.name $bar"));
246  1 Assert.assertEquals("hello java.lang.String $bar", writer.toString());
247    }
248   
249    /*
250    * Checks that the deprecated check uberspector works.
251    */
 
252  1 toggle @SuppressWarnings("deprecation")
253    @Test
254    public void testDeprecatedUberspector() throws Exception
255    {
256  1 Properties prop = new Properties();
257  1 prop.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, ChainingUberspector.class
258    .getCanonicalName());
259  1 prop.setProperty(ChainingUberspector.UBERSPECT_CHAIN_CLASSNAMES, UberspectImpl.class
260    .getCanonicalName()
261    + ","
262    + TestingUberspector.class.getCanonicalName()
263    + ","
264    + DeprecatedCheckUberspector.class.getCanonicalName());
265  1 TestingUberspector.methodCalls = 0;
266  1 TestingUberspector.getterCalls = 0;
267  1 this.engine.initialize(prop);
268  1 StringWriter writer = new StringWriter();
269  1 VelocityContext context = new org.apache.velocity.VelocityContext();
270  1 Date d = new Date();
271  1 context.put("date", d);
272  1 context.put("dobject", new DeprecatedObject());
273   
274  1 final String threadIdPrefix = Thread.currentThread().getId() + ":";
275   
276    // Define expectations on the Logger
277  1 this.loggingVerification.become("on");
278  1 this.mockery.checking(new Expectations()
 
279  1 toggle {{
280  1 oneOf(mockLogger).warn("Deprecated usage of method [java.util.Date.getYear] in " + threadIdPrefix + "mytemplate@1,19");
281  1 oneOf(mockLogger).warn("Deprecated usage of getter [java.util.Date.getMonth] in " + threadIdPrefix + "mytemplate@1,40");
282  1 oneOf(mockLogger).warn("Deprecated usage of method [org.xwiki.velocity.introspection.DeprecatedObject.foo] in " + threadIdPrefix + "mytemplate@1,55");
283  1 oneOf(mockLogger).warn("Deprecated usage of method [org.xwiki.velocity.introspection.DeprecatedObject.size] in " + threadIdPrefix + "mytemplate@1,70");
284    }});
285   
286  1 this.engine.evaluate(context, writer, "mytemplate",
287    new StringReader("#set($foo = $date.getYear())$foo $date.month $dobject.foo() $dobject.size()"));
288   
289  1 Assert.assertEquals(d.getYear() + " " + d.getMonth() + " foo 0", writer.toString());
290  1 Assert.assertEquals(3, TestingUberspector.methodCalls);
291  1 Assert.assertEquals(1, TestingUberspector.getterCalls);
292    }
293    }