Path: blob/master/test/jaxp/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java
42588 views
/*1* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package jaxp.library;2324import static org.testng.Assert.fail;2526import java.io.ByteArrayInputStream;27import java.io.File;28import java.io.IOException;29import java.io.InputStream;30import java.io.StringWriter;31import java.nio.ByteBuffer;32import java.nio.ByteOrder;33import java.nio.charset.Charset;34import java.nio.charset.StandardCharsets;35import java.nio.charset.UnsupportedCharsetException;36import java.nio.file.Files;37import java.nio.file.Paths;38import java.security.Permission;39import java.util.ArrayList;40import java.util.HashMap;41import java.util.List;42import java.util.Map;43import java.util.Optional;44import java.util.concurrent.Callable;45import java.util.concurrent.ConcurrentHashMap;46import java.util.function.Supplier;47import java.util.regex.Pattern;48import java.util.stream.Collectors;4950import javax.xml.parsers.DocumentBuilder;51import javax.xml.parsers.DocumentBuilderFactory;52import javax.xml.parsers.ParserConfigurationException;53import javax.xml.transform.Transformer;54import javax.xml.transform.TransformerException;55import javax.xml.transform.TransformerFactory;56import javax.xml.transform.dom.DOMSource;57import javax.xml.transform.stream.StreamResult;5859import org.w3c.dom.Document;60import org.w3c.dom.Node;61import org.xml.sax.SAXException;6263/**64* This is an interface provide basic support for JAXP functional test.65*/66public class JAXPTestUtilities {67/**68* Prefix for error message.69*/70public static final String ERROR_MSG_HEADER = "Unexcepted exception thrown:";7172/**73* Prefix for error message on clean up block.74*/75public static final String ERROR_MSG_CLEANUP = "Clean up failed on %s";7677/**78* Force using slash as File separator as we always use cygwin to test in79* Windows platform.80*/81public static final String FILE_SEP = "/";8283/**84* A map storing every test's current test file pointer. File number should85* be incremental and it's a thread-safe reading on this file number.86*/87private static final ConcurrentHashMap<Class<?>, Integer> currentFileNumber88= new ConcurrentHashMap<>();8990/**91* BOM table for storing BOM header.92*/93private final static Map<String, byte[]> bom = new HashMap<>();9495/**96* Initialize all BOM headers.97*/98static {99bom.put("UTF-8", new byte[]{(byte)0xEF, (byte) 0xBB, (byte) 0xBF});100bom.put("UTF-16BE", new byte[]{(byte)0xFE, (byte)0xFF});101bom.put("UTF-16LE", new byte[]{(byte)0xFF, (byte)0xFE});102bom.put("UTF-32BE", new byte[]{(byte)0x00, (byte)0x00, (byte)0xFE, (byte)0xFF});103bom.put("UTF-32LE", new byte[]{(byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x00});104}105106/**107* Compare contents of golden file with test output file line by line.108* return true if they're identical.109* @param goldfile Golden output file name110* @param outputfile Test output file name111* @return true if two files are identical.112* false if two files are not identical.113* @throws IOException if an I/O error occurs reading from the file or a114* malformed or unmappable byte sequence is read.115*/116public static boolean compareWithGold(String goldfile, String outputfile)117throws IOException {118return compareWithGold(goldfile, outputfile, StandardCharsets.UTF_8);119}120121/**122* Compare contents of golden file with test output file line by line.123* return true if they're identical.124* @param goldfile Golden output file name.125* @param outputfile Test output file name.126* @param cs the charset to use for decoding.127* @return true if two files are identical.128* false if two files are not identical.129* @throws IOException if an I/O error occurs reading from the file or a130* malformed or unmappable byte sequence is read.131*/132public static boolean compareWithGold(String goldfile, String outputfile,133Charset cs) throws IOException {134boolean isSame = Files.readAllLines(Paths.get(goldfile)).135equals(Files.readAllLines(Paths.get(outputfile), cs));136if (!isSame) {137System.err.println("Golden file " + goldfile + " :");138Files.readAllLines(Paths.get(goldfile)).forEach(System.err::println);139System.err.println("Output file " + outputfile + " :");140Files.readAllLines(Paths.get(outputfile), cs).forEach(System.err::println);141}142return isSame;143}144145/**146* Compare contents of golden file with test output list line by line.147* return true if they're identical.148* @param goldfile Golden output file name.149* @param lines test output list.150* @return true if file's content is identical to given list.151* false if file's content is not identical to given list.152* @throws IOException if an I/O error occurs reading from the file or a153* malformed or unmappable byte sequence is read154*/155public static boolean compareLinesWithGold(String goldfile, List<String> lines)156throws IOException {157return Files.readAllLines(Paths.get(goldfile)).equals(lines);158}159160/**161* Compare contents of golden file with a test output string.162* return true if they're identical.163* @param goldfile Golden output file name.164* @param string test string.165* @return true if file's content is identical to given string.166* false if file's content is not identical to given string.167* @throws IOException if an I/O error occurs reading from the file or a168* malformed or unmappable byte sequence is read169*/170public static boolean compareStringWithGold(String goldfile, String string)171throws IOException {172return Files.readAllLines(Paths.get(goldfile)).stream().collect(173Collectors.joining(System.getProperty("line.separator")))174.equals(string);175}176177/**178* Compare contents of golden file with test output file by their document179* representation.180* Here we ignore the white space and comments. return true if they're181* lexical identical.182* @param goldfile Golden output file name.183* @param resultFile Test output file name.184* @return true if two file's document representation are identical.185* false if two file's document representation are not identical.186* @throws javax.xml.parsers.ParserConfigurationException if the187* implementation is not available or cannot be instantiated.188* @throws SAXException If any parse errors occur.189* @throws IOException if an I/O error occurs reading from the file or a190* malformed or unmappable byte sequence is read .191*/192public static boolean compareDocumentWithGold(String goldfile, String resultFile)193throws ParserConfigurationException, SAXException, IOException {194DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();195factory.setNamespaceAware(true);196factory.setCoalescing(true);197factory.setIgnoringElementContentWhitespace(true);198factory.setIgnoringComments(true);199DocumentBuilder db = factory.newDocumentBuilder();200201Document goldD = db.parse(Paths.get(goldfile).toFile());202goldD.normalizeDocument();203Document resultD = db.parse(Paths.get(resultFile).toFile());204resultD.normalizeDocument();205return goldD.isEqualNode(resultD);206}207208/**209* Compare contents of golden file with the serialization represent by given210* DOM node.211* Here we ignore the white space and comments. return true if they're212* lexical identical.213* @param goldfile Golden output file name.214* @param node A DOM node instance.215* @return true if file's content is identical to given node's serialization216* represent.217* false if file's content is not identical to given node's218* serialization represent.219* @throws TransformerException If an unrecoverable error occurs during the220* course of the transformation..221* @throws IOException if an I/O error occurs reading from the file or a222* malformed or unmappable byte sequence is read .223*/224public static boolean compareSerializeDOMWithGold(String goldfile, Node node)225throws TransformerException, IOException {226TransformerFactory factory = TransformerFactory.newInstance();227// Use identity transformer to serialize228Transformer identityTransformer = factory.newTransformer();229StringWriter sw = new StringWriter();230StreamResult streamResult = new StreamResult(sw);231DOMSource nodeSource = new DOMSource(node);232identityTransformer.transform(nodeSource, streamResult);233return compareStringWithGold(goldfile, sw.toString());234}235236/**237* Convert stream to ByteArrayInputStream by given character set.238* @param charset target character set.239* @param file a file that contains no BOM head content.240* @return a ByteArrayInputStream contains BOM heads and bytes in original241* stream242* @throws IOException I/O operation failed or unsupported character set.243*/244public static InputStream bomStream(String charset, String file)245throws IOException {246String localCharset = charset;247if (charset.equals("UTF-16") || charset.equals("UTF-32")) {248localCharset249+= ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? "BE" : "LE";250}251if (!bom.containsKey(localCharset))252throw new UnsupportedCharsetException("Charset:" + localCharset);253254byte[] content = Files.readAllLines(Paths.get(file)).stream().255collect(Collectors.joining()).getBytes(localCharset);256byte[] head = bom.get(localCharset);257ByteBuffer bb = ByteBuffer.allocate(content.length + head.length);258bb.put(head);259bb.put(content);260return new ByteArrayInputStream(bb.array());261}262263/**264* Worker method to detect common absolute URLs.265*266* @param s String path\filename or URL (or any, really)267* @return true if s starts with a common URI scheme (namely268* the ones found in the examples of RFC2396); false otherwise269*/270protected static boolean isCommonURL(String s) {271if (null == s)272return false;273return Pattern.compile("^(file:|http:|ftp:|mailto:|news:|telnet:)")274.matcher(s).matches();275}276277/**278* Utility method to translate a String filename to URL.279*280* If the name starts with a common URI scheme (namely the ones281* found in the examples of RFC2396), then simply return the282* name as-is (the assumption is that it's already a URL).283* Otherwise we attempt (cheaply) to convert to a file:/ URL.284*285* @param filename local path/filename of a file.286* @return a file:/ URL if filename represent a file, the same string if287* it appears to already be a URL.288*/289public static String filenameToURL(String filename) {290return Paths.get(filename).toUri().toASCIIString();291}292293/**294* Prints error message if an exception is thrown295* @param ex The exception is thrown by test.296*/297public static void failUnexpected(Throwable ex) {298fail(ERROR_MSG_HEADER, ex);299}300301/**302* Prints error message if an exception is thrown when clean up a file.303* @param ex The exception is thrown in cleaning up a file.304* @param name Cleaning up file name.305*/306public static void failCleanup(IOException ex, String name) {307fail(String.format(ERROR_MSG_CLEANUP, name), ex);308}309310/**311* Retrieve next test output file name. This method is a thread-safe method.312* @param clazz test class.313* @return next test output file name.314*/315public static String getNextFile(Class<?> clazz) {316int nextNumber = currentFileNumber.contains(clazz)317? currentFileNumber.get(clazz) + 1 : 1;318Integer i = currentFileNumber.putIfAbsent(clazz, nextNumber);319if (i != null) {320do {321nextNumber = currentFileNumber.get(clazz) + 1;322} while (!currentFileNumber.replace(clazz, nextNumber - 1, nextNumber));323}324return USER_DIR + clazz.getName() + nextNumber + ".out";325}326327/**328* Acquire a full path string by given class name and relative path string.329* @param clazz Class name for the test.330* @param relativeDir relative path between java source file and expected331* path.332* @return a string represents the full path of accessing path.333*/334public static String getPathByClassName(Class<?> clazz, String relativeDir) {335String javaSourcePath = System.getProperty("test.src").replaceAll("\\" + File.separator, FILE_SEP);336String normalizedPath = Paths.get(javaSourcePath, relativeDir).normalize().337toAbsolutePath().toString();338return normalizedPath.replace("\\", FILE_SEP) + FILE_SEP;339}340341342/**343* Run the supplier with all permissions. This won't impact global policy.344*345* @param s346* Supplier to run347*/348public static <T> T runWithAllPerm(Supplier<T> s) {349Optional<JAXPPolicyManager> policyManager = Optional.ofNullable(JAXPPolicyManager350.getJAXPPolicyManager(false));351policyManager.ifPresent(manager -> manager.setAllowAll(true));352try {353return s.get();354} finally {355policyManager.ifPresent(manager -> manager.setAllowAll(false));356}357}358359/**360* Run the supplier with all permissions. This won't impact global policy.361*362* @param s363* Supplier to run364*/365public static <T> T tryRunWithAllPerm(Callable<T> c) throws Exception {366Optional<JAXPPolicyManager> policyManager = Optional.ofNullable(JAXPPolicyManager367.getJAXPPolicyManager(false));368policyManager.ifPresent(manager -> manager.setAllowAll(true));369try {370return c.call();371} finally {372policyManager.ifPresent(manager -> manager.setAllowAll(false));373}374}375376/**377* Run the Runnable with all permissions. This won't impact global policy.378*379* @param s380* Supplier to run381*/382public static void runWithAllPerm(Runnable r) {383Optional<JAXPPolicyManager> policyManager = Optional.ofNullable(JAXPPolicyManager384.getJAXPPolicyManager(false));385policyManager.ifPresent(manager -> manager.setAllowAll(true));386try {387r.run();388} finally {389policyManager.ifPresent(manager -> manager.setAllowAll(false));390}391}392393/**394* Acquire a system property.395*396* @param name397* System property name to be acquired.398* @return property value399*/400public static String getSystemProperty(String name) {401return runWithAllPerm(() -> System.getProperty(name));402}403404/**405* Set a system property by given system value.406*407* @param name408* System property name to be set.409* @param value410* System property value to be set.411*/412public static void setSystemProperty(String name, String value) {413runWithAllPerm(() -> System.setProperty(name, value));414}415416/**417* Clear a system property.418*419* @param name420* System property name to be cleared.421*/422public static void clearSystemProperty(String name) {423runWithAllPerm(() -> System.clearProperty(name));424}425426/**427* Run the runnable with assigning temporary permissions. This won't impact428* global policy.429*430* @param r431* Runnable to run432* @param ps433* assigning permissions to add.434*/435public static void runWithTmpPermission(Runnable r, Permission... ps) {436JAXPPolicyManager policyManager = JAXPPolicyManager.getJAXPPolicyManager(false);437List<Integer> tmpPermissionIndexes = new ArrayList<>();438if (policyManager != null) {439for (Permission p : ps)440tmpPermissionIndexes.add(policyManager.addTmpPermission(p));441}442try {443r.run();444} finally {445for (int index: tmpPermissionIndexes)446policyManager.removeTmpPermission(index);447}448}449450/**451* Run the supplier with assigning temporary permissions. This won't impact452* global policy.453*454* @param s455* Supplier to run456* @param ps457* assigning permissions to add.458*/459public static <T> T runWithTmpPermission(Supplier<T> s, Permission... ps) {460JAXPPolicyManager policyManager = JAXPPolicyManager.getJAXPPolicyManager(false);461List<Integer> tmpPermissionIndexes = new ArrayList<>();462if (policyManager != null) {463for (Permission p : ps)464tmpPermissionIndexes.add(policyManager.addTmpPermission(p));465}466try {467return s.get();468} finally {469for (int index: tmpPermissionIndexes)470policyManager.removeTmpPermission(index);471}472}473474/**475* Run the RunnableWithException with assigning temporary permissions. This476* won't impact global policy.477*478* @param r479* RunnableWithException to execute480* @param ps481* assigning permissions to add.482*/483public static void tryRunWithTmpPermission(RunnableWithException r, Permission... ps) throws Exception {484JAXPPolicyManager policyManager = JAXPPolicyManager.getJAXPPolicyManager(false);485List<Integer> tmpPermissionIndexes = new ArrayList<>();486if (policyManager != null) {487for (Permission p : ps)488tmpPermissionIndexes.add(policyManager.addTmpPermission(p));489}490try {491r.run();492} finally {493for (int index: tmpPermissionIndexes)494policyManager.removeTmpPermission(index);495}496}497498@FunctionalInterface499public interface RunnableWithException {500void run() throws Exception;501}502503/**504* Current test directory.505*/506public static final String USER_DIR = getSystemProperty("user.dir") + FILE_SEP;;507508}509510511