001/* $Id: SetNestedPropertiesRuleTestCase.java 1197969 2011-11-05 15:15:10Z simonetripodi $
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements.  See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.commons.digester3;
020
021import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
022import static org.junit.Assert.assertEquals;
023import static org.junit.Assert.assertNotNull;
024import static org.junit.Assert.fail;
025
026import java.io.IOException;
027import java.io.Reader;
028import java.io.StringReader;
029
030import org.apache.commons.digester3.binder.AbstractRulesModule;
031import org.junit.Test;
032import org.xml.sax.SAXException;
033
034/**
035 * <p>
036 * Test case for <code>SetNestedPropertiesRule</code>. This contains tests for the main applications of the rule and two
037 * more general tests of digester functionality used by this rule.
038 */
039public class SetNestedPropertiesRuleTestCase
040{
041
042    // ----------------------------------------------------- Instance Variables
043
044    /**
045     * Simple test xml document used in the tests.
046     */
047    protected final static String TEST_XML = "<?xml version='1.0'?>" + "<root>ROOT BODY" + "<alpha>ALPHA BODY</alpha>"
048        + "<beta>BETA BODY</beta>" + "<gamma>GAMMA BODY</gamma>" + "<delta>DELTA BODY</delta>" + "</root>";
049
050    // ------------------------------------------------ Individual Test Methods
051
052    /**
053     * Test that you can successfully automatically set properties.
054     */
055    @Test
056    public void testAutomaticallySetProperties()
057        throws SAXException, IOException
058    {
059        Digester digester = newLoader( new AbstractRulesModule()
060        {
061
062            @Override
063            protected void configure()
064            {
065                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
066                    .then()
067                    .setNestedProperties();
068            }
069
070        }).newDigester();
071
072        SimpleTestBean bean = digester.parse( xmlTestReader() );
073
074        // check properties are set correctly
075        assertEquals( "Property alpha not set correctly", "ALPHA BODY", bean.getAlpha() );
076
077        assertEquals( "Property beta not set correctly", "BETA BODY", bean.getBeta() );
078
079        assertEquals( "Property gamma not set correctly", "GAMMA BODY", bean.getGamma() );
080
081        assertEquals( "Property delta not set correctly", "DELTA BODY", bean.getDeltaValue() );
082    }
083
084    /**
085     * Test that it is an error when a child element exists but no corresponding java property exists.
086     */
087    @Test
088    public void testMandatoryProperties()
089        throws SAXException, IOException
090    {
091        Digester digester = newLoader( new AbstractRulesModule()
092        {
093
094            @Override
095            protected void configure()
096            {
097                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
098                    .then()
099                    .setNestedProperties();
100            }
101
102        }).newDigester();
103
104        String TEST_XML = "<?xml version='1.0'?>" + "<root>ROOT BODY" + "<badprop>ALPHA BODY</badprop>" + "</root>";
105
106        try
107        {
108            SimpleTestBean bean = digester.parse( new StringReader( TEST_XML ) );
109
110            // we should never get here...
111            fail( "No exception thrown by parse when unknown child element found." );
112            assertNotNull( bean ); // just to prevent compiler warning on unused var
113        }
114        catch ( org.xml.sax.SAXParseException e )
115        {
116            String msg = e.getMessage();
117            if ( msg.indexOf( "badprop" ) >= 0 )
118            {
119                // ok, this is expected; there is no "setBadprop" method on the
120                // SimpleTestBean class...
121            }
122            else
123            {
124                fail( "Unexpected parse exception:" + e.getMessage() );
125            }
126        }
127    }
128
129    /**
130     * Test that you can customise the property mappings using the constructor which takes arrays-of-strings.
131     */
132    @Test
133    public void testCustomisedProperties1()
134        throws SAXException, IOException
135    {
136        Digester digester = newLoader( new AbstractRulesModule()
137        {
138
139            @Override
140            protected void configure()
141            {
142                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
143                    .then()
144                    .setNestedProperties()
145                        .addAlias( "alpha" ).forProperty( null )
146                        .addAlias( "gamma-alt" ).forProperty( "gamma" )
147                        .addAlias( "delta" ).forProperty(  null );
148            }
149
150        }).newDigester();
151
152        String TEST_XML =
153            "<?xml version='1.0'?>" + "<root>ROOT BODY" + "<alpha>ALPHA BODY</alpha>" + "<beta>BETA BODY</beta>"
154                + "<gamma-alt>GAMMA BODY</gamma-alt>" + "<delta>DELTA BODY</delta>" + "</root>";
155
156        SimpleTestBean bean = digester.parse( new StringReader( TEST_XML ) );
157
158        // check properties are set correctly
159        assertEquals( "Property alpha was not ignored (it should be)", null, bean.getAlpha() );
160
161        assertEquals( "Property beta not set correctly", "BETA BODY", bean.getBeta() );
162
163        assertEquals( "Property gamma not set correctly", "GAMMA BODY", bean.getGamma() );
164
165        assertEquals( "Property delta was not ignored (it should be)", null, bean.getDeltaValue() );
166
167        // check no bad rules object is left
168        assertEquals( "Digester rules object not reset.", RulesBase.class, digester.getRules().getClass() );
169    }
170
171    /**
172     * Test that you can ignore a single input xml element using the constructor which takes a single remapping.
173     */
174    @Test
175    public void testCustomisedProperties2a()
176        throws SAXException, IOException
177    {
178        Digester digester = newLoader( new AbstractRulesModule()
179        {
180
181            @Override
182            protected void configure()
183            {
184                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
185                    .then()
186                    .setNestedProperties()
187                        .addAlias( "alpha" ).forProperty( null );
188            }
189
190        }).newDigester();
191
192        String TEST_XML =
193            "<?xml version='1.0'?>" + "<root>ROOT BODY" + "<alpha>ALPHA BODY</alpha>" + "<beta>BETA BODY</beta>"
194                + "<gamma>GAMMA BODY</gamma>" + "<delta>DELTA BODY</delta>" + "</root>";
195
196        SimpleTestBean bean = digester.parse( new StringReader( TEST_XML ) );
197
198        // check properties are set correctly
199        assertEquals( "Property alpha was not ignored (it should be)", null, bean.getAlpha() );
200
201        assertEquals( "Property beta not set correctly", "BETA BODY", bean.getBeta() );
202
203        assertEquals( "Property gamma not set correctly", "GAMMA BODY", bean.getGamma() );
204
205        assertEquals( "Property delta not set correctly", "DELTA BODY", bean.getDeltaValue() );
206
207        // check no bad rules object is left
208        assertEquals( "Digester rules object not reset.", RulesBase.class, digester.getRules().getClass() );
209    }
210
211    /**
212     * Test that you can customise the property mappings using the constructor which takes a single remapping.
213     */
214    @Test
215    public void testCustomisedProperties2b()
216        throws SAXException, IOException
217    {
218        Digester digester = newLoader( new AbstractRulesModule()
219        {
220
221            @Override
222            protected void configure()
223            {
224                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
225                    .then()
226                    .setNestedProperties()
227                        .addAlias( "alpha-alt" ).forProperty( "alpha" );
228            }
229
230        }).newDigester();
231
232        String TEST_XML =
233            "<?xml version='1.0'?>" + "<root>ROOT BODY" + "<alpha-alt>ALPHA BODY</alpha-alt>"
234                + "<beta>BETA BODY</beta>" + "<gamma>GAMMA BODY</gamma>" + "<delta>DELTA BODY</delta>" + "</root>";
235
236        SimpleTestBean bean = digester.parse( new StringReader( TEST_XML ) );
237
238        // check properties are set correctly
239        assertEquals( "Property alpha not set correctly", "ALPHA BODY", bean.getAlpha() );
240
241        assertEquals( "Property beta not set correctly", "BETA BODY", bean.getBeta() );
242
243        assertEquals( "Property gamma not set correctly", "GAMMA BODY", bean.getGamma() );
244
245        assertEquals( "Property delta not set correctly", "DELTA BODY", bean.getDeltaValue() );
246
247        // check no bad rules object is left
248        assertEquals( "Digester rules object not reset.", RulesBase.class, digester.getRules().getClass() );
249    }
250
251    /**
252     * Test that:
253     * <ul>
254     * <li>you can have rules matching the same pattern as the SetNestedPropertiesRule,</li>
255     * <li>you can have rules matching child elements of the rule,</li>
256     * <li>the Rules object is reset nicely.</li>
257     * </ul>
258     */
259    @Test
260    public void testMultiRuleMatch()
261        throws SAXException, IOException
262    {
263        Digester digester = newLoader( new AbstractRulesModule()
264        {
265
266            @Override
267            protected void configure()
268            {
269                forPattern( "root/testbean" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
270                    .then()
271                    .setProperties()
272                    .then()
273                    .setNestedProperties();
274                forPattern( "root/testbean/gamma/prop" ).setProperty( "name" ).extractingValueFromAttribute( "value" );
275            }
276
277        }).newDigester();
278
279        String testXml =
280            "<?xml version='1.0'?>" + "<root>" + "<testbean alpha='alpha-attr'>ROOT BODY" + "<beta>BETA BODY</beta>"
281                + "<gamma>GAMMA " + "<prop name='delta' value='delta-prop'/>" + "BODY" + "</gamma>" + "</testbean>"
282                + "</root>";
283
284        Reader reader = new StringReader( testXml );
285
286        SimpleTestBean bean = digester.parse( reader );
287
288        assertNotNull( "No object created", bean );
289
290        // check properties are set correctly
291        assertEquals( "Property alpha not set correctly", "alpha-attr", bean.getAlpha() );
292
293        assertEquals( "Property beta not set correctly", "BETA BODY", bean.getBeta() );
294
295        assertEquals( "Property gamma not set correctly", "GAMMA BODY", bean.getGamma() );
296
297        assertEquals( "Property delta not set correctly", "delta-prop", bean.getDeltaValue() );
298
299        // check no bad rules object is left
300        assertEquals( "Digester rules object not reset.", RulesBase.class, digester.getRules().getClass() );
301    }
302
303    /**
304     * Test that unknown child elements trigger an exception.
305     */
306    @Test
307    public void testUnknownChildrenCausesException()
308        throws SAXException, IOException
309    {
310        Digester digester = newLoader( new AbstractRulesModule()
311        {
312
313            @Override
314            protected void configure()
315            {
316                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
317                    .then()
318                    .setNestedProperties();
319            }
320
321        }).newDigester();
322
323        String testXml =
324            "<?xml version='1.0'?>" + "<root>" + "<testbean>" + "<beta>BETA BODY</beta>" + "<foo>GAMMA</foo>"
325                + "</testbean>" + "</root>";
326
327        Reader reader = new StringReader( testXml );
328
329        try
330        {
331            SimpleTestBean bean = digester.parse( reader );
332            fail( "Expected to generate an exception." );
333            assertNotNull( bean ); // just to prevent compiler warning on unused var
334        }
335        catch ( SAXException e )
336        {
337            Exception nested = e.getException();
338            if ( ( nested == null ) || !( nested instanceof NoSuchMethodException ) )
339            {
340                // nope, not the sort of exception we expected
341                throw e;
342            }
343        }
344    }
345
346    /**
347     * Test that unknown child elements are allowed if the appropriate flag is set.
348     */
349    @Test
350    public void testUnknownChildrenExceptionOverride()
351        throws SAXException, IOException
352    {
353        Digester digester = newLoader( new AbstractRulesModule()
354        {
355
356            @Override
357            protected void configure()
358            {
359                forPattern( "root" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
360                    .then()
361                    .setNestedProperties().allowUnknownChildElements( true );
362            }
363
364        }).newDigester();
365
366        String testXml =
367            "<?xml version='1.0'?>" + "<root>" + "<testbean>" + "<beta>BETA BODY</beta>" + "<foo>GAMMA</foo>"
368                + "</testbean>" + "</root>";
369
370        Reader reader = new StringReader( testXml );
371
372        SimpleTestBean bean = digester.parse( reader );
373        assertNotNull( bean );
374    }
375
376    /**
377     * Test that the rule works in a sane manner when the associated pattern is a wildcard such that the rule matches
378     * one of its own child elements.
379     * <p>
380     * See bugzilla entry 31393.
381     */
382    @Test
383    public void testRecursiveNestedProperties()
384        throws SAXException, IOException
385    {
386        Digester digester = newLoader( new AbstractRulesModule()
387        {
388
389            @Override
390            protected void configure()
391            {
392                forPattern( "*/testbean" ).createObject().ofType( "org.apache.commons.digester3.SimpleTestBean" )
393                    .then()
394                    .setNestedProperties().allowUnknownChildElements( true );
395            }
396
397        }).newDigester();
398
399        String testXml =
400            "<?xml version='1.0'?>" + "<testbean>" + "<beta>BETA BODY</beta>" + "<testbean>" + "<beta>BETA BODY</beta>"
401                + "</testbean>" + "</testbean>";
402
403        Reader reader = new StringReader( testXml );
404
405        SimpleTestBean bean = digester.parse( reader );
406        assertNotNull( bean );
407    }
408
409    /**
410     * Get input stream from {@link #TEST_XML}.
411     */
412    private Reader xmlTestReader()
413    {
414        return new StringReader( TEST_XML );
415    }
416
417}