001 /*
002 * Copyright (c) 2007 Henri Sivonen
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a
005 * copy of this software and associated documentation files (the "Software"),
006 * to deal in the Software without restriction, including without limitation
007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
008 * and/or sell copies of the Software, and to permit persons to whom the
009 * Software is furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020 * DEALINGS IN THE SOFTWARE.
021 */
022
023 package nu.validator.htmlparser.test;
024
025 import java.io.BufferedInputStream;
026 import java.io.BufferedReader;
027 import java.io.FileInputStream;
028 import java.io.IOException;
029 import java.io.InputStream;
030 import java.io.InputStreamReader;
031 import java.io.StringWriter;
032 import java.util.LinkedList;
033
034 import nu.validator.htmlparser.common.XmlViolationPolicy;
035 import nu.validator.htmlparser.sax.HtmlParser;
036
037 import org.xml.sax.InputSource;
038 import org.xml.sax.SAXException;
039 import org.xml.sax.SAXParseException;
040
041 public class TreeTester {
042
043 private final BufferedInputStream aggregateStream;
044
045 private boolean streaming = false;
046
047 /**
048 * @param aggregateStream
049 */
050 public TreeTester(InputStream aggregateStream) {
051 this.aggregateStream = new BufferedInputStream(aggregateStream);
052 }
053
054 private void runTests() throws Throwable {
055 if (aggregateStream.read() != '#') {
056 System.err.println("No hash at start!");
057 return;
058 }
059 while (runTest()) {
060 // spin
061 }
062 }
063
064 private boolean runTest() throws Throwable {
065 UntilHashInputStream stream = null;
066 try {
067 String context = null;
068 aggregateStream.mark(4096);
069 if (skipLabel()) { // #data
070 return false;
071 }
072 stream = new UntilHashInputStream(aggregateStream);
073 while (stream.read() != -1) {
074 // spin
075 }
076 if (skipLabel()) { // #errors
077 System.err.println("Premature end of test data.");
078 return false;
079 }
080 stream = new UntilHashInputStream(aggregateStream);
081 while (stream.read() != -1) {
082 // spin
083 }
084
085 StringBuilder sb = new StringBuilder();
086 int c;
087 while ((c = aggregateStream.read()) != '\n') {
088 sb.append((char) c);
089 }
090 String label = sb.toString();
091 if ("document-fragment".equals(label)) {
092 sb.setLength(0);
093 while ((c = aggregateStream.read()) != '\n') {
094 sb.append((char) c);
095 }
096 context = sb.toString();
097 }
098 aggregateStream.reset();
099 if (skipLabel()) { // #data
100 System.err.println("Premature end of test data.");
101 return false;
102 }
103 stream = new UntilHashInputStream(aggregateStream);
104 InputSource is = new InputSource(stream);
105 is.setEncoding("UTF-8");
106 StringWriter sw = new StringWriter();
107 ListErrorHandler leh = new ListErrorHandler();
108 TreeDumpContentHandler treeDumpContentHandler = new TreeDumpContentHandler(
109 sw);
110 HtmlParser htmlParser = new HtmlParser(XmlViolationPolicy.ALLOW);
111 if (streaming) {
112 htmlParser.setStreamabilityViolationPolicy(XmlViolationPolicy.FATAL);
113 }
114 htmlParser.setContentHandler(treeDumpContentHandler);
115 htmlParser.setLexicalHandler(treeDumpContentHandler);
116 htmlParser.setErrorHandler(leh);
117 htmlParser.setScriptingEnabled(true);
118 try {
119 if (context == null) {
120 htmlParser.parse(is);
121 } else {
122 htmlParser.parseFragment(is, context);
123 treeDumpContentHandler.endDocument();
124 }
125 } catch (SAXParseException e) {
126 // ignore
127 }
128 stream.close();
129
130 if (skipLabel()) { // #errors
131 System.err.println("Premature end of test data.");
132 return false;
133 }
134 LinkedList<String> expectedErrors = new LinkedList<String>();
135 BufferedReader br = new BufferedReader(new InputStreamReader(
136 new UntilHashInputStream(aggregateStream), "UTF-8"));
137 String line = null;
138 while ((line = br.readLine()) != null) {
139 expectedErrors.add(line);
140 }
141
142 if (context != null) {
143 if (skipLabel()) { // #document-fragment
144 System.err.println("Premature end of test data.");
145 return false;
146 }
147 UntilHashInputStream stream2 = new UntilHashInputStream(aggregateStream);
148 while (stream2.read() != -1) {
149 // spin
150 }
151 }
152
153
154 if (skipLabel()) { // #document
155 System.err.println("Premature end of test data.");
156 return false;
157 }
158
159 StringBuilder expectedBuilder = new StringBuilder();
160 br = new BufferedReader(new InputStreamReader(
161 new UntilHashInputStream(aggregateStream), "UTF-8"));
162 while ((line = br.readLine()) != null) {
163 expectedBuilder.append(line);
164 expectedBuilder.append('\n');
165 }
166 String expected = expectedBuilder.toString();
167 String actual = sw.toString();
168
169 LinkedList<String> actualErrors = leh.getErrors();
170
171 if (expected.equals(actual) || (streaming && leh.isFatal()) /*
172 * && expectedErrors.size() ==
173 * actualErrors.size()
174 */) {
175 System.err.println("Success.");
176 // System.err.println(stream);
177 } else {
178 System.err.print("Failure.\nData:\n" + stream + "\nExpected:\n"
179 + expected + "Got: \n" + actual);
180 System.err.println("Expected errors:");
181 for (String err : expectedErrors) {
182 System.err.println(err);
183 }
184 System.err.println("Actual errors:");
185 for (String err : actualErrors) {
186 System.err.println(err);
187 }
188 }
189 } catch (Throwable t) {
190 System.err.println("Failure.\nData:\n" + stream);
191 throw t;
192 }
193 return true;
194 }
195
196 private boolean skipLabel() throws IOException {
197 int b = aggregateStream.read();
198 if (b == -1) {
199 return true;
200 }
201 for (;;) {
202 b = aggregateStream.read();
203 if (b == -1) {
204 return true;
205 } else if (b == 0x0A) {
206 return false;
207 }
208 }
209 }
210
211 /**
212 * @param args
213 * @throws Throwable
214 */
215 public static void main(String[] args) throws Throwable {
216 for (int i = 0; i < args.length; i++) {
217 TreeTester tester = new TreeTester(new FileInputStream(args[i]));
218 tester.runTests();
219 }
220 }
221
222 }