1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.parser;
20
21 import java.io.IOException;
22 import java.io.Reader;
23 import java.io.StringWriter;
24 import java.io.Writer;
25 import java.util.Iterator;
26 import java.util.ListIterator;
27
28 import org.apache.maven.doxia.AbstractModuleTest;
29 import org.apache.maven.doxia.sink.Sink;
30 import org.apache.maven.doxia.sink.SinkEventAttributes;
31 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
32 import org.apache.maven.doxia.sink.impl.SinkEventElement;
33 import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
34 import org.apache.maven.doxia.sink.impl.SinkWrapper;
35 import org.apache.maven.doxia.sink.impl.SinkWrapperFactory;
36 import org.apache.maven.doxia.sink.impl.TextSink;
37 import org.apache.maven.doxia.sink.impl.WellformednessCheckingSink;
38 import org.junit.jupiter.api.Assertions;
39 import org.junit.jupiter.api.Test;
40
41 import static org.junit.jupiter.api.Assertions.assertEquals;
42 import static org.junit.jupiter.api.Assertions.assertFalse;
43 import static org.junit.jupiter.api.Assertions.assertTrue;
44 import static org.junit.jupiter.api.Assumptions.assumeTrue;
45
46
47
48
49
50
51
52
53 public abstract class AbstractParserTest extends AbstractModuleTest {
54
55
56
57 public static final String TEXT_WITH_SPECIAL_CHARS = "<>{}=#*";
58
59
60
61
62
63
64 protected abstract AbstractParser createParser();
65
66
67
68
69
70
71 protected String getOutputDir() {
72 return "parser/";
73 }
74
75
76
77
78
79
80
81
82
83 @Test
84 public final void testParser() throws IOException, ParseException {
85 WellformednessCheckingSink sink = new WellformednessCheckingSink();
86
87 try (Reader reader = getTestReader("test", outputExtension())) {
88 createParser().parse(reader, sink);
89
90 assertTrue(
91 sink.isWellformed(),
92 "Parser output not well-formed, last offending element: " + sink.getOffender());
93 }
94 }
95
96
97
98
99
100
101
102
103
104 @Test
105 public final void testDocument() throws IOException, ParseException {
106 try (Writer writer = getTestWriter("test", "txt");
107 Reader reader = getTestReader("test", outputExtension())) {
108 Sink sink = new TextSink(writer);
109 createParser().parse(reader, sink);
110 }
111 }
112
113 private static final class TestSinkWrapperFactory implements SinkWrapperFactory {
114
115 private final int priority;
116
117 public TestSinkWrapperFactory(int priority) {
118 super();
119 this.priority = priority;
120 }
121
122 @Override
123 public Sink createWrapper(Sink sink) {
124 return new SinkWrapper(sink) {
125
126 @Override
127 public void text(String text, SinkEventAttributes attributes) {
128 super.text("beforeWrapper" + priority + text + "afterWrapper" + priority, attributes);
129 }
130 };
131 }
132
133 @Override
134 public int getPriority() {
135 return priority;
136 }
137 }
138
139 @Test
140 public final void testSinkWrapper() throws ParseException, IOException {
141 Parser parser = createParser();
142
143 parser.addSinkWrapperFactory(new TestSinkWrapperFactory(1));
144 parser.addSinkWrapperFactory(new TestSinkWrapperFactory(0));
145 parser.addSinkWrapperFactory(new TestSinkWrapperFactory(2));
146
147 try (StringWriter writer = new StringWriter();
148 Reader reader = getTestReader("test", outputExtension())) {
149 Sink sink = new TextSink(writer);
150 parser.parse(reader, sink);
151
152
153
154 assertTrue(writer.toString().contains("beforeWrapper0beforeWrapper1beforeWrapper2"));
155 assertTrue(writer.toString().contains("afterWrapper2afterWrapper1afterWrapper0"));
156 }
157 }
158
159
160
161
162
163
164 protected void assertEventPrefix(Iterator<SinkEventElement> eventIterator) {
165
166 }
167
168
169
170
171
172
173 protected void assertEventSuffix(Iterator<SinkEventElement> eventIterator) {
174 assertFalse(eventIterator.hasNext(), "didn't expect any further events but got at least one");
175 }
176
177
178
179
180
181 protected abstract String getVerbatimSource();
182
183
184
185
186
187 @Test
188 public void testVerbatim() throws ParseException {
189 String source = getVerbatimSource();
190 assumeTrue(source != null, "parser does not support simple verbatim text");
191 AbstractParser parser = createParser();
192 SinkEventTestingSink sink = new SinkEventTestingSink();
193
194 parser.parse(source, sink);
195 ListIterator<SinkEventElement> it = sink.getEventList().listIterator();
196 assertEventPrefix(it);
197 assertEquals("verbatim", it.next().getName());
198 assertConcatenatedTextEquals(it, TEXT_WITH_SPECIAL_CHARS, true);
199 assertEquals("verbatim_", it.next().getName());
200 assertEventSuffix(it);
201 }
202
203
204
205
206
207 protected abstract String getVerbatimCodeSource();
208
209
210
211
212
213 @Test
214 public void testVerbatimCode() throws ParseException {
215 String source = getVerbatimCodeSource();
216 assumeTrue(source != null, "parser does not support verbatim code");
217 AbstractParser parser = createParser();
218 SinkEventTestingSink sink = new SinkEventTestingSink();
219
220 parser.parse(source, sink);
221 ListIterator<SinkEventElement> it = sink.getEventList().listIterator();
222 assertEventPrefix(it);
223 SinkEventElement verbatimEvt = it.next();
224 assertEquals("verbatim", verbatimEvt.getName());
225 SinkEventAttributeSet atts = (SinkEventAttributeSet) verbatimEvt.getArgs()[0];
226
227
228 boolean isInlineCode;
229 if (atts.isEmpty()) {
230 isInlineCode = true;
231 assertSinkAttributesEqual(it.next(), "inline", SinkEventAttributeSet.Semantics.CODE);
232 } else {
233 isInlineCode = false;
234 assertEquals(SinkEventAttributeSet.SOURCE, atts);
235 }
236 assertConcatenatedTextEquals(it, TEXT_WITH_SPECIAL_CHARS, true);
237 if (isInlineCode) {
238 assertEquals("inline_", it.next().getName());
239 }
240 assertEquals("verbatim_", it.next().getName());
241 assertEventSuffix(it);
242 }
243
244 public static void assertSinkEquals(SinkEventElement element, String name, Object... args) {
245 Assertions.assertEquals(name, element.getName(), "Name of element doesn't match");
246 Assertions.assertArrayEquals(args, element.getArgs(), "Arguments don't match");
247 }
248
249 public static void assertSinkAttributeEquals(SinkEventElement element, String name, String attr, String value) {
250 Assertions.assertEquals(name, element.getName());
251 SinkEventAttributeSet atts = (SinkEventAttributeSet) element.getArgs()[0];
252 Assertions.assertEquals(value, atts.getAttribute(attr));
253 }
254
255 public static void assertSinkAttributesEqual(
256 SinkEventElement element, String name, SinkEventAttributes expectedAttributes) {
257 Assertions.assertEquals(name, element.getName());
258 SinkEventAttributeSet atts = (SinkEventAttributeSet) element.getArgs()[0];
259 Assertions.assertEquals(expectedAttributes, atts);
260 }
261
262
263
264
265
266
267
268 void assertConcatenatedTextEquals(ListIterator<SinkEventElement> it, String expectedText, boolean trimText) {
269 StringBuilder builder = new StringBuilder();
270 while (it.hasNext()) {
271 SinkEventElement currentEvent = it.next();
272 if (currentEvent.getName() != "text") {
273 it.previous();
274 break;
275 }
276 builder.append(currentEvent.getArgs()[0]);
277 }
278 String actualValue = builder.toString();
279 if (trimText) {
280 actualValue = actualValue.trim();
281 }
282 assertEquals(expectedText, actualValue);
283 }
284
285 public static void assertSinkEquals(Iterator<SinkEventElement> it, String... names) {
286 StringBuilder expected = new StringBuilder();
287 StringBuilder actual = new StringBuilder();
288
289 for (String name : names) {
290 expected.append(name).append('\n');
291 }
292
293 while (it.hasNext()) {
294 actual.append(it.next().getName()).append('\n');
295 }
296
297 Assertions.assertEquals(expected.toString(), actual.toString());
298 }
299
300 public static void assertSinkStartsWith(Iterator<SinkEventElement> it, String... names) {
301 StringBuilder expected = new StringBuilder();
302 StringBuilder actual = new StringBuilder();
303
304 for (String name : names) {
305 expected.append(name).append('\n');
306 if (it.hasNext()) {
307 actual.append(it.next().getName()).append('\n');
308 }
309 }
310 Assertions.assertEquals(expected.toString(), actual.toString());
311 }
312 }