1
2
3
4
5 package com.jcabi.xml;
6
7 import com.jcabi.matchers.XhtmlMatchers;
8 import com.yegor256.Together;
9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.TimeUnit;
12 import org.apache.commons.lang3.StringUtils;
13 import org.hamcrest.MatcherAssert;
14 import org.hamcrest.Matchers;
15 import org.junit.jupiter.api.Assertions;
16 import org.junit.jupiter.api.RepeatedTest;
17 import org.junit.jupiter.api.Test;
18
19
20
21
22
23
24 @SuppressWarnings({"PMD.TooManyMethods", "PMD.JUnitAssertionsShouldIncludeMessage"})
25 final class XSLDocumentTest {
26
27 @Test
28 void makesXslTransformations() {
29 final XSL xsl = new XSLDocument(
30 StringUtils.join(
31 "<xsl:stylesheet",
32 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'",
33 " version='2.0'>",
34 "<xsl:template match='/'><done/>",
35 "</xsl:template></xsl:stylesheet>"
36 )
37 );
38 MatcherAssert.assertThat(
39 xsl.transform(new XMLDocument("<a/>")),
40 XhtmlMatchers.hasXPath("/done")
41 );
42 MatcherAssert.assertThat(
43 xsl.transform(new XMLDocument("<a></a>")),
44 XhtmlMatchers.hasXPath("/done ")
45 );
46 }
47
48 @Test
49 @SuppressWarnings({"PMD.DoNotUseThreads", "PMD.CloseResource"})
50 void makesXslTransformationsInThreads() throws Exception {
51 final int loop = 50;
52 final int timeout = 30;
53 final XSL xsl = new XSLDocument(
54 StringUtils.join(
55 "<xsl:stylesheet ",
56 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform' ",
57 " version='2.0' >",
58 "<xsl:template match='/'><works/>",
59 "</xsl:template> </xsl:stylesheet>"
60 )
61 );
62 final Runnable runnable = () -> MatcherAssert.assertThat(
63 xsl.transform(new XMLDocument("<test/>")),
64 XhtmlMatchers.hasXPath("/works")
65 );
66 final ExecutorService service = Executors.newFixedThreadPool(5);
67 for (int count = 0; count < loop; count += 1) {
68 service.submit(runnable);
69 }
70 service.shutdown();
71 MatcherAssert.assertThat(
72 service.awaitTermination(timeout, TimeUnit.SECONDS),
73 Matchers.is(true)
74 );
75 service.shutdownNow();
76 }
77
78 @Test
79 void transformsWithImports() {
80 final XSL xsl = new XSLDocument(
81 this.getClass().getResourceAsStream("first.xsl")
82 ).with(new ClasspathSources(this.getClass()));
83 MatcherAssert.assertThat(
84 xsl.transform(new XMLDocument("<simple-test/>")),
85 XhtmlMatchers.hasXPath("/result[.=6]")
86 );
87 }
88
89 @Test
90 void transformsWithImportsFromUrl() {
91 final XSL xsl = XSLDocument.make(
92 this.getClass().getResource("first.xsl")
93 ).with(new ClasspathSources(this.getClass()));
94 MatcherAssert.assertThat(
95 xsl.transform(new XMLDocument("<simple-test/>")),
96 XhtmlMatchers.hasXPath("/result[.=6]")
97 );
98 }
99
100 @Test
101 void transformsIntoText() {
102 final XSL xsl = new XSLDocument(
103 StringUtils.join(
104 "<xsl:stylesheet ",
105 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform' ",
106 " version='2.0'><xsl:output method='text'/>",
107 "<xsl:template match='/'>hello</xsl:template></xsl:stylesheet>"
108 )
109 );
110 MatcherAssert.assertThat(
111 xsl.applyTo(new XMLDocument("<something/>")),
112 Matchers.equalTo("hello")
113 );
114 }
115
116 @Test
117 void stripsXml() {
118 MatcherAssert.assertThat(
119 XSLDocument.STRIP.transform(
120 new XMLDocument("<a> <b/> </a>")
121 ).toString(),
122 Matchers.containsString("<a>\n")
123 );
124 }
125
126 @Test
127 void transformsIntoTextWithParams() {
128 final XSL xsl = new XSLDocument(
129 StringUtils.join(
130 "<xsl:stylesheet ",
131 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform' ",
132 " xmlns:xs='http://www.w3.org/2001/XMLSchema'",
133 " version='2.0'><xsl:output method='text' />",
134 "<xsl:param name='boom' />",
135 "<xsl:template match='/'>[<xsl:value-of select='$boom'/>]",
136 "</xsl:template> </xsl:stylesheet>"
137 )
138 );
139 MatcherAssert.assertThat(
140 xsl.with("boom", "Donny").applyTo(new XMLDocument("<ehe/>")),
141 Matchers.equalTo("[Donny]")
142 );
143 }
144
145 @Test
146 void transformsIntoTextWithIntegerParams() {
147 final XSL xsl = new XSLDocument(
148 StringUtils.join(
149 "<xsl:stylesheet ",
150 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform' ",
151 " version='2.0'><xsl:output method='text' />",
152 "<xsl:param name='faa' select='5'/>",
153 "<xsl:template match='/'>+<xsl:value-of select='$faa'/>+",
154 "</xsl:template> </xsl:stylesheet> "
155 )
156 );
157 MatcherAssert.assertThat(
158 xsl.with("faa", 1).applyTo(new XMLDocument("<r0/>")),
159 Matchers.equalTo("+1+")
160 );
161 }
162
163 @Test
164 void catchesXslErrorMessages() {
165 MatcherAssert.assertThat(
166 Assertions.assertThrows(
167 RuntimeException.class,
168 () -> new XSLDocument(
169 StringUtils.join(
170 " <xsl:stylesheet",
171 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'",
172 " version='2.0'><xsl:template match='/'>",
173 "<xsl:message terminate='yes'>",
174 "<xsl:text>oopsie...</xsl:text>",
175 " </xsl:message></xsl:template></xsl:stylesheet>"
176 ),
177 "foo"
178 ).with(new ClasspathSources()).transform(new XMLDocument("<zz1/>"))
179 ).getLocalizedMessage(),
180 Matchers.allOf(
181 Matchers.containsString("Processing terminated by xsl:message"),
182 Matchers.containsString("by xsl:message at line 1 in foo")
183 )
184 );
185 }
186
187 @Test
188 void catchesXslWarningsDuringCompilation() {
189 MatcherAssert.assertThat(
190 Assertions.assertThrows(
191 RuntimeException.class,
192 () ->
193 new XSLDocument(this.getClass().getResourceAsStream("multiple-imports.xsl"))
194 .with(new ClasspathSources(this.getClass()))
195 .transform(new XMLDocument("<f/>")),
196 "Warnings was not thrown, but they should"
197 ).getLocalizedMessage(),
198 Matchers.allOf(
199 Matchers.containsString(
200 "Stylesheet module file:/second.xsl is included or imported more than once"
201 )
202 )
203 );
204 }
205
206 @Test
207 void printsSystemIdInErrorMessages() {
208 MatcherAssert.assertThat(
209 Assertions.assertThrows(
210 RuntimeException.class,
211 () -> new XSLDocument(
212 StringUtils.join(
213 " <xsl:stylesheet",
214 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'",
215 " version='2.0'><xsl:template match='/'>",
216 "<xsl:value-of select='$xx'/></xsl:template>",
217 " </xsl:stylesheet>"
218 ),
219 "some-fake-systemId"
220 ).with(new ClasspathSources()).transform(new XMLDocument("<ooo/>"))
221 ).getLocalizedMessage(),
222 Matchers.containsString(
223 "Failed to create transformer by net.sf.saxon.TransformerFactoryImpl"
224 )
225 );
226 }
227
228 @Test
229 void catchesSaxonWarnings() {
230 new XSLDocument(
231 StringUtils.join(
232 " <xsl:stylesheet",
233 " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'",
234 " version='2.0'>",
235 "<xsl:template match='a'></xsl:template>",
236 "<xsl:template match='a'></xsl:template>",
237 "</xsl:stylesheet>"
238 ),
239 "https://example.com/hello.xsl"
240 ).transform(new XMLDocument("<x><a/></x>"));
241 }
242
243 @RepeatedTest(10)
244 void transformsInManyThreads() throws Exception {
245 final XSL xsl = new XSLDocument(
246 this.getClass().getResourceAsStream("first.xsl")
247 ).with(new ClasspathSources());
248 final XML xml = new XMLDocument(
249 this.getClass().getResourceAsStream("simple.xml")
250 );
251 final int total = 50;
252 MatcherAssert.assertThat(
253 new Together<>(
254 total,
255 t -> xsl.transform(xml)
256 ).asList().size(),
257 Matchers.equalTo(total)
258 );
259 }
260
261 }