1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package com.jcabi.xml;
31
32 import java.io.ByteArrayInputStream;
33 import java.nio.charset.StandardCharsets;
34 import java.security.SecureRandom;
35 import java.util.Collection;
36 import java.util.Random;
37 import java.util.concurrent.Callable;
38 import java.util.concurrent.ExecutorService;
39 import java.util.concurrent.Executors;
40 import java.util.concurrent.TimeUnit;
41 import javax.xml.transform.dom.DOMSource;
42 import javax.xml.transform.stream.StreamSource;
43 import org.apache.commons.lang3.RandomStringUtils;
44 import org.apache.commons.lang3.StringUtils;
45 import org.hamcrest.MatcherAssert;
46 import org.hamcrest.Matchers;
47 import org.junit.jupiter.api.Test;
48 import org.xml.sax.SAXParseException;
49
50
51
52
53
54
55 final class XSDDocumentTest {
56
57 @Test
58 void validatesXml() {
59 final XSD xsd = new XSDDocument(
60 new ByteArrayInputStream(
61 StringUtils.join(
62 "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' >",
63 "<xs:element name='test'/>",
64 " </xs:schema>"
65 ).getBytes()
66 )
67 );
68 MatcherAssert.assertThat(
69 xsd.validate(new DOMSource(new XMLDocument("<test/>").node())),
70 Matchers.empty()
71 );
72 MatcherAssert.assertThat(
73 xsd.validate(
74 new DOMSource(new XMLDocument("<test></test>").node())
75 ),
76 Matchers.empty()
77 );
78 }
79
80 @Test
81 void detectsSchemaViolations() {
82 final String xsd = StringUtils.join(
83 "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>",
84 "<xs:element name='first'/></xs:schema>"
85 );
86 final Collection<SAXParseException> errors =
87 new XSDDocument(xsd).validate(
88 new StreamSource(
89 new ByteArrayInputStream("<second/>".getBytes())
90 )
91 );
92 MatcherAssert.assertThat(
93 errors,
94 Matchers.iterableWithSize(1)
95 );
96 MatcherAssert.assertThat(
97 errors.iterator().next().getLineNumber(),
98 Matchers.greaterThan(0)
99 );
100 }
101
102 @Test
103 @SuppressWarnings({
104 "PMD.AvoidInstantiatingObjectsInLoops",
105 "PMD.InsufficientStringBufferDeclaration"
106 })
107 void validatesComplexXml() throws Exception {
108 final int loopp = 5;
109 final int size = 10_000;
110 final int loop = 100;
111 final int random = 10;
112 final String xsd = StringUtils.join(
113 "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' >",
114 "<xs:element name='root'>",
115 "<xs:complexType><xs:sequence>",
116 "<xs:element name='a' type='xs:string' maxOccurs='unbounded' />",
117 "</xs:sequence></xs:complexType>",
118 "</xs:element></xs:schema>"
119 );
120 final StringBuilder text = new StringBuilder(size)
121 .append("<root>");
122 for (int idx = 0; idx < loop; ++idx) {
123 text.append("\n<a>\t<>&"	
")
124 .append(RandomStringUtils.randomAlphanumeric(random))
125 .append("</a>\n\r \t ");
126 }
127 text.append("</root>");
128 for (int idx = 0; idx < loopp; ++idx) {
129 MatcherAssert.assertThat(
130 new XSDDocument(xsd).validate(
131 new StreamSource(
132 new ByteArrayInputStream(
133 text.toString().getBytes(StandardCharsets.UTF_8)
134 )
135 )
136 ),
137 Matchers.empty()
138 );
139 }
140 }
141
142 @Test
143 void validatesLongXml() throws Exception {
144 final XSD xsd = new XSDDocument(
145 this.getClass().getResource("sample.xsd")
146 );
147 MatcherAssert.assertThat(
148 xsd.validate(
149 new DOMSource(
150 new XMLDocument(
151 StringUtils.join(
152 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
153 "<payment><id>333</id>",
154 "<date>1-Jan-2013</date>",
155 "<debit>test-1</debit>",
156 "<credit>test-2</credit>",
157 "</payment>"
158 )
159 ).node()
160 )
161 ),
162 Matchers.empty()
163 );
164 }
165
166 @Test
167 void validatesMultipleXmlsInThreads() throws Exception {
168 final int random = 100;
169 final int loop = 10;
170 final int timeout = 30;
171 final Random rand = new SecureRandom();
172 final XSD xsd = new XSDDocument(
173 StringUtils.join(
174 "<xs:schema xmlns:xs ='http://www.w3.org/2001/XMLSchema' >",
175 "<xs:element name='r'><xs:complexType>",
176 "<xs:sequence>",
177 "<xs:element name='x' type='xs:integer'",
178 " minOccurs='0' maxOccurs='unbounded'/>",
179 "</xs:sequence></xs:complexType></xs:element>",
180 "</xs:schema>"
181 )
182 );
183
184 final Callable<Void> callable = new Callable<Void>() {
185 @Override
186 public Void call() throws Exception {
187 final int cnt = rand.nextInt(random);
188 MatcherAssert.assertThat(
189 xsd.validate(
190 new DOMSource(
191 new XMLDocument(
192 StringUtils.join(
193 "<r>",
194 StringUtils.repeat("<x>hey</x>", cnt),
195 "</r>"
196 )
197 ).node()
198 )
199 ),
200 Matchers.hasSize(cnt << 1)
201 );
202 return null;
203 }
204 };
205 final ExecutorService service = Executors.newFixedThreadPool(5);
206 for (int count = 0; count < loop; count += 1) {
207 service.submit(callable);
208 }
209 service.shutdown();
210 MatcherAssert.assertThat(
211 service.awaitTermination(timeout, TimeUnit.SECONDS),
212 Matchers.is(true)
213 );
214 service.shutdownNow();
215 }
216
217 }