1   /*
2    * Copyright 2006 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.xml.stream;
18  
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.StringReader;
22  import java.util.Arrays;
23  import javax.xml.stream.XMLInputFactory;
24  import javax.xml.stream.XMLStreamException;
25  
26  import junit.framework.TestCase;
27  import org.easymock.AbstractMatcher;
28  import org.easymock.MockControl;
29  import org.xml.sax.Attributes;
30  import org.xml.sax.ContentHandler;
31  import org.xml.sax.DTDHandler;
32  import org.xml.sax.InputSource;
33  import org.xml.sax.Locator;
34  import org.xml.sax.SAXException;
35  import org.xml.sax.XMLReader;
36  import org.xml.sax.helpers.XMLReaderFactory;
37  
38  public abstract class AbstractStaxXmlReaderTestCase extends TestCase {
39  
40      protected static XMLInputFactory inputFactory = XMLInputFactory.newInstance();
41  
42      private static final String XML_DTD_HANDLER =
43              "<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'><beans />";
44  
45      private static final String XML_CONTENT_HANDLER =
46              "<?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2'>content</prefix:child></root>";
47  
48      private static final String XML_CONTENT_HANDLER_ATTS = "<element xmlns='namespace' attr='value'/>";
49  
50      private XMLReader reader;
51  
52      protected void setUp() throws Exception {
53          reader = XMLReaderFactory.createXMLReader();
54          reader.setFeature("http://xml.org/sax/features/namespaces", true);
55          reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
56      }
57  
58      public void testContentHandler() throws SAXException, IOException, XMLStreamException {
59          // record the callbacks by parsing the XML with a regular SAX parser
60          MockControl control = MockControl.createStrictControl(ContentHandler.class);
61          control.setDefaultMatcher(new SaxArgumentMatcher());
62          ContentHandler mock = (ContentHandler) control.getMock();
63          reader.setContentHandler(mock);
64          reader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER)));
65          control.replay();
66          AbstractStaxXmlReader staxXmlReader = createStaxXmlReader(new StringReader(XML_CONTENT_HANDLER));
67          staxXmlReader.setContentHandler(mock);
68          staxXmlReader.parse(new InputSource());
69          control.verify();
70      }
71  
72      public void testContentHandlerAttributes() throws SAXException, IOException, XMLStreamException {
73          MockControl control = MockControl.createStrictControl(ContentHandler.class);
74          control.setDefaultMatcher(new SaxArgumentMatcher());
75          ContentHandler mock = (ContentHandler) control.getMock();
76          reader.setContentHandler(mock);
77          reader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER_ATTS)));
78          control.replay();
79          AbstractStaxXmlReader staxXmlReader = createStaxXmlReader(new StringReader(XML_CONTENT_HANDLER_ATTS));
80          staxXmlReader.setContentHandler(mock);
81          staxXmlReader.parse(new InputSource());
82          control.verify();
83      }
84  
85      public void testDtdHandler() throws IOException, SAXException, XMLStreamException {
86          // record the callbacks by parsing the XML with a regular SAX parser
87          MockControl control = MockControl.createStrictControl(DTDHandler.class);
88          control.setDefaultMatcher(new SaxArgumentMatcher());
89          DTDHandler mock = (DTDHandler) control.getMock();
90          reader.setDTDHandler(mock);
91          reader.parse(new InputSource(new StringReader(XML_DTD_HANDLER)));
92          control.replay();
93          AbstractStaxXmlReader staxXmlReader = createStaxXmlReader(new StringReader(XML_DTD_HANDLER));
94          staxXmlReader.setDTDHandler(mock);
95          staxXmlReader.parse(new InputSource());
96          control.verify();
97      }
98  
99      protected abstract AbstractStaxXmlReader createStaxXmlReader(Reader reader) throws XMLStreamException;
100 
101     /** Easymock <code>ArgumentMatcher</code> implementation that matches SAX arguments. */
102     protected static class SaxArgumentMatcher extends AbstractMatcher {
103 
104         public boolean matches(Object[] expected, Object[] actual) {
105             if (expected == actual) {
106                 return true;
107             }
108             if (expected == null || actual == null) {
109                 return false;
110             }
111             if (expected.length != actual.length) {
112                 throw new IllegalArgumentException("Expected and actual arguments must have the same size");
113             }
114             if (expected.length == 3 && expected[0] instanceof char[] && expected[1] instanceof Integer &&
115                     expected[2] instanceof Integer) {
116                 // handling of the character(char[], int, int) methods
117                 String expectedString = new String((char[]) expected[0], ((Integer) expected[1]).intValue(),
118                         ((Integer) expected[2]).intValue());
119                 String actualString = new String((char[]) actual[0], ((Integer) actual[1]).intValue(),
120                         ((Integer) actual[2]).intValue());
121                 return expectedString.equals(actualString);
122             }
123             else if (expected.length == 1 && (expected[0] instanceof Locator)) {
124                 return true;
125             }
126             else {
127                 return super.matches(expected, actual);
128             }
129         }
130 
131         protected boolean argumentMatches(Object expected, Object actual) {
132             if (expected instanceof char[]) {
133                 return Arrays.equals((char[]) expected, (char[]) actual);
134             }
135             else if (expected instanceof Attributes) {
136                 Attributes expectedAttributes = (Attributes) expected;
137                 Attributes actualAttributes = (Attributes) actual;
138                 if (expectedAttributes.getLength() != actualAttributes.getLength()) {
139                     return false;
140                 }
141                 for (int i = 0; i < expectedAttributes.getLength(); i++) {
142                     if (!expectedAttributes.getURI(i).equals(actualAttributes.getURI(i)) ||
143                             !expectedAttributes.getQName(i).equals(actualAttributes.getQName(i)) ||
144                             !expectedAttributes.getType(i).equals(actualAttributes.getType(i)) ||
145                             !expectedAttributes.getValue(i).equals(actualAttributes.getValue(i))) {
146                         return false;
147                     }
148                 }
149                 return true;
150             }
151             else if (expected instanceof Locator) {
152                 Locator expectedLocator = (Locator) expected;
153                 Locator actualLocator = (Locator) actual;
154                 return expectedLocator.getColumnNumber() == actualLocator.getColumnNumber() &&
155                         expectedLocator.getLineNumber() == actualLocator.getLineNumber();
156             }
157             return super.argumentMatches(expected, actual);
158         }
159 
160         protected String argumentToString(Object argument) {
161             if (argument instanceof char[]) {
162                 char[] array = (char[]) argument;
163                 StringBuffer buffer = new StringBuffer();
164                 for (int i = 0; i < array.length; i++) {
165                     buffer.append(array[i]);
166                 }
167                 return buffer.toString();
168             }
169             else if (argument instanceof Attributes) {
170                 Attributes attributes = (Attributes) argument;
171                 StringBuffer buffer = new StringBuffer("[");
172                 for (int i = 0; i < attributes.getLength(); i++) {
173                     buffer.append('{');
174                     buffer.append(attributes.getURI(i));
175                     buffer.append('}');
176                     buffer.append(attributes.getQName(i));
177                     buffer.append('=');
178                     buffer.append(attributes.getValue(i));
179                     if (i < attributes.getLength() - 1) {
180                         buffer.append(", ");
181                     }
182                 }
183                 buffer.append(']');
184                 return buffer.toString();
185             }
186             else if (argument instanceof Locator) {
187                 Locator locator = (Locator) argument;
188                 StringBuffer buffer = new StringBuffer("[");
189                 buffer.append(locator.getLineNumber());
190                 buffer.append(',');
191                 buffer.append(locator.getColumnNumber());
192                 buffer.append(']');
193                 return buffer.toString();
194             }
195             else {
196                 return super.argumentToString(argument);
197             }
198         }
199     }
200 
201 
202 }