1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jaxp.library;
  24 
  25 import java.io.ByteArrayInputStream;
  26 import java.io.IOException;
  27 import java.io.InputStream;
  28 import java.nio.ByteBuffer;
  29 import java.nio.ByteOrder;
  30 import java.nio.charset.UnsupportedCharsetException;
  31 import java.nio.file.Files;
  32 import java.nio.file.Paths;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 import java.util.stream.Collectors;
  36 import javax.xml.parsers.DocumentBuilder;
  37 import javax.xml.parsers.DocumentBuilderFactory;
  38 import javax.xml.parsers.ParserConfigurationException;
  39 import static org.testng.Assert.fail;
  40 import org.w3c.dom.Document;
  41 import org.xml.sax.SAXException;
  42 
  43 /**
  44  * This is an interface provide basic support for JAXP functional test.
  45  */
  46 public class JAXPTestUtilities {
  47     /**
  48      * Prefix for error message.
  49      */
  50     public static final String ERROR_MSG_HEADER = "Unexcepted exception thrown:";
  51 
  52     /**
  53      * Prefix for error message on clean up block.
  54      */
  55     public static final String ERROR_MSG_CLEANUP = "Clean up failed on %s";
  56 
  57     /**
  58      * Force using slash as File separator as we always use cygwin to test in
  59      * Windows platform.
  60      */
  61     public static final String FILE_SEP = "/";
  62 
  63     /**
  64      * User home.
  65      */
  66     public static final String USER_DIR = System.getProperty("user.dir", ".");
  67 
  68     /**
  69      * TEMP file directory.
  70      */
  71     public static final String TEMP_DIR = System.getProperty("java.io.tmpdir", ".");
  72 
  73     /**
  74      * BOM table for storing BOM header.
  75      */
  76     private final static Map<String, byte[]> bom = new HashMap();
  77 
  78     /**
  79      * Initialize all BOM headers.
  80      */
  81     static {
  82         bom.put("UTF-8", new byte[]{(byte)0xEF, (byte) 0xBB, (byte) 0xBF});
  83         bom.put("UTF-16BE", new byte[]{(byte)0xFE, (byte)0xFF});
  84         bom.put("UTF-16LE", new byte[]{(byte)0xFF, (byte)0xFE});
  85         bom.put("UTF-32BE", new byte[]{(byte)0x00, (byte)0x00, (byte)0xFE, (byte)0xFF});
  86         bom.put("UTF-32LE", new byte[]{(byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x00});
  87     }
  88 
  89     /**
  90      * Compare contents of golden file with test output file line by line.
  91      * return true if they're identical.
  92      * @param goldfile Golden output file name
  93      * @param outputfile Test output file name
  94      * @return true if two files are identical.
  95      *         false if two files are not identical.
  96      * @throws IOException if an I/O error occurs reading from the file or a
  97      *         malformed or unmappable byte sequence is read
  98      */
  99     public static boolean compareWithGold(String goldfile, String outputfile)
 100             throws IOException {
 101         return Files.readAllLines(Paths.get(goldfile)).
 102                 equals(Files.readAllLines(Paths.get(outputfile)));
 103     }
 104 
 105     /**
 106      * Compare contents of golden file with test output file by their document
 107      * representation.
 108      * Here we ignore the white space and comments. return true if they're
 109      * lexical identical.
 110      * @param goldfile Golden output file name.
 111      * @param resultFile Test output file name.
 112      * @return true if two file's document representation are identical.
 113      *         false if two file's document representation are not identical.
 114      * @throws javax.xml.parsers.ParserConfigurationException if the
 115      *         implementation is not available or cannot be instantiated.
 116      * @throws SAXException If any parse errors occur.
 117      * @throws IOException if an I/O error occurs reading from the file or a
 118      *         malformed or unmappable byte sequence is read .
 119      */
 120     public static boolean compareDocumentWithGold(String goldfile, String resultFile)
 121             throws ParserConfigurationException, SAXException, IOException {
 122         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 123         factory.setNamespaceAware(true);
 124         factory.setCoalescing(true);
 125         factory.setIgnoringElementContentWhitespace(true);
 126         factory.setIgnoringComments(true);
 127         DocumentBuilder db = factory.newDocumentBuilder();
 128 
 129         Document goldD = db.parse(Paths.get(goldfile).toFile());
 130         goldD.normalizeDocument();
 131         Document resultD = db.parse(Paths.get(resultFile).toFile());
 132         resultD.normalizeDocument();
 133         return goldD.isEqualNode(resultD);
 134     }
 135     /**
 136      * Convert stream to ByteArrayInputStream by given character set.
 137      * @param charset target character set.
 138      * @param file a file that contains no BOM head content.
 139      * @return a ByteArrayInputStream contains BOM heads and bytes in original
 140      *         stream
 141      * @throws IOException I/O operation failed or unsupported character set.
 142      */
 143     public static InputStream bomStream(String charset, String file)
 144             throws IOException {
 145         String localCharset = charset;
 146         if (charset.equals("UTF-16") || charset.equals("UTF-32")) {
 147             localCharset
 148                 += ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? "BE" : "LE";
 149         }
 150         if (!bom.containsKey(localCharset))
 151             throw new UnsupportedCharsetException("Charset:" + localCharset);
 152 
 153         byte[] content = Files.readAllLines(Paths.get(file)).stream().
 154                 collect(Collectors.joining()).getBytes(localCharset);
 155         byte[] head = bom.get(localCharset);
 156         ByteBuffer bb = ByteBuffer.allocate(content.length + head.length);
 157         bb.put(head);
 158         bb.put(content);
 159         return new ByteArrayInputStream(bb.array());
 160     }
 161 
 162     /**
 163      * Prints error message if an exception is thrown
 164      * @param ex The exception is thrown by test.
 165      */
 166     public static void failUnexpected(Throwable ex) {
 167         fail(ERROR_MSG_HEADER, ex);
 168     }
 169 
 170     /**
 171      * Prints error message if an exception is thrown when clean up a file.
 172      * @param ex The exception is thrown in cleaning up a file.
 173      * @param name Cleaning up file name.
 174      */
 175     public static void failCleanup(IOException ex, String name) {
 176         fail(String.format(ERROR_MSG_CLEANUP, name), ex);
 177     }
 178 }