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