001/* 002 * Shredzone Commons 003 * 004 * Copyright (C) 2014 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Library General Public License as 009 * published by the Free Software Foundation, either version 3 of the 010 * License, or (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU Library General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package org.shredzone.commons.xml; 021 022import static java.util.stream.Collectors.toList; 023import static org.hamcrest.Matchers.*; 024import static org.junit.Assert.assertThat; 025 026import java.io.IOException; 027import java.io.InputStreamReader; 028import java.io.Reader; 029import java.util.List; 030 031import org.junit.Before; 032import org.junit.Test; 033 034/** 035 * Unit tests for {@link XQuery}. 036 * 037 * @author Richard "Shred" Körber 038 */ 039public class XQueryTest { 040 041 private XQuery xq; 042 043 /** 044 * Sets up a new {@link XQuery} instance. 045 */ 046 @Before 047 public void init() throws IOException { 048 xq = XQuery.parse(XQueryTest.class.getResourceAsStream("/test.xml")); 049 } 050 051 /** 052 * Test {@link Reader} based parser. 053 */ 054 @Test 055 public void parserReaderTest() throws IOException { 056 try (Reader r = new InputStreamReader(XQueryTest.class.getResourceAsStream("/test.xml"))) { 057 XQuery result = XQuery.parse(r); 058 assertThat(result, is(notNullValue())); 059 } 060 } 061 062 /** 063 * Test {@link String} based parser. 064 */ 065 @Test 066 public void parserStringTest() throws IOException { 067 XQuery result = XQuery.parse("<test><foo>bar</foo></test>"); 068 assertThat(result, is(notNullValue())); 069 } 070 071 /** 072 * Test parser error on bad XML. 073 */ 074 @Test(expected = IOException.class) 075 public void parserFailTest() throws IOException { 076 XQuery.parse(":-("); 077 } 078 079 /** 080 * Does the {@link XQuery#stream()} of the root {@link XQuery} return the root 081 * element? 082 */ 083 @Test 084 public void streamTest() throws IOException { 085 List<String> tags = xq.stream().map(XQuery::name).collect(toList()); 086 087 assertThat(tags, contains("catalog")); 088 } 089 090 /** 091 * Does the {@link XQuery#stream()} of a subelement return the child elements of that 092 * element? 093 */ 094 @Test 095 public void subStreamTest() throws IOException { 096 XQuery book7 = xq.get("//book[@id='bk7']"); 097 List<String> tags = book7.stream().map(XQuery::name).collect(toList()); 098 099 assertThat(tags, contains("author", "title", "original", "published", "description")); 100 } 101 102 /** 103 * Does {@link XQuery#select(String)} return the correct elements? Does 104 * {@link XQuery#text()} return the text content? 105 */ 106 @Test 107 public void selectTest() throws IOException { 108 List<String> titles = xq.select("//book/original").map(XQuery::text).collect(toList()); 109 110 assertThat(titles, contains("Le Lotus bleu", "L'Île noire", 111 "Le Secret de la Licorne", "Objectif Lune", "Tintin au Tibet")); 112 } 113 114 /** 115 * Does {@link XQuery#get(String)} return a single element? 116 */ 117 @Test 118 public void getTest() throws IOException { 119 XQuery book11 = xq.get("//book[@id='bk11']"); 120 assertThat(book11.attr().get("id"), is("bk11")); 121 } 122 123 /** 124 * Does {@link XQuery#get(String)} throw an exception if there is no such element? 125 */ 126 @Test(expected = IllegalArgumentException.class) 127 public void getNoneFailTest() throws IOException { 128 xq.get("//book[@id='bk9']"); 129 } 130 131 /** 132 * Does {@link XQuery#get(String)} throw an exception if multiple elements are 133 * found? 134 */ 135 @Test(expected = IllegalArgumentException.class) 136 public void getMultipleFailTest() throws IOException { 137 xq.get("//book"); 138 } 139 140 /** 141 * Does {@link XQuery#previousSibling()} and {@link XQuery#nextSibling()} return 142 * the correct siblings? 143 */ 144 @Test 145 public void siblingTest() throws IOException { 146 XQuery book7 = xq.get("//book[@id='bk7']"); 147 148 XQuery book5 = book7.previousSibling().get(); 149 assertThat(book5.attr().get("id"), is("bk5")); 150 assertThat(book5.previousSibling().isPresent(), is(false)); 151 152 XQuery book11 = book7.nextSibling().get(); 153 assertThat(book11.attr().get("id"), is("bk11")); 154 155 XQuery book16 = book11.nextSibling().get(); 156 assertThat(book16.attr().get("id"), is("bk16")); 157 158 XQuery book20 = book16.nextSibling().get(); 159 assertThat(book20.attr().get("id"), is("bk20")); 160 assertThat(book20.nextSibling().isPresent(), is(false)); 161 } 162 163 /** 164 * Does {@link XQuery#exists(String)} return a correct answer. 165 */ 166 @Test 167 public void existsTest() throws IOException { 168 assertThat(xq.exists("//book/original"), is(true)); 169 assertThat(xq.exists("//catfood/brand"), is(false)); 170 } 171 172 /** 173 * Does {@link XQuery#select(String)} fail on bad XPath? 174 */ 175 @Test(expected = IllegalArgumentException.class) 176 public void selectFailTest() throws IOException { 177 xq.select(":-("); 178 } 179 180 /** 181 * Does {@link XQuery#value(String)} return the text contents of the matching 182 * elements? 183 */ 184 @Test 185 public void valueTest() throws IOException { 186 List<String> titles = xq.value("/catalog/book/title").collect(toList()); 187 188 assertThat(titles, contains("The Blue Lotus","The Black Island", 189 "The Secret of the Unicorn", "Destination Moon", 190 "Tintin in Tibet")); 191 } 192 193 /** 194 * Does {@link XQuery#allValue(String)} return the text contents of the matching 195 * elements, recursively? 196 */ 197 @Test 198 public void allValueTest() throws IOException { 199 List<String> dates = xq.value("/catalog/book/published").map(String::trim).collect(toList()); 200 List<String> allDates = xq.allValue("/catalog/book/published").map(String::trim).collect(toList()); 201 202 assertThat(dates, contains("", "", "", "", "")); 203 assertThat(allDates, contains("1936\n 1946", "1938\n 1943\n 1966", 204 "1943", "1953", "1960")); 205 } 206 207 /** 208 * Is {@link XQuery#value(String)} non-recursive, i.e. does it only return the text 209 * of the immediate children? 210 */ 211 @Test 212 public void valueNonRecursiveTest() throws IOException { 213 List<String> dates = xq.value("/catalog/book[@id='bk7']/published") 214 .map(String::trim) 215 .collect(toList()); 216 217 assertThat(dates, contains("")); 218 } 219 220 /** 221 * Does {@link XQuery#select(String)} and {@link XQuery#allText()} return the text 222 * contents of the entire subtree? 223 */ 224 @Test 225 public void value3Test() throws IOException { 226 String dates = xq.select("/catalog/book[@id='bk7']/published") 227 .map(XQuery::allText) 228 .findFirst() 229 .get(); 230 231 assertThat(dates, is("\n 1938\n 1943\n 1966\n ")); 232 } 233 234 /** 235 * Does {@link XQuery#attr()} return a map of attributes? 236 */ 237 @Test 238 public void attrTest() throws IOException { 239 List<String> ids = xq.select("/catalog/book") 240 .map(book -> book.attr().get("id")) 241 .collect(toList()); 242 243 assertThat(ids, contains("bk5", "bk7", "bk11", "bk16", "bk20")); 244 } 245 246 /** 247 * Does {@link XQuery#attr()} return a map of multiple attributes? 248 */ 249 @Test 250 public void attrManyTest() throws IOException { 251 List<XQuery> albums = xq.select("/catalog/book[@id='bk7']/published/album") 252 .collect(toList()); 253 254 assertThat(albums.get(0).attr().size(), is(1)); 255 assertThat(albums.get(0).attr().get("type"), is("bw")); 256 257 assertThat(albums.get(1).attr().size(), is(1)); 258 assertThat(albums.get(1).attr().get("type"), is("color")); 259 260 assertThat(albums.get(2).attr().size(), is(2)); 261 assertThat(albums.get(2).attr().get("type"), is("color")); 262 assertThat(albums.get(2).attr().get("republished"), is("yes")); 263 } 264 265 /** 266 * Does {@link XQuery#attr()} return an empty map of attributes when there are none? 267 */ 268 @Test 269 public void attrEmptyTest() throws IOException { 270 xq.select("/catalog/book/author") 271 .forEach(author -> assertThat(author.attr().keySet(), is(empty()))); 272 assertThat(xq.attr().keySet(), is(empty())); 273 } 274 275 /** 276 * Are comments ignored? 277 */ 278 @Test 279 public void noCommentTest() throws IOException { 280 String text = xq.text("/catalog/book[@id='bk16']/description"); 281 282 assertThat(text, is("Tintin's friend Professor Calculus has been secretly commissioned\n" 283 + " \n" 284 + " by the Syldavian government to build a rocket ship that will fly from the\n" 285 + " Earth to the Moon.")); 286 } 287 288 /** 289 * Are CDATA elements read as text? 290 */ 291 @Test 292 public void cdataTest() throws IOException { 293 String text = xq.text("/catalog/book[@id='bk20']/description"); 294 295 assertThat(text, is("While on holiday at a resort in the French Alps with Snowy,\n" 296 + " Captain Haddock, & Professor Calculus, <Tintin> reads about a plane crash in\n" 297 + " the Gosain Than Massif in the Himalayas of Tibet.")); 298 } 299 300 /** 301 * Does {@link XQuery#parent()} return the correct parent node? 302 */ 303 @Test 304 public void parentTest() throws IOException { 305 XQuery title = xq.get("/catalog/book[@id='bk11']/title"); 306 307 XQuery parent = title.parent().get(); 308 assertThat(parent.name(), is("book")); 309 310 // make sure parent is cached 311 XQuery parent2 = title.parent().get(); 312 assertThat(parent2, is(sameInstance(parent))); 313 } 314 315 /** 316 * Does {@link XQuery#parent()} return empty on root? 317 */ 318 @Test 319 public void parentOfRootTest() throws IOException { 320 assertThat(xq.parent().isPresent(), is(false)); 321 } 322 323 /** 324 * Does {@link XQuery#parent()} return the correct parent node? 325 */ 326 @Test 327 public void rootTest() throws IOException { 328 XQuery title = xq.get("/catalog/book[@id='bk11']/title"); 329 assertThat(title.isRoot(), is(false)); 330 assertThat(title.name(), is("title")); 331 332 XQuery root = title.root(); 333 assertThat(root.isRoot(), is(true)); 334 assertThat(root.name(), is("#document")); 335 } 336 337 /** 338 * Does {@link XQuery#parent()} return empty on root? 339 */ 340 @Test 341 public void rootOfRootTest() throws IOException { 342 assertThat(xq.root(), is(sameInstance(xq))); 343 assertThat(xq.isRoot(), is(true)); 344 } 345 346}