001/* $Id: NodeCreateRuleTestCase.java 1212599 2011-12-09 19:46:42Z 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.assertNull;
025import static org.junit.Assert.assertTrue;
026import static org.junit.Assert.fail;
027
028import java.io.IOException;
029import java.io.InputStream;
030import java.io.StringReader;
031import java.util.ArrayList;
032import java.util.List;
033
034import javax.xml.parsers.DocumentBuilder;
035import javax.xml.parsers.DocumentBuilderFactory;
036import javax.xml.parsers.ParserConfigurationException;
037
038import org.apache.commons.digester3.binder.AbstractRulesModule;
039import org.apache.commons.digester3.binder.NodeCreateRuleProvider.NodeType;
040import org.junit.Test;
041import org.w3c.dom.Document;
042import org.w3c.dom.DocumentFragment;
043import org.w3c.dom.Element;
044import org.w3c.dom.Node;
045import org.xml.sax.SAXException;
046
047/**
048 * <p>
049 * Test case for the <code>NodeCreateRule</code>.
050 *
051 * @author Christopher Lenz
052 */
053public class NodeCreateRuleTestCase
054{
055
056    // ----------------------------------------------------- Instance Variables
057
058    /**
059     * Simple test xml document used in the tests.
060     */
061    protected final static String TEST_XML = "<?xml version='1.0'?><root>ROOT BODY<alpha>ALPHA BODY</alpha>"
062        + "<beta>BETA BODY</beta><gamma>GAMMA BODY</gamma></root>";
063
064    // ------------------------------------------------ Individual Test Methods
065
066    /**
067     * Tests simple element construction, using the {@link #TEST_XML} XML input data.
068     */
069    @Test
070    public void testInvalidNodeTypes()
071        throws Exception
072    {
073
074        try
075        {
076            Rule rule = new NodeCreateRule( Node.ATTRIBUTE_NODE );
077            fail( "IllegalArgumentException expected for type ATTRIBUTE_NODE" );
078            assertNotNull( rule ); // just to prevent compiler warning on unused var
079        }
080        catch ( IllegalArgumentException iae )
081        {
082            // expected
083        }
084        try
085        {
086            Rule rule = new NodeCreateRule( Node.CDATA_SECTION_NODE );
087            fail( "IllegalArgumentException expected for type " + "CDATA_SECTION_NODE" );
088            assertNotNull( rule ); // just to prevent compiler warning on unused var
089        }
090        catch ( IllegalArgumentException iae )
091        {
092            // expected
093        }
094        try
095        {
096            Rule rule = new NodeCreateRule( Node.COMMENT_NODE );
097            fail( "IllegalArgumentException expected for type COMMENT_NODE" );
098            assertNotNull( rule ); // just to prevent compiler warning on unused var
099        }
100        catch ( IllegalArgumentException iae )
101        {
102            // expected
103        }
104        try
105        {
106            Rule rule = new NodeCreateRule( Node.DOCUMENT_NODE );
107            fail( "IllegalArgumentException expected for type DOCUMENT_NODE" );
108            assertNotNull( rule ); // just to prevent compiler warning on unused var
109        }
110        catch ( IllegalArgumentException iae )
111        {
112            // expected
113        }
114        try
115        {
116            Rule rule = new NodeCreateRule( Node.DOCUMENT_TYPE_NODE );
117            fail( "IllegalArgumentException expected for type " + "DOCUMENT_TYPE_NODE" );
118            assertNotNull( rule ); // just to prevent compiler warning on unused var
119        }
120        catch ( IllegalArgumentException iae )
121        {
122            // expected
123        }
124        try
125        {
126            Rule rule = new NodeCreateRule( Node.ENTITY_NODE );
127            fail( "IllegalArgumentException expected for type ENTITY_NODE" );
128            assertNotNull( rule ); // just to prevent compiler warning on unused var
129        }
130        catch ( IllegalArgumentException iae )
131        {
132            // expected
133        }
134        try
135        {
136            Rule rule = new NodeCreateRule( Node.ENTITY_REFERENCE_NODE );
137            fail( "IllegalArgumentException expected for type " + "ENTITY_REFERENCE_NODE" );
138            assertNotNull( rule ); // just to prevent compiler warning on unused var
139        }
140        catch ( IllegalArgumentException iae )
141        {
142            // expected
143        }
144        try
145        {
146            Rule rule = new NodeCreateRule( Node.NOTATION_NODE );
147            fail( "IllegalArgumentException expected for type NOTATION_NODE" );
148            assertNotNull( rule ); // just to prevent compiler warning on unused var
149        }
150        catch ( IllegalArgumentException iae )
151        {
152            // expected
153        }
154        try
155        {
156            Rule rule = new NodeCreateRule( Node.PROCESSING_INSTRUCTION_NODE );
157            fail( "IllegalArgumentException expected for type " + "PROCESSING_INSTRUCTION_NODE" );
158            assertNotNull( rule ); // just to prevent compiler warning on unused var
159        }
160        catch ( IllegalArgumentException iae )
161        {
162            // expected
163        }
164        try
165        {
166            Rule rule = new NodeCreateRule( Node.TEXT_NODE );
167            fail( "IllegalArgumentException expected for type TEXT_NODE" );
168            assertNotNull( rule ); // just to prevent compiler warning on unused var
169        }
170        catch ( IllegalArgumentException iae )
171        {
172            // expected
173        }
174
175    }
176
177    /**
178     * Tests simple element construction, using the {@link #TEST_XML} XML input data.
179     */
180    @Test
181    public void testElement()
182        throws SAXException, IOException
183    {
184        Digester digester = newLoader( new AbstractRulesModule()
185        {
186
187            @Override
188            protected void configure()
189            {
190                forPattern( "root/alpha" ).createNode();
191            }
192
193        }).newDigester();
194
195        Element element = digester.parse( new StringReader( TEST_XML ) );
196
197        assertNotNull( element );
198        assertEquals( "alpha", element.getNodeName() );
199        assertNull( element.getLocalName() );
200        assertNull( element.getNamespaceURI() );
201        assertEquals( 1, element.getChildNodes().getLength() );
202        assertEquals( "ALPHA BODY", element.getFirstChild().getNodeValue() );
203
204    }
205
206    /**
207     * Tests simple fragment construction, using the {@link #TEST_XML} XML input data.
208     */
209    @Test
210    public void testDocumentFragment()
211        throws SAXException, IOException
212    {
213        Digester digester = newLoader( new AbstractRulesModule()
214        {
215
216            @Override
217            protected void configure()
218            {
219                forPattern( "root" ).createNode().ofType( NodeType.DOCUMENT_FRAGMENT );
220            }
221
222        }).newDigester();
223
224        DocumentFragment fragment = digester.parse( new StringReader( TEST_XML ) );
225
226        assertNotNull( fragment );
227        assertEquals( 4, fragment.getChildNodes().getLength() );
228
229        Node rootBody = fragment.getFirstChild();
230        assertEquals( Node.TEXT_NODE, rootBody.getNodeType() );
231        assertEquals( "ROOT BODY", rootBody.getNodeValue() );
232
233        Node alpha = fragment.getChildNodes().item( 1 );
234        assertEquals( Node.ELEMENT_NODE, alpha.getNodeType() );
235        assertEquals( "alpha", alpha.getNodeName() );
236        assertNull( ( (Element) alpha ).getLocalName() );
237        assertNull( ( (Element) alpha ).getNamespaceURI() );
238        assertEquals( 1, alpha.getChildNodes().getLength() );
239        assertEquals( "ALPHA BODY", alpha.getFirstChild().getNodeValue() );
240
241        Node beta = fragment.getChildNodes().item( 2 );
242        assertEquals( Node.ELEMENT_NODE, beta.getNodeType() );
243        assertEquals( "beta", beta.getNodeName() );
244        assertNull( ( (Element) beta ).getLocalName() );
245        assertNull( ( (Element) beta ).getNamespaceURI() );
246        assertEquals( 1, beta.getChildNodes().getLength() );
247        assertEquals( "BETA BODY", beta.getFirstChild().getNodeValue() );
248
249        Node gamma = fragment.getChildNodes().item( 3 );
250        assertEquals( Node.ELEMENT_NODE, gamma.getNodeType() );
251        assertEquals( "gamma", gamma.getNodeName() );
252        assertNull( ( (Element) gamma ).getLocalName() );
253        assertNull( ( (Element) gamma ).getNamespaceURI() );
254        assertEquals( 1, gamma.getChildNodes().getLength() );
255        assertEquals( "GAMMA BODY", gamma.getFirstChild().getNodeValue() );
256
257    }
258
259    /**
260     * Tests whether control is returned to digester after fragment construction.
261     */
262    @Test
263    public void testNested()
264        throws SAXException, IOException
265    {
266        Digester digester = newLoader( new AbstractRulesModule()
267        {
268
269            @Override
270            protected void configure()
271            {
272                forPattern( "root" ).createObject().ofType( ArrayList.class );
273                forPattern( "root/a/b" ).createNode().ofType( NodeType.DOCUMENT_FRAGMENT )
274                    .then()
275                    .setRoot( "add" );
276                forPattern( "root/b" ).createObject().ofType( String.class )
277                    .then()
278                    .setRoot( "add" );
279            }
280
281        }).newDigester();
282
283        List<?> list = digester.parse( getInputStream( "Test4.xml" ) );
284
285        assertNotNull( list );
286        assertEquals( 2, list.size() );
287
288        assertTrue( list.get( 0 ) instanceof DocumentFragment );
289        DocumentFragment fragment = (DocumentFragment) list.get( 0 );
290
291        assertEquals( Node.ELEMENT_NODE, fragment.getFirstChild().getNodeType() );
292        Element a = (Element) fragment.getFirstChild();
293        assertEquals( "a", a.getNodeName() );
294        assertEquals( 1, a.getAttributes().getLength() );
295        assertEquals( "THREE", a.getAttribute( "name" ) );
296
297        assertTrue( list.get( 1 ) instanceof String );
298
299    }
300
301    /**
302     * Tests whether attributes are correctly imported into the fragment, using the example in the Test1 XML file.
303     */
304    @Test
305    public void testAttributes()
306        throws SAXException, IOException
307    {
308        Digester digester = newLoader( new AbstractRulesModule()
309        {
310
311            @Override
312            protected void configure()
313            {
314                forPattern( "employee" ).createNode().ofType( NodeType.DOCUMENT_FRAGMENT );
315            }
316
317        }).newDigester();
318
319        DocumentFragment fragment = digester.parse( getInputStream( "Test1.xml" ) );
320
321        assertNotNull( fragment );
322        assertEquals( 2, fragment.getChildNodes().getLength() );
323
324        assertEquals( Node.ELEMENT_NODE, fragment.getFirstChild().getNodeType() );
325        Element address1 = (Element) fragment.getFirstChild();
326        assertEquals( "address", address1.getNodeName() );
327        assertEquals( 5, address1.getAttributes().getLength() );
328        assertEquals( "home", address1.getAttribute( "type" ) );
329        assertEquals( "Home Street", address1.getAttribute( "street" ) );
330        assertEquals( "Home City", address1.getAttribute( "city" ) );
331        assertEquals( "HS", address1.getAttribute( "state" ) );
332        assertEquals( "HmZip", address1.getAttribute( "zipCode" ) );
333
334        assertEquals( Node.ELEMENT_NODE, fragment.getLastChild().getNodeType() );
335        Element address2 = (Element) fragment.getLastChild();
336        assertEquals( "address", address2.getNodeName() );
337        assertEquals( 5, address2.getAttributes().getLength() );
338        assertEquals( "office", address2.getAttribute( "type" ) );
339        assertEquals( "Office Street", address2.getAttribute( "street" ) );
340        assertEquals( "Office City", address2.getAttribute( "city" ) );
341        assertEquals( "OS", address2.getAttribute( "state" ) );
342        assertEquals( "OfZip", address2.getAttribute( "zipCode" ) );
343
344    }
345
346    /**
347     * Tests whether namespaces are handled correctly, using the example from the file Test3 XML file.
348     */
349    @Test
350    public void testNamespaces()
351        throws SAXException, IOException
352    {
353        Digester digester = newLoader( new AbstractRulesModule()
354        {
355
356            @Override
357            protected void configure()
358            {
359                forPattern( "employee" ).createNode().ofType( NodeType.DOCUMENT_FRAGMENT );
360            }
361
362        })
363        .setNamespaceAware( true )
364        .newDigester();
365
366        DocumentFragment fragment = digester.parse( getInputStream( "Test3.xml" ) );
367
368        assertNotNull( fragment );
369        assertEquals( 2, fragment.getChildNodes().getLength() );
370
371        assertEquals( Node.ELEMENT_NODE, fragment.getFirstChild().getNodeType() );
372        Element address1 = (Element) fragment.getFirstChild();
373        assertEquals( "address", address1.getNodeName() );
374        assertEquals( "http://commons.apache.org/digester/Bar", address1.getNamespaceURI() );
375        assertEquals( "address", address1.getLocalName() );
376        assertEquals( 5, address1.getAttributes().getLength() );
377        assertEquals( "home", address1.getAttribute( "type" ) );
378        assertEquals( "Home Street", address1.getAttribute( "street" ) );
379        assertEquals( "Home City", address1.getAttribute( "city" ) );
380        assertEquals( "HS", address1.getAttribute( "state" ) );
381        assertEquals( "HmZip", address1.getAttribute( "zipCode" ) );
382
383        assertEquals( Node.ELEMENT_NODE, fragment.getLastChild().getNodeType() );
384        Element address2 = (Element) fragment.getLastChild();
385        assertEquals( "address", address2.getNodeName() );
386        assertEquals( "http://commons.apache.org/digester/Bar", address2.getNamespaceURI() );
387        assertEquals( "address", address2.getLocalName() );
388        assertEquals( 5, address2.getAttributes().getLength() );
389        assertEquals( "office", address2.getAttribute( "type" ) );
390        assertEquals( "Office Street", address2.getAttribute( "street" ) );
391        assertEquals( "Office City", address2.getAttribute( "city" ) );
392        assertEquals( "OS", address2.getAttribute( "state" ) );
393        assertEquals( "OfZip", address2.getAttribute( "zipCode" ) );
394
395    }
396
397    /**
398     * Tests whether namespaced attributes are handled correctly, using the example from the file Test10 XML file.
399     */
400    @Test
401    public void testNamespacedAttribute()
402        throws SAXException, IOException
403    {
404        Digester digester = newLoader( new AbstractRulesModule()
405        {
406
407            @Override
408            protected void configure()
409            {
410                forPattern( "employee" ).createNode().ofType( NodeType.ELEMENT );
411            }
412
413        })
414        .setNamespaceAware( true )
415        .newDigester();
416
417        Element element = digester.parse( getInputStream( "Test10.xml" ) );
418
419        assertNotNull( element );
420
421        assertNotNull( element.getAttributeNodeNS( "http://commons.apache.org/digester/Bar", "test" ) );
422        assertEquals( "MyTestAttribute",
423                      element.getAttributeNodeNS( "http://commons.apache.org/digester/Bar", "test" ).getNodeValue() );
424        assertEquals( "test",
425                      element.getAttributeNodeNS( "http://commons.apache.org/digester/Bar", "test" ).getLocalName() );
426        assertEquals( "bar", element.getAttributeNodeNS( "http://commons.apache.org/digester/Bar", "test" ).getPrefix() );
427        assertEquals( "bar:test",
428                      element.getAttributeNodeNS( "http://commons.apache.org/digester/Bar", "test" ).getName() );
429
430    }
431
432    /**
433     * Tests whether non-namespaced attributes are handled correctly, using the example from the file Test11 XML file.
434     */
435    @Test
436    public void testNonNamespacedAttribute()
437        throws SAXException, IOException
438    {
439        Digester digester = newLoader( new AbstractRulesModule()
440        {
441
442            @Override
443            protected void configure()
444            {
445                forPattern( "employee" ).createNode().ofType( NodeType.ELEMENT );
446            }
447
448        })
449        .setNamespaceAware( true )
450        .newDigester();
451
452        Element element = digester.parse( getInputStream( "Test10.xml" ) );
453
454        assertNotNull( element );
455
456        assertNotNull( element.getAttributeNode( "firstName" ) );
457        assertEquals( "First Name", element.getAttributeNode( "firstName" ).getNodeValue() );
458        assertEquals( "firstName", element.getAttributeNode( "firstName" ).getLocalName() );
459        assertEquals( null, element.getAttributeNode( "firstName" ).getPrefix() );
460        assertEquals( "firstName", element.getAttributeNode( "firstName" ).getName() );
461
462    }
463
464    /**
465     * Tests whether the created fragment can be imported into an existing document.
466     */
467    @Test
468    public void testImport()
469        throws SAXException, ParserConfigurationException, IOException
470    {
471        Digester digester = newLoader( new AbstractRulesModule()
472        {
473
474            @Override
475            protected void configure()
476            {
477                forPattern( "root" ).createNode().ofType( NodeType.DOCUMENT_FRAGMENT );
478            }
479
480        })
481        .newDigester();
482
483        DocumentFragment fragment = digester.parse( new StringReader( TEST_XML ) );
484
485        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
486        DocumentBuilder builder = factory.newDocumentBuilder();
487        Document doc = builder.newDocument();
488        Node importedFragment = doc.importNode( fragment, true );
489        doc.appendChild( doc.createElement( "root" ) );
490        doc.getFirstChild().appendChild( importedFragment );
491
492    }
493
494    /**
495     * This unit test checks that text nodes are correctly created when xml entities are used. In particular, this
496     * usually causes the xml parser to make multiple invocations of the characters(..) sax callback, rather than just
497     * one.
498     */
499    @Test
500    public void testEntityText()
501        throws Exception
502    {
503        String TEST_XML2 = "<?xml version='1.0'?><root><alpha>&#65; &#65;</alpha></root>";
504
505        Digester digester = newLoader( new AbstractRulesModule()
506        {
507
508            @Override
509            protected void configure()
510            {
511                forPattern( "root/alpha" ).createNode();
512            }
513
514        })
515        .newDigester();
516
517        Element element = digester.parse( new StringReader( TEST_XML2 ) );
518
519        assertNotNull( element );
520        assertEquals( "alpha", element.getNodeName() );
521        assertNull( element.getLocalName() );
522        assertNull( element.getNamespaceURI() );
523        assertEquals( 1, element.getChildNodes().getLength() );
524        assertEquals( "A A", element.getFirstChild().getNodeValue() );
525    }
526
527    // ------------------------------------------------ Utility Support Methods
528
529    /**
530     * Return an appropriate InputStream for the specified test file (which must be inside our current package.
531     *
532     * @param name Name of the test file we want
533     * @exception IOException if an input/output error occurs
534     */
535    protected InputStream getInputStream( String name )
536        throws IOException
537    {
538
539        return ( this.getClass().getResourceAsStream( "/org/apache/commons/digester3/" + name ) );
540
541    }
542
543}