1package im.conversations.android.xmpp;
2
3import static org.hamcrest.CoreMatchers.instanceOf;
4import static org.hamcrest.MatcherAssert.assertThat;
5import static org.junit.Assert.assertNull;
6
7import eu.siacs.conversations.xml.Element;
8import eu.siacs.conversations.xmpp.manager.DiscoManager;
9import im.conversations.android.xml.XmlElementReader;
10import im.conversations.android.xmpp.model.disco.info.InfoQuery;
11import im.conversations.android.xmpp.model.stanza.Iq;
12import java.io.IOException;
13import java.nio.charset.StandardCharsets;
14import org.junit.Assert;
15import org.junit.Test;
16import org.junit.runner.RunWith;
17import org.robolectric.RobolectricTestRunner;
18import org.robolectric.annotation.ConscryptMode;
19
20@RunWith(RobolectricTestRunner.class)
21@ConscryptMode(ConscryptMode.Mode.OFF)
22public class EntityCapabilitiesTest {
23
24 @Test
25 public void entityCaps() throws IOException {
26 final String xml =
27 """
28 <query xmlns='http://jabber.org/protocol/disco#info'
29 node='http://code.google.com/p/exodus#QgayPKawpkPSDYmwT/WM94uAlu0='>
30 <identity category='client' name='Exodus 0.9.1' type='pc'/>
31 <feature var='http://jabber.org/protocol/caps'/>
32 <feature var='http://jabber.org/protocol/disco#items'/>
33 <feature var='http://jabber.org/protocol/disco#info'/>
34 <feature var='http://jabber.org/protocol/muc'/>
35 </query>""";
36 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
37 assertThat(element, instanceOf(InfoQuery.class));
38 final InfoQuery info = (InfoQuery) element;
39 final String var = EntityCapabilities.hash(info).encoded();
40 Assert.assertEquals("QgayPKawpkPSDYmwT/WM94uAlu0=", var);
41 }
42
43 @Test
44 public void entityCapsComplexExample() throws IOException {
45 final String xml =
46 """
47 <query xmlns='http://jabber.org/protocol/disco#info'
48 node='http://psi-im.org#q07IKJEyjvHSyhy//CH0CxmKi8w='>
49 <identity xml:lang='en' category='client' name='Psi 0.11' type='pc'/>
50 <identity xml:lang='el' category='client' name='Ψ 0.11' type='pc'/>
51 <feature var='http://jabber.org/protocol/caps'/>
52 <feature var='http://jabber.org/protocol/disco#info'/>
53 <feature var='http://jabber.org/protocol/disco#items'/>
54 <feature var='http://jabber.org/protocol/muc'/>
55 <x xmlns='jabber:x:data' type='result'>
56 <field var='FORM_TYPE' type='hidden'>
57 <value>urn:xmpp:dataforms:softwareinfo</value>
58 </field>
59 <field var='ip_version' type='text-multi' >
60 <value>ipv4</value>
61 <value>ipv6</value>
62 </field>
63 <field var='os'>
64 <value>Mac</value>
65 </field>
66 <field var='os_version'>
67 <value>10.5.1</value>
68 </field>
69 <field var='software'>
70 <value>Psi</value>
71 </field>
72 <field var='software_version'>
73 <value>0.11</value>
74 </field>
75 </x>
76 </query>""";
77 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
78 assertThat(element, instanceOf(InfoQuery.class));
79 final InfoQuery info = (InfoQuery) element;
80 final String var = EntityCapabilities.hash(info).encoded();
81 Assert.assertEquals("q07IKJEyjvHSyhy//CH0CxmKi8w=", var);
82 }
83
84 @Test
85 public void entityCapsOpenFireOrg() throws IOException {
86 final String xml =
87 """
88 <iq type="result" xmlns="jabber:client" to="inputmice3@igniterealtime.org/Conversations.cI4W" from="igniterealtime.org" id="L3xl8X8_kzvx">
89 <query node="https://www.igniterealtime.org/projects/openfire/#Cd91QBSG4JGOCEvRsSz64xeJPMk=" xmlns="http://jabber.org/protocol/disco#info">
90 <identity name="Openfire Server" type="im" category="server" xmlns="http://jabber.org/protocol/disco#info"/>
91 <identity type="pep" category="pubsub" xmlns="http://jabber.org/protocol/disco#info"/>
92 <feature var="urn:xmpp:raa:0#embed-presence-directed" xmlns="http://jabber.org/protocol/disco#info"/>
93 <feature var="http://jabber.org/protocol/caps" xmlns="http://jabber.org/protocol/disco#info"/>
94 <feature var="http://jabber.org/protocol/pubsub#retrieve-default" xmlns="http://jabber.org/protocol/disco#info"/>
95 <feature var="http://jabber.org/protocol/pubsub#purge-nodes" xmlns="http://jabber.org/protocol/disco#info"/>
96 <feature var="http://jabber.org/protocol/pubsub#subscription-options" xmlns="http://jabber.org/protocol/disco#info"/>
97 <feature var="urn:xmpp:raa:0#embed-message " xmlns="http://jabber.org/protocol/disco#info"/>
98 <feature var="http://jabber.org/protocol/pubsub#outcast-affiliation" xmlns="http://jabber.org/protocol/disco#info"/>
99 <feature var="msgoffline" xmlns="http://jabber.org/protocol/disco#info"/>
100 <feature var="http://jabber.org/protocol/pubsub#delete-nodes" xmlns="http://jabber.org/protocol/disco#info"/>
101 <feature var="jabber:iq:register" xmlns="http://jabber.org/protocol/disco#info"/>
102 <feature var="http://jabber.org/protocol/pubsub#config-node" xmlns="http://jabber.org/protocol/disco#info"/>
103 <feature var="http://jabber.org/protocol/pubsub#retrieve-items" xmlns="http://jabber.org/protocol/disco#info"/>
104 <feature var="http://jabber.org/protocol/pubsub#auto-create" xmlns="http://jabber.org/protocol/disco#info"/>
105 <feature var="http://jabber.org/protocol/disco#items" xmlns="http://jabber.org/protocol/disco#info"/>
106 <feature var="http://jabber.org/protocol/pubsub#delete-items" xmlns="http://jabber.org/protocol/disco#info"/>
107 <feature var="urn:xmpp:mam:0" xmlns="http://jabber.org/protocol/disco#info"/>
108 <feature var="urn:xmpp:mam:1" xmlns="http://jabber.org/protocol/disco#info"/>
109 <feature var="urn:xmpp:mam:2" xmlns="http://jabber.org/protocol/disco#info"/>
110 <feature var="urn:xmpp:fulltext:0" xmlns="http://jabber.org/protocol/disco#info"/>
111 <feature var="http://jabber.org/protocol/pubsub#persistent-items" xmlns="http://jabber.org/protocol/disco#info"/>
112 <feature var="http://jabber.org/protocol/pubsub#create-and-configure" xmlns="http://jabber.org/protocol/disco#info"/>
113 <feature var="http://jabber.org/protocol/pubsub#retrieve-affiliations" xmlns="http://jabber.org/protocol/disco#info"/>
114 <feature var="urn:xmpp:time" xmlns="http://jabber.org/protocol/disco#info"/>
115 <feature var="http://jabber.org/protocol/pubsub#manage-subscriptions" xmlns="http://jabber.org/protocol/disco#info"/>
116 <feature var="urn:xmpp:bookmarks-conversion:0" xmlns="http://jabber.org/protocol/disco#info"/>
117 <feature var="http://jabber.org/protocol/pubsub#auto-subscribe" xmlns="http://jabber.org/protocol/disco#info"/>
118 <feature var="http://jabber.org/protocol/offline" xmlns="http://jabber.org/protocol/disco#info"/>
119 <feature var="http://jabber.org/protocol/pubsub#publish-options" xmlns="http://jabber.org/protocol/disco#info"/>
120 <feature var="urn:xmpp:carbons:2" xmlns="http://jabber.org/protocol/disco#info"/>
121 <feature var="http://jabber.org/protocol/address" xmlns="http://jabber.org/protocol/disco#info"/>
122 <feature var="http://jabber.org/protocol/pubsub#collections" xmlns="http://jabber.org/protocol/disco#info"/>
123 <feature var="http://jabber.org/protocol/pubsub#retrieve-subscriptions" xmlns="http://jabber.org/protocol/disco#info"/>
124 <feature var="vcard-temp" xmlns="http://jabber.org/protocol/disco#info"/>
125 <feature var="http://jabber.org/protocol/pubsub#subscribe" xmlns="http://jabber.org/protocol/disco#info"/>
126 <feature var="http://jabber.org/protocol/pubsub#create-nodes" xmlns="http://jabber.org/protocol/disco#info"/>
127 <feature var="http://jabber.org/protocol/pubsub#get-pending" xmlns="http://jabber.org/protocol/disco#info"/>
128 <feature var="urn:xmpp:blocking" xmlns="http://jabber.org/protocol/disco#info"/>
129 <feature var="http://jabber.org/protocol/pubsub#multi-subscribe" xmlns="http://jabber.org/protocol/disco#info"/>
130 <feature var="http://jabber.org/protocol/pubsub#presence-notifications" xmlns="http://jabber.org/protocol/disco#info"/>
131 <feature var="urn:xmpp:ping" xmlns="http://jabber.org/protocol/disco#info"/>
132 <feature var="urn:xmpp:archive:manage" xmlns="http://jabber.org/protocol/disco#info"/>
133 <feature var="http://jabber.org/protocol/pubsub#filtered-notifications" xmlns="http://jabber.org/protocol/disco#info"/>
134 <feature var="urn:xmpp:push:0" xmlns="http://jabber.org/protocol/disco#info"/>
135 <feature var="http://jabber.org/protocol/pubsub#meta-data" xmlns="http://jabber.org/protocol/disco#info"/>
136 <feature var="http://jabber.org/protocol/pubsub#multi-items" xmlns="http://jabber.org/protocol/disco#info"/>
137 <feature var="http://jabber.org/protocol/pubsub#item-ids" xmlns="http://jabber.org/protocol/disco#info"/>
138 <feature var="jabber:iq:roster" xmlns="http://jabber.org/protocol/disco#info"/>
139 <feature var="http://jabber.org/protocol/pubsub#instant-nodes" xmlns="http://jabber.org/protocol/disco#info"/>
140 <feature var="http://jabber.org/protocol/pubsub#modify-affiliations" xmlns="http://jabber.org/protocol/disco#info"/>
141 <feature var="urn:xmpp:raa:0#embed-presence-sub" xmlns="http://jabber.org/protocol/disco#info"/>
142 <feature var="http://jabber.org/protocol/pubsub" xmlns="http://jabber.org/protocol/disco#info"/>
143 <feature var="http://jabber.org/protocol/pubsub#publisher-affiliation" xmlns="http://jabber.org/protocol/disco#info"/>
144 <feature var="http://jabber.org/protocol/pubsub#access-open" xmlns="http://jabber.org/protocol/disco#info"/>
145 <feature var="jabber:iq:version" xmlns="http://jabber.org/protocol/disco#info"/>
146 <feature var="http://jabber.org/protocol/pubsub#retract-items" xmlns="http://jabber.org/protocol/disco#info"/>
147 <feature var="urn:xmpp:extdisco:1" xmlns="http://jabber.org/protocol/disco#info"/>
148 <feature var="jabber:iq:privacy" xmlns="http://jabber.org/protocol/disco#info"/>
149 <feature var="urn:xmpp:extdisco:2" xmlns="http://jabber.org/protocol/disco#info"/>
150 <feature var="http://jabber.org/protocol/commands" xmlns="http://jabber.org/protocol/disco#info"/>
151 <feature var="jabber:iq:last" xmlns="http://jabber.org/protocol/disco#info"/>
152 <feature var="urn:xmpp:raa:0" xmlns="http://jabber.org/protocol/disco#info"/>
153 <feature var="http://jabber.org/protocol/pubsub#publish" xmlns="http://jabber.org/protocol/disco#info"/>
154 <feature var="urn:xmpp:serverinfo:0" xmlns="http://jabber.org/protocol/disco#info"/>
155 <feature var="urn:xmpp:archive:auto" xmlns="http://jabber.org/protocol/disco#info"/>
156 <feature var="http://jabber.org/protocol/disco#info" xmlns="http://jabber.org/protocol/disco#info"/>
157 <feature var="jabber:iq:private" xmlns="http://jabber.org/protocol/disco#info"/>
158 <feature var="http://jabber.org/protocol/rsm" xmlns="http://jabber.org/protocol/disco#info"/>
159 <x type="result" xmlns="jabber:x:data">
160 <field var="FORM_TYPE" type="hidden" xmlns="jabber:x:data">
161 <value xmlns="jabber:x:data">urn:xmpp:dataforms:softwareinfo</value>
162 </field>
163 <field var="os" type="text-single" xmlns="jabber:x:data">
164 <value xmlns="jabber:x:data">Linux</value>
165 </field>
166 <field var="os_version" type="text-single" xmlns="jabber:x:data">
167 <value xmlns="jabber:x:data">4.14.355-276.618.amzn2.x86_64 amd64 - Java 17.0.14</value>
168 </field>
169 <field var="software" type="text-single" xmlns="jabber:x:data">
170 <value xmlns="jabber:x:data">Openfire</value>
171 </field>
172 <field var="software_version" type="text-single" xmlns="jabber:x:data">
173 <value xmlns="jabber:x:data">5.0.0 Alpha</value>
174 </field>
175 </x>
176 <x type="result" xmlns="jabber:x:data">
177 <field var="FORM_TYPE" type="hidden" xmlns="jabber:x:data">
178 <value xmlns="jabber:x:data">http://jabber.org/network/serverinfo</value>
179 </field>
180 <field var="admin-addresses" type="list-multi" xmlns="jabber:x:data">
181 <value xmlns="jabber:x:data">xmpp:dwd@dave.cridland.net</value>
182 <value xmlns="jabber:x:data">xmpp:akrherz@igniterealtime.org</value>
183 <value xmlns="jabber:x:data">xmpp:benjamin@igniterealtime.org</value>
184 <value xmlns="jabber:x:data">mailto:benjamin@holyarmy.org</value>
185 <value xmlns="jabber:x:data">xmpp:csh@igniterealtime.org</value>
186 <value xmlns="jabber:x:data">xmpp:dan.caseley@igniterealtime.org</value>
187 <value xmlns="jabber:x:data">mailto:dan.caseley@surevine.com</value>
188 <value xmlns="jabber:x:data">xmpp:flow@igniterealtime.org</value>
189 <value xmlns="jabber:x:data">xmpp:gdt@igniterealtime.org</value>
190 <value xmlns="jabber:x:data">mailto:greg.d.thomas@gmail.com</value>
191 <value xmlns="jabber:x:data">xmpp:guus.der.kinderen@igniterealtime.org</value>
192 <value xmlns="jabber:x:data">mailto:guus.der.kinderen@gmail.com</value>
193 <value xmlns="jabber:x:data">xmpp:lg@igniterealtime.org</value>
194 <value xmlns="jabber:x:data">xmpp:rcollier@igniterealtime.org</value>
195 <value xmlns="jabber:x:data">mailto:robincollier@hotmail.com</value>
196 </field>
197 </x>
198 </query>
199</iq>
200""";
201 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
202 assertThat(element, instanceOf(Iq.class));
203 final var iq = (Iq) element;
204 final InfoQuery info = iq.getExtension(InfoQuery.class);
205 final String var = EntityCapabilities.hash(info).encoded();
206 Assert.assertEquals("Cd91QBSG4JGOCEvRsSz64xeJPMk=", var);
207 }
208
209 @Test
210 public void entityCapsOpenFireTestServer() throws IOException {
211 final String xml =
212 """
213<iq type="result" id="779-6" to="jane@example.org" xmlns="jabber:client">
214 <query xmlns="http://jabber.org/protocol/disco#info">
215 <identity category="server" name="Openfire Server" type="im"/>
216 <identity category="pubsub" type="pep"/>
217 <feature var="http://jabber.org/protocol/caps"/>
218 <feature var="http://jabber.org/protocol/pubsub#retrieve-default"/>
219 <feature var="http://jabber.org/protocol/pubsub#purge-nodes"/>
220 <feature var="http://jabber.org/protocol/pubsub#subscription-options"/>
221 <feature var="http://jabber.org/protocol/pubsub#outcast-affiliation"/>
222 <feature var="msgoffline"/>
223 <feature var="jabber:iq:register"/>
224 <feature var="http://jabber.org/protocol/pubsub#delete-nodes"/>
225 <feature var="http://jabber.org/protocol/pubsub#config-node"/>
226 <feature var="http://jabber.org/protocol/pubsub#retrieve-items"/>
227 <feature var="http://jabber.org/protocol/pubsub#auto-create"/>
228 <feature var="http://jabber.org/protocol/pubsub#delete-items"/>
229 <feature var="http://jabber.org/protocol/disco#items"/>
230 <feature var="http://jabber.org/protocol/pubsub#persistent-items"/>
231 <feature var="http://jabber.org/protocol/pubsub#create-and-configure"/>
232 <feature var="http://jabber.org/protocol/pubsub#retrieve-affiliations"/>
233 <feature var="urn:xmpp:time"/>
234 <feature var="http://jabber.org/protocol/pubsub#manage-subscriptions"/>
235 <feature var="urn:xmpp:bookmarks-conversion:0"/>
236 <feature var="http://jabber.org/protocol/offline"/>
237 <feature var="http://jabber.org/protocol/pubsub#auto-subscribe"/>
238 <feature var="http://jabber.org/protocol/pubsub#publish-options"/>
239 <feature var="urn:xmpp:carbons:2"/>
240 <feature var="http://jabber.org/protocol/address"/>
241 <feature var="http://jabber.org/protocol/pubsub#collections"/>
242 <feature var="http://jabber.org/protocol/pubsub#retrieve-subscriptions"/>
243 <feature var="vcard-temp"/>
244 <feature var="http://jabber.org/protocol/pubsub#subscribe"/>
245 <feature var="http://jabber.org/protocol/pubsub#create-nodes"/>
246 <feature var="http://jabber.org/protocol/pubsub#get-pending"/>
247 <feature var="urn:xmpp:blocking"/>
248 <feature var="http://jabber.org/protocol/pubsub#multi-subscribe"/>
249 <feature var="http://jabber.org/protocol/pubsub#presence-notifications"/>
250 <feature var="urn:xmpp:ping"/>
251 <feature var="http://jabber.org/protocol/pubsub#filtered-notifications"/>
252 <feature var="http://jabber.org/protocol/pubsub#item-ids"/>
253 <feature var="http://jabber.org/protocol/pubsub#meta-data"/>
254 <feature var="http://jabber.org/protocol/pubsub#multi-items"/>
255 <feature var="jabber:iq:roster"/>
256 <feature var="http://jabber.org/protocol/pubsub#instant-nodes"/>
257 <feature var="http://jabber.org/protocol/pubsub#modify-affiliations"/>
258 <feature var="http://jabber.org/protocol/pubsub"/>
259 <feature var="http://jabber.org/protocol/pubsub#publisher-affiliation"/>
260 <feature var="http://jabber.org/protocol/pubsub#access-open"/>
261 <feature var="jabber:iq:version"/>
262 <feature var="http://jabber.org/protocol/pubsub#retract-items"/>
263 <feature var="jabber:iq:privacy"/>
264 <feature var="jabber:iq:last"/>
265 <feature var="http://jabber.org/protocol/commands"/>
266 <feature var="http://jabber.org/protocol/pubsub#publish"/>
267 <feature var="http://jabber.org/protocol/disco#info"/>
268 <feature var="jabber:iq:private"/>
269 <feature var="http://jabber.org/protocol/rsm"/>
270 <x xmlns="jabber:x:data" type="result">
271 <field var="FORM_TYPE" type="hidden">
272 <value>http://jabber.org/network/serverinfo</value>
273 </field>
274 <field var="admin-addresses" type="list-multi">
275 <value>xmpp:admin@example.org</value>
276 <value>mailto:admin@example.com</value>
277 </field>
278 </x>
279 <x xmlns="jabber:x:data" type="result">
280 <field var="FORM_TYPE" type="hidden">
281 <value>urn:xmpp:dataforms:softwareinfo</value>
282 </field>
283 <field type="text-single" var="os">
284 <value>Linux</value>
285 </field>
286 <field type="text-single" var="os_version">
287 <value>6.8.0-59-generic amd64 - Java 21.0.7</value>
288 </field>
289 <field type="text-single" var="software">
290 <value>Openfire</value>
291 </field>
292 <field type="text-single" var="software_version">
293 <value>5.0.0 Alpha</value>
294 </field>
295 </x>
296 </query>
297</iq>
298""";
299 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
300 assertThat(element, instanceOf(Iq.class));
301 final var iq = (Iq) element;
302 final InfoQuery info = iq.getExtension(InfoQuery.class);
303 final String var = EntityCapabilities.hash(info).encoded();
304 Assert.assertEquals("3wkXXN9QL/i/AyVoHaqaiTT8BFA=", var);
305 }
306
307 @Test
308 public void caps2() throws IOException {
309 final String xml =
310 """
311 <query xmlns="http://jabber.org/protocol/disco#info">
312 <identity category="client" name="BombusMod" type="mobile"/>
313 <feature var="http://jabber.org/protocol/si"/>
314 <feature var="http://jabber.org/protocol/bytestreams"/>
315 <feature var="http://jabber.org/protocol/chatstates"/>
316 <feature var="http://jabber.org/protocol/disco#info"/>
317 <feature var="http://jabber.org/protocol/disco#items"/>
318 <feature var="urn:xmpp:ping"/>
319 <feature var="jabber:iq:time"/>
320 <feature var="jabber:iq:privacy"/>
321 <feature var="jabber:iq:version"/>
322 <feature var="http://jabber.org/protocol/rosterx"/>
323 <feature var="urn:xmpp:time"/>
324 <feature var="jabber:x:oob"/>
325 <feature var="http://jabber.org/protocol/ibb"/>
326 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
327 <feature var="urn:xmpp:receipts"/>
328 <feature var="jabber:iq:roster"/>
329 <feature var="jabber:iq:last"/>
330 </query>""";
331 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
332 assertThat(element, instanceOf(InfoQuery.class));
333 final InfoQuery info = (InfoQuery) element;
334 final String var = EntityCapabilities2.hash(info).encoded();
335 Assert.assertEquals("kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=", var);
336 }
337
338 @Test
339 public void caps2complex() throws IOException {
340 final String xml =
341 """
342 <query xmlns="http://jabber.org/protocol/disco#info">
343 <identity category="client" name="Tkabber" type="pc" xml:lang="en"/>
344 <identity category="client" name="Ткаббер" type="pc" xml:lang="ru"/>
345 <feature var="games:board"/>
346 <feature var="http://jabber.org/protocol/activity"/>
347 <feature var="http://jabber.org/protocol/activity+notify"/>
348 <feature var="http://jabber.org/protocol/bytestreams"/>
349 <feature var="http://jabber.org/protocol/chatstates"/>
350 <feature var="http://jabber.org/protocol/commands"/>
351 <feature var="http://jabber.org/protocol/disco#info"/>
352 <feature var="http://jabber.org/protocol/disco#items"/>
353 <feature var="http://jabber.org/protocol/evil"/>
354 <feature var="http://jabber.org/protocol/feature-neg"/>
355 <feature var="http://jabber.org/protocol/geoloc"/>
356 <feature var="http://jabber.org/protocol/geoloc+notify"/>
357 <feature var="http://jabber.org/protocol/ibb"/>
358 <feature var="http://jabber.org/protocol/iqibb"/>
359 <feature var="http://jabber.org/protocol/mood"/>
360 <feature var="http://jabber.org/protocol/mood+notify"/>
361 <feature var="http://jabber.org/protocol/rosterx"/>
362 <feature var="http://jabber.org/protocol/si"/>
363 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
364 <feature var="http://jabber.org/protocol/tune"/>
365 <feature var="http://www.facebook.com/xmpp/messages"/>
366 <feature var="http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify"/>
367 <feature var="jabber:iq:avatar"/>
368 <feature var="jabber:iq:browse"/>
369 <feature var="jabber:iq:dtcp"/>
370 <feature var="jabber:iq:filexfer"/>
371 <feature var="jabber:iq:ibb"/>
372 <feature var="jabber:iq:inband"/>
373 <feature var="jabber:iq:jidlink"/>
374 <feature var="jabber:iq:last"/>
375 <feature var="jabber:iq:oob"/>
376 <feature var="jabber:iq:privacy"/>
377 <feature var="jabber:iq:roster"/>
378 <feature var="jabber:iq:time"/>
379 <feature var="jabber:iq:version"/>
380 <feature var="jabber:x:data"/>
381 <feature var="jabber:x:event"/>
382 <feature var="jabber:x:oob"/>
383 <feature var="urn:xmpp:avatar:metadata+notify"/>
384 <feature var="urn:xmpp:ping"/>
385 <feature var="urn:xmpp:receipts"/>
386 <feature var="urn:xmpp:time"/>
387 <x xmlns="jabber:x:data" type="result">
388 <field type="hidden" var="FORM_TYPE">
389 <value>urn:xmpp:dataforms:softwareinfo</value>
390 </field>
391 <field var="software">
392 <value>Tkabber</value>
393 </field>
394 <field var="software_version">
395 <value>0.11.1-svn-20111216-mod (Tcl/Tk 8.6b2)</value>
396 </field>
397 <field var="os">
398 <value>Windows</value>
399 </field>
400 <field var="os_version">
401 <value>XP</value>
402 </field>
403 </x>
404 </query>""";
405 final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
406 assertThat(element, instanceOf(InfoQuery.class));
407 final InfoQuery info = (InfoQuery) element;
408 final String var = EntityCapabilities2.hash(info).encoded();
409 Assert.assertEquals("u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=", var);
410 }
411
412 @Test
413 public void parseCaps2Node() {
414 final var caps =
415 DiscoManager.buildHashFromNode(
416 "urn:xmpp:caps#sha-256.u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
417 assertThat(caps, instanceOf(EntityCapabilities2.EntityCaps2Hash.class));
418 }
419
420 @Test
421 public void parseCaps2NodeMissingHash() {
422 final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#sha-256.");
423 assertNull(caps);
424 }
425
426 @Test
427 public void parseCaps2NodeInvalid() {
428 final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#-");
429 assertNull(caps);
430 }
431
432 @Test
433 public void parseCaps2NodeUnknownAlgo() {
434 final var caps = DiscoManager.buildHashFromNode("urn:xmpp:caps#test.test");
435 assertNull(caps);
436 }
437}