Coverage Report - com.jcabi.matchers.XhtmlMatchers
 
Classes in this File Line Coverage Branch Coverage Complexity
XhtmlMatchers
78%
26/33
68%
11/16
2.143
 
 1  
 /**
 2  
  * Copyright (c) 2011-2014, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.matchers;
 31  
 
 32  
 import com.jcabi.xml.XPathContext;
 33  
 import java.io.InputStream;
 34  
 import java.io.InputStreamReader;
 35  
 import java.io.Reader;
 36  
 import java.io.UnsupportedEncodingException;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Collection;
 39  
 import java.util.Scanner;
 40  
 import javax.xml.namespace.NamespaceContext;
 41  
 import javax.xml.transform.Source;
 42  
 import lombok.EqualsAndHashCode;
 43  
 import lombok.ToString;
 44  
 import org.hamcrest.Matcher;
 45  
 import org.hamcrest.Matchers;
 46  
 import org.w3c.dom.Node;
 47  
 
 48  
 /**
 49  
  * Convenient set of matchers for XHTML/XML content.
 50  
  *
 51  
  * <p>For example:
 52  
  *
 53  
  * <pre> MatcherAssert.assertThat(
 54  
  *   "&lt;root&gt;&lt;a&gt;hello&lt;/a&gt;&lt;/root&gt;",
 55  
  *   XhtmlMatchers.hasXPath("/root/a[.='hello']")
 56  
  * );</pre>
 57  
  *
 58  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 59  
  * @version $Id$
 60  
  * @since 0.2.6
 61  
  */
 62  0
 @ToString
 63  0
 @EqualsAndHashCode
 64  
 public final class XhtmlMatchers {
 65  
 
 66  
     /**
 67  
      * Private ctor, it's a utility class.
 68  
      */
 69  0
     private XhtmlMatchers() {
 70  
         // intentionally empty
 71  0
     }
 72  
 
 73  
     /**
 74  
      * Makes XHTML source presentable for testing.
 75  
      *
 76  
      * <p>Useful method for assertions in unit tests. For example:
 77  
      *
 78  
      * <pre> MatcherAssert.assertThat(
 79  
      *   XhtmlMatchers.xhtml(dom_xml_element),
 80  
      *   XhtmlMatchers.hasXPath("/root/data")
 81  
      * );</pre>
 82  
      *
 83  
      * <p>The method understands different input types differently. For example,
 84  
      * an {@link InputStream} will be read as a UTF-8 document, {@link Reader}
 85  
      * will be read as a document, a {@link Source} will be used "as is",
 86  
      * {@link Node} will be printed as a text, etc. The goal is to make any
 87  
      * input type presentable as an XML document, as much as it is possible.
 88  
      *
 89  
      * @param xhtml The source of data
 90  
      * @return Renderable source
 91  
      * @param <T> Type of source
 92  
      * @since 0.4.10
 93  
      */
 94  
     public static <T> Source xhtml(final T xhtml) {
 95  
         Source source;
 96  34
         if (xhtml instanceof Source) {
 97  5
             source = Source.class.cast(xhtml);
 98  29
         } else if (xhtml instanceof InputStream) {
 99  1
             final InputStream stream = InputStream.class.cast(xhtml);
 100  
             try {
 101  1
                 source = new StringSource(
 102  
                     readAsString(new InputStreamReader(stream, "UTF-8"))
 103  
                 );
 104  0
             } catch (final UnsupportedEncodingException ex) {
 105  0
                 throw new IllegalStateException(ex);
 106  1
             }
 107  1
         } else if (xhtml instanceof Reader) {
 108  1
             final Reader reader = Reader.class.cast(xhtml);
 109  1
             source = new StringSource(readAsString(reader));
 110  1
         } else if (xhtml instanceof Node) {
 111  1
             source = new StringSource(Node.class.cast(xhtml));
 112  
         } else {
 113  26
             source = new StringSource(xhtml.toString());
 114  
         }
 115  34
         return source;
 116  
     }
 117  
 
 118  
     /**
 119  
      * Matches content against XPath query.
 120  
      * @param query The query
 121  
      * @return Matcher suitable for JUnit/Hamcrest matching
 122  
      * @param <T> Type of XML content provided
 123  
      */
 124  
     public static <T> Matcher<T> hasXPath(final String query) {
 125  17
         return XhtmlMatchers.hasXPath(query, new XPathContext());
 126  
     }
 127  
 
 128  
     /**
 129  
      * Matches content against XPath query, with custom namespaces.
 130  
      *
 131  
      * <p>Every namespace from the {@code namespaces} list will be assigned to
 132  
      * its own prefix, in order of appearance. Start with {@code 1}.
 133  
      * For example:
 134  
      *
 135  
      * <pre> MatcherAssert.assert(
 136  
      *   "&lt;foo xmlns='my-namespace'&gt;&lt;/foo&gt;",
 137  
      *   XhtmlMatchers.hasXPath("/ns1:foo", "my-namespace")
 138  
      * );</pre>
 139  
      *
 140  
      * @param query The query
 141  
      * @param namespaces List of namespaces
 142  
      * @return Matcher suitable for JUnit/Hamcrest matching
 143  
      * @param <T> Type of XML content provided
 144  
      */
 145  
     public static <T> Matcher<T> hasXPath(final String query,
 146  
         final Object... namespaces) {
 147  5
         return XhtmlMatchers.hasXPath(query, new XPathContext(namespaces));
 148  
     }
 149  
 
 150  
     /**
 151  
      * Matches content against XPath query, with custom context.
 152  
      * @param query The query
 153  
      * @param ctx The context
 154  
      * @return Matcher suitable for JUnit/Hamcrest matching
 155  
      * @param <T> Type of XML content provided
 156  
      */
 157  
     public static <T> Matcher<T> hasXPath(final String query,
 158  
         final NamespaceContext ctx) {
 159  34
         return new XPathMatcher<T>(query, ctx);
 160  
     }
 161  
 
 162  
     /**
 163  
      * Matches content against list of XPaths.
 164  
      * @param xpaths The query
 165  
      * @return Matcher suitable for JUnit/Hamcrest matching
 166  
      * @param <T> Type of XML content provided
 167  
      */
 168  
     public static <T> Matcher<T> hasXPaths(final String...xpaths) {
 169  1
         final Collection<Matcher<? super T>> list =
 170  
             new ArrayList<Matcher<? super T>>(xpaths.length);
 171  3
         for (final String xpath : xpaths) {
 172  2
             list.add(XhtmlMatchers.<T>hasXPath(xpath));
 173  
         }
 174  1
         return Matchers.allOf(list);
 175  
     }
 176  
 
 177  
     /**
 178  
      * Reads an entire reader's contents into a string.
 179  
      * @param reader The stream to read
 180  
      * @return The reader content, in String form
 181  
      */
 182  
     private static String readAsString(final Reader reader) {
 183  
         @SuppressWarnings("resource")
 184  2
         final Scanner scanner =
 185  
             new Scanner(reader).useDelimiter("\\A");
 186  
         final String result;
 187  
         try {
 188  2
             if (scanner.hasNext()) {
 189  2
                 result = scanner.next();
 190  
             } else {
 191  0
                 result = "";
 192  
             }
 193  
         } finally {
 194  2
             scanner.close();
 195  2
         }
 196  2
         return result;
 197  
     }
 198  
 }