View Javadoc

1   /* $Id: VariableExpansionTestCase.java 1212599 2011-12-09 19:46:42Z simonetripodi $
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one or more
4    * contributor license agreements.  See the NOTICE file distributed with
5    * this work for additional information regarding copyright ownership.
6    * The ASF licenses this file to You under the Apache License, Version 2.0
7    * (the "License"); you may not use this file except in compliance with
8    * the License.  You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.commons.digester3.substitution;
20  
21  import static org.junit.Assert.*;
22  
23  import java.io.IOException;
24  import java.io.StringReader;
25  import java.util.HashMap;
26  import java.util.LinkedList;
27  
28  import org.apache.commons.digester3.CallMethodRule;
29  import org.apache.commons.digester3.Digester;
30  import org.apache.commons.digester3.SimpleTestBean;
31  import org.apache.commons.digester3.substitution.MultiVariableExpander;
32  import org.apache.commons.digester3.substitution.VariableSubstitutor;
33  import org.junit.Test;
34  import org.xml.sax.SAXException;
35  
36  /**
37   * <p>
38   * Test Case for the variable expansion facility in Digester.
39   *
40   * @author Simon Kitching
41   */
42  public class VariableExpansionTestCase
43  {
44  
45      // --------------------------------------------------- Overall Test Methods
46  
47      // method used in tests4
48      private LinkedList<SimpleTestBean> simpleTestBeans = new LinkedList<SimpleTestBean>();
49  
50      public void addSimpleTestBean( SimpleTestBean bean )
51      {
52          simpleTestBeans.add( bean );
53      }
54  
55      // implementation of source shared by the variable expander and
56      // is updatable during digesting via an Ant-like property element
57      private HashMap<String, Object> mutableSource = new HashMap<String, Object>();
58  
59      /**
60       * Used in test case "testExpansionWithMutableSource", where the set of variables available to be substituted into
61       * the xml is updated as the xml is parsed.
62       */
63      public void addProperty( String key, String value )
64      {
65          mutableSource.put( key, value );
66      }
67  
68      /**
69       * Creates a Digester configured to show Ant-like capability.
70       *
71       * @return a Digester with rules and variable substitutor
72       */
73      private Digester createDigesterThatCanDoAnt()
74      {
75          Digester digester = new Digester();
76  
77          MultiVariableExpander expander = new MultiVariableExpander();
78          expander.addSource( "$", mutableSource );
79          digester.setSubstitutor( new VariableSubstitutor( expander ) );
80  
81          int useRootObj = -1;
82          Class<?>[] callerArgTypes = new Class[] { String.class, String.class };
83          CallMethodRule caller = new CallMethodRule( useRootObj, "addProperty", callerArgTypes.length, callerArgTypes );
84          digester.addRule( "root/property", caller );
85          digester.addCallParam( "root/property", 0, "name" );
86          digester.addCallParam( "root/property", 1, "value" );
87  
88          digester.addObjectCreate( "root/bean", SimpleTestBean.class );
89          digester.addSetProperties( "root/bean" );
90          digester.addSetNext( "root/bean", "addSimpleTestBean" );
91          return digester;
92      }
93  
94      // ------------------------------------------------ Individual Test Methods
95  
96      /**
97       * Test that by default no expansion occurs.
98       */
99      @Test
100     public void testNoExpansion()
101         throws SAXException, IOException
102     {
103 
104         String xml = "<root alpha='${attr1}' beta='var{attr2}'/>";
105         StringReader input = new StringReader( xml );
106         Digester digester = new Digester();
107 
108         // Configure the digester as required
109         digester.addObjectCreate( "root", SimpleTestBean.class );
110         digester.addSetProperties( "root" );
111 
112         // Parse our test input.
113         SimpleTestBean root = digester.parse( input );
114 
115         assertNotNull( "Digester returned no object", root );
116 
117         assertEquals( "${attr1}", root.getAlpha() );
118         assertEquals( "var{attr2}", root.getBeta() );
119     }
120 
121     /**
122      * Test that a MultiVariableExpander with no sources does no expansion.
123      */
124     @Test
125     public void testExpansionWithNoSource()
126         throws SAXException, IOException
127     {
128 
129         String xml = "<root alpha='${attr1}' beta='var{attr2}'/>";
130         StringReader input = new StringReader( xml );
131         Digester digester = new Digester();
132 
133         // Configure the digester as required
134         MultiVariableExpander expander = new MultiVariableExpander();
135         digester.setSubstitutor( new VariableSubstitutor( expander ) );
136         digester.addObjectCreate( "root", SimpleTestBean.class );
137         digester.addSetProperties( "root" );
138 
139         // Parse our test input.
140         SimpleTestBean root = digester.parse( input );
141 
142         assertNotNull( "Digester returned no object", root );
143 
144         assertEquals( "${attr1}", root.getAlpha() );
145         assertEquals( "var{attr2}", root.getBeta() );
146     }
147 
148     /**
149      * Test that a MultiVariableExpander with multiple sources works. It also tests that expansion works ok where
150      * multiple elements exist.
151      */
152     @Test
153     public void testExpansionWithMultipleSources()
154         throws SAXException, IOException
155     {
156 
157         String xml =
158             "<root>" + "<bean alpha='${attr1}' beta='var{attr1}'/>" + "<bean alpha='${attr2}' beta='var{attr2}'/>"
159                 + "</root>";
160 
161         StringReader input = new StringReader( xml );
162         Digester digester = new Digester();
163 
164         // Configure the digester as required
165         HashMap<String, Object> source1 = new HashMap<String, Object>();
166         source1.put( "attr1", "source1.attr1" );
167         source1.put( "attr2", "source1.attr2" ); // should not be used
168 
169         HashMap<String, Object> source2 = new HashMap<String, Object>();
170         source2.put( "attr1", "source2.attr1" ); // should not be used
171         source2.put( "attr2", "source2.attr2" );
172 
173         MultiVariableExpander expander = new MultiVariableExpander();
174         expander.addSource( "$", source1 );
175         expander.addSource( "var", source2 );
176 
177         digester.setSubstitutor( new VariableSubstitutor( expander ) );
178         digester.addObjectCreate( "root/bean", SimpleTestBean.class );
179         digester.addSetProperties( "root/bean" );
180         digester.addSetNext( "root/bean", "addSimpleTestBean" );
181 
182         // Parse our test input.
183         this.simpleTestBeans.clear();
184         digester.push( this );
185         digester.parse( input );
186 
187         assertEquals( 2, this.simpleTestBeans.size() );
188 
189         {
190             SimpleTestBean bean = this.simpleTestBeans.get( 0 );
191             assertEquals( "source1.attr1", bean.getAlpha() );
192             assertEquals( "source2.attr1", bean.getBeta() );
193         }
194 
195         {
196             SimpleTestBean bean = this.simpleTestBeans.get( 1 );
197             assertEquals( "source1.attr2", bean.getAlpha() );
198             assertEquals( "source2.attr2", bean.getBeta() );
199         }
200     }
201 
202     /**
203      * Test expansion of text in element bodies.
204      */
205     @Test
206     public void testBodyExpansion()
207         throws SAXException, IOException
208     {
209 
210         String xml = "<root>" + "Twas noun{1} and the noun{2}" + " did verb{1} and verb{2} in the noun{3}" + "</root>";
211 
212         StringReader input = new StringReader( xml );
213         Digester digester = new Digester();
214 
215         // Configure the digester as required
216         HashMap<String, Object> nouns = new HashMap<String, Object>();
217         nouns.put( "1", "brillig" );
218         nouns.put( "2", "slithy toves" );
219         nouns.put( "3", "wabe" );
220 
221         HashMap<String, Object> verbs = new HashMap<String, Object>();
222         verbs.put( "1", "gyre" );
223         verbs.put( "2", "gimble" );
224 
225         MultiVariableExpander expander = new MultiVariableExpander();
226         expander.addSource( "noun", nouns );
227         expander.addSource( "verb", verbs );
228         digester.setSubstitutor( new VariableSubstitutor( expander ) );
229 
230         digester.addObjectCreate( "root", SimpleTestBean.class );
231         digester.addCallMethod( "root", "setAlpha", 0 );
232 
233         // Parse our test input.
234         SimpleTestBean root = digester.parse( input );
235 
236         assertNotNull( "Digester returned no object", root );
237 
238         assertEquals( "Twas brillig and the slithy toves" + " did gyre and gimble in the wabe", root.getAlpha() );
239     }
240 
241     /**
242      * Test that an unknown variable causes a RuntimeException.
243      */
244     @Test
245     public void testExpansionException()
246         throws IOException
247     {
248 
249         String xml = "<root alpha='${attr1}'/>";
250         StringReader input = new StringReader( xml );
251         Digester digester = new Digester();
252 
253         // Configure the digester as required
254         MultiVariableExpander expander = new MultiVariableExpander();
255         expander.addSource( "$", new HashMap<String, Object>() );
256         digester.setSubstitutor( new VariableSubstitutor( expander ) );
257 
258         digester.addObjectCreate( "root", SimpleTestBean.class );
259         digester.addSetProperties( "root" );
260 
261         // Parse our test input.
262         try
263         {
264             digester.parse( input );
265             fail( "Exception expected due to unknown variable." );
266         }
267         catch ( SAXException e )
268         {
269             // expected, due to reference to undefined variable
270         }
271     }
272 
273     /**
274      * First of two tests added to verify that the substitution framework is capable of processing Ant-like properties.
275      * The tests above essentially verify that if a property was pre-set (e.g. using the "-D" option to Ant), then the
276      * property could be expanded via a variable used either in an attribute or in body text. This test shows that if
277      * properties were also set while processing a document, you could still perform variable expansion (i.e. just like
278      * using the "property" task in Ant).
279      *
280      * @throws IOException
281      * @throws SAXException
282      */
283     @Test
284     public void testExpansionWithMutableSource()
285         throws SAXException, IOException
286     {
287         String xml = "<root>" + "<property name='attr' value='prop.value'/>" + "<bean alpha='${attr}'/>" + "</root>";
288         StringReader input = new StringReader( xml );
289         Digester digester = createDigesterThatCanDoAnt();
290 
291         simpleTestBeans.clear();
292         digester.push( this );
293         digester.parse( input );
294 
295         assertEquals( 1, simpleTestBeans.size() );
296         SimpleTestBean bean = simpleTestBeans.get( 0 );
297         assertEquals( "prop.value", bean.getAlpha() );
298     }
299 
300     /**
301      * Second of two tests added to verify that the substitution framework is capable of processing Ant-like properties.
302      * This test shows that if properties were also set while processing a document, the resulting variables could also
303      * be expanded within a property element. This is thus effectively a "closure" test, since it shows that the
304      * mechanism used to bind properties is also capable of having property values that are driven by property
305      * variables.
306      *
307      * @throws IOException
308      * @throws SAXException
309      */
310     @Test
311     public void testExpansionOfPropertyInProperty()
312         throws SAXException, IOException
313     {
314         String xml =
315             "<root>" + "<property name='attr1' value='prop.value1'/>"
316                 + "<property name='attr2' value='substituted-${attr1}'/>" + "<bean alpha='${attr2}'/>" + "</root>";
317         StringReader input = new StringReader( xml );
318         Digester digester = createDigesterThatCanDoAnt();
319 
320         simpleTestBeans.clear();
321         digester.push( this );
322         digester.parse( input );
323 
324         assertEquals( 1, simpleTestBeans.size() );
325         SimpleTestBean bean = simpleTestBeans.get( 0 );
326         assertEquals( "substituted-prop.value1", bean.getAlpha() );
327     }
328 
329 }