• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.asllib.testutils;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertThrows;
21 
22 import com.android.asllib.marshallable.AslMarshallable;
23 import com.android.asllib.marshallable.AslMarshallableFactory;
24 import com.android.asllib.util.MalformedXmlException;
25 import com.android.asllib.util.XmlUtils;
26 
27 import org.w3c.dom.Document;
28 import org.w3c.dom.Element;
29 import org.w3c.dom.Node;
30 import org.w3c.dom.NodeList;
31 import org.xml.sax.SAXException;
32 
33 import java.io.ByteArrayInputStream;
34 import java.io.ByteArrayOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.nio.charset.StandardCharsets;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.util.List;
41 import java.util.Optional;
42 
43 import javax.xml.parsers.DocumentBuilderFactory;
44 import javax.xml.parsers.ParserConfigurationException;
45 import javax.xml.transform.OutputKeys;
46 import javax.xml.transform.Transformer;
47 import javax.xml.transform.TransformerException;
48 import javax.xml.transform.TransformerFactory;
49 import javax.xml.transform.dom.DOMSource;
50 import javax.xml.transform.stream.StreamResult;
51 
52 public class TestUtils {
53     public static final String HOLDER_TAG_NAME = "holder_of_flattened_for_testing";
54 
55     /** Reads a Resource file into a String. */
readStrFromResource(Path filePath)56     public static String readStrFromResource(Path filePath) throws IOException {
57         InputStream hrStream =
58                 TestUtils.class.getClassLoader().getResourceAsStream(filePath.toString());
59         return new String(hrStream.readAllBytes(), StandardCharsets.UTF_8);
60     }
61 
62     /** Gets List of Element from a path to an existing Resource. */
getElementsFromResource(Path filePath)63     public static List<Element> getElementsFromResource(Path filePath)
64             throws ParserConfigurationException, IOException, SAXException {
65         String str = readStrFromResource(filePath);
66         InputStream stream = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));
67 
68         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
69         factory.setNamespaceAware(true);
70         Document document = factory.newDocumentBuilder().parse(stream);
71         Element root = document.getDocumentElement();
72         if (root.getTagName().equals(HOLDER_TAG_NAME)) {
73             String tagName =
74                     XmlUtils.asElementList(root.getChildNodes()).stream()
75                             .findFirst()
76                             .get()
77                             .getTagName();
78             return XmlUtils.getChildrenByTagName(root, tagName);
79         } else {
80             return List.of(root);
81         }
82     }
83 
84     /** Reads a Document into a String. */
docToStr(Document doc, boolean omitXmlDeclaration)85     public static String docToStr(Document doc, boolean omitXmlDeclaration)
86             throws TransformerException {
87         TransformerFactory transformerFactory = TransformerFactory.newInstance();
88         Transformer transformer = transformerFactory.newTransformer();
89         transformer.setOutputProperty(OutputKeys.INDENT, "yes");
90         transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
91         transformer.setOutputProperty(
92                 OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration ? "yes" : "no");
93 
94         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
95         StreamResult streamResult = new StreamResult(outStream); // out
96         DOMSource domSource = new DOMSource(doc);
97         transformer.transform(domSource, streamResult);
98 
99         return outStream.toString(StandardCharsets.UTF_8);
100     }
101 
102     /** Removes on-device style child with the corresponding name */
removeOdChildEleWithName(Element ele, String childNameName)103     public static void removeOdChildEleWithName(Element ele, String childNameName) {
104         Optional<Element> childEle =
105                 XmlUtils.asElementList(ele.getChildNodes()).stream()
106                         .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(childNameName))
107                         .findFirst();
108         if (childEle.isEmpty()) {
109             throw new IllegalStateException(
110                     String.format("%s was not found in %s", childNameName, ele.getTagName()));
111         }
112         ele.removeChild(childEle.get());
113     }
114 
115     /**
116      * Gets formatted XML for slightly more robust comparison checking than naive string comparison.
117      */
getFormattedXml(String xmlStr, boolean omitXmlDeclaration)118     public static String getFormattedXml(String xmlStr, boolean omitXmlDeclaration)
119             throws ParserConfigurationException, IOException, SAXException, TransformerException {
120         InputStream stream = new ByteArrayInputStream(xmlStr.getBytes(StandardCharsets.UTF_8));
121         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
122         factory.setNamespaceAware(true);
123         Document document = factory.newDocumentBuilder().parse(stream);
124         stripEmptyElements(document);
125         return docToStr(document, omitXmlDeclaration);
126     }
127 
128     /** Helper for getting a new Document */
document()129     public static Document document() throws ParserConfigurationException {
130         return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
131     }
132 
133     /** Helper for testing human-readable to on-device conversion expecting exception */
hrToOdExpectException( AslMarshallableFactory<T> factory, String hrFolderPath, String fileName)134     public static <T extends AslMarshallable> void hrToOdExpectException(
135             AslMarshallableFactory<T> factory, String hrFolderPath, String fileName) {
136         assertThrows(
137                 MalformedXmlException.class,
138                 () -> {
139                     factory.createFromHrElements(
140                             TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName)));
141                 });
142     }
143 
144     /** Helper for testing on-device to human-readable conversion expecting exception */
odToHrExpectException( AslMarshallableFactory<T> factory, String odFolderPath, String fileName)145     public static <T extends AslMarshallable> void odToHrExpectException(
146             AslMarshallableFactory<T> factory, String odFolderPath, String fileName) {
147         assertThrows(
148                 MalformedXmlException.class,
149                 () -> {
150                     factory.createFromOdElements(
151                             TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName)));
152                 });
153     }
154 
155     /** Helper for testing human-readable to on-device conversion */
testHrToOd( Document doc, AslMarshallableFactory<T> factory, String hrFolderPath, String odFolderPath, String fileName)156     public static <T extends AslMarshallable> void testHrToOd(
157             Document doc,
158             AslMarshallableFactory<T> factory,
159             String hrFolderPath,
160             String odFolderPath,
161             String fileName)
162             throws Exception {
163         testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true);
164     }
165 
166     /** Helper for testing on-device to human-readable conversion */
testOdToHr( Document doc, AslMarshallableFactory<T> factory, String odFolderPath, String hrFolderPath, String fileName)167     public static <T extends AslMarshallable> void testOdToHr(
168             Document doc,
169             AslMarshallableFactory<T> factory,
170             String odFolderPath,
171             String hrFolderPath,
172             String fileName)
173             throws Exception {
174         testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false);
175     }
176 
177     /** Helper for testing format to format conversion */
testFormatToFormat( Document doc, AslMarshallableFactory<T> factory, String inFolderPath, String outFolderPath, String fileName, boolean hrToOd)178     private static <T extends AslMarshallable> void testFormatToFormat(
179             Document doc,
180             AslMarshallableFactory<T> factory,
181             String inFolderPath,
182             String outFolderPath,
183             String fileName,
184             boolean hrToOd)
185             throws Exception {
186         AslMarshallable marshallable =
187                 hrToOd
188                         ? factory.createFromHrElements(
189                                 TestUtils.getElementsFromResource(
190                                         Paths.get(inFolderPath, fileName)))
191                         : factory.createFromOdElements(
192                                 TestUtils.getElementsFromResource(
193                                         Paths.get(inFolderPath, fileName)));
194 
195         List<Element> elements =
196                 hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc);
197         if (elements.isEmpty()) {
198             throw new IllegalStateException("elements was empty.");
199         } else if (elements.size() == 1) {
200             doc.appendChild(elements.get(0));
201         } else {
202             Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME);
203             for (var child : elements) {
204                 root.appendChild(child);
205             }
206             doc.appendChild(root);
207         }
208         String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true);
209         System.out.println("Converted: " + converted);
210         String expectedOutContents =
211                 TestUtils.getFormattedXml(
212                         TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true);
213         System.out.println("Expected: " + expectedOutContents);
214         assertEquals(expectedOutContents, converted);
215     }
216 
stripEmptyElements(Node node)217     private static void stripEmptyElements(Node node) {
218         NodeList children = node.getChildNodes();
219         for (int i = 0; i < children.getLength(); ++i) {
220             Node child = children.item(i);
221             if (child.getNodeType() == Node.TEXT_NODE) {
222                 if (child.getTextContent().trim().length() == 0) {
223                     child.getParentNode().removeChild(child);
224                     i--;
225                 }
226             }
227             stripEmptyElements(child);
228         }
229     }
230 }
231