// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.enterprise.connector.util;
import static com.google.common.base.Charsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.google.common.io.Files;
import com.google.enterprise.connector.servlet.ServletUtil;
import com.google.enterprise.connector.util.testing.Logging;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXParseException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class XmlParseUtilTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
private File tempFile;
private ArrayList<String> saxExceptions;
@Before
public void setUp() throws IOException {
tempFile = tempFolder.newFile("test.txt");
Files.write("hello, world", tempFile, UTF_8);
saxExceptions = new ArrayList<String>();
Logging.captureLogMessages(XmlParseUtil.class, "SAX Exception",
saxExceptions);
}
@Test
public void verifyTempFile() throws IOException {
assertEquals("hello, world", Files.readFirstLine(tempFile, UTF_8));
}
@Test
public void testValidateXhtml_valid() throws Exception {
XmlParseUtil.validateXhtml("<tr><td>hello, world</td></tr>");
}
@Test
public void testValidateXhtml_invalid() throws Exception {
thrown.expect(SAXParseException.class);
XmlParseUtil.validateXhtml("<tr>hello, world</td>");
}
@Test
public void testParse_success() {
String xml = "<ConnectorInstances></ConnectorInstances>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.nonEntityResolver);
assertTrue(saxExceptions.toString(), saxExceptions.isEmpty());
assertNotNull(doc);
}
@Test
public void testParse_unknownDoctype_nonResolver() {
String xml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD something\" \"\">"
+ "<ConnectorInstances></ConnectorInstances>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.nonEntityResolver);
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertNull(doc);
}
@Test
public void testParse_unknownDoctype_catalogResolver() {
String xml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD something\" \"\">"
+ "<ConnectorInstances></ConnectorInstances>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.catalogEntityResolver);
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertNull(doc);
}
@Test
public void testParse_xmlEntities() throws Exception {
String original = "a<b&I say "Ain't nothing"";
String expected = "a<b&I say \"Ain't nothing\"";
String xml = "<Credentials><Username>bar</Username><Password>"
+ original
+ "</Password></Credentials>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.nonEntityResolver);
assertTrue(saxExceptions.toString(), saxExceptions.isEmpty());
assertNotNull(doc);
Element root = doc.getDocumentElement();
String actual = XmlParseUtil.getFirstElementByTagName(root, "Password");
assertEquals(expected, actual);
}
@Test
public void testParse_htmlEntities_nonResolver() throws Exception {
String original = "Hëllo, World¡";
String xml = "<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC"
+ " \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"\">"
+ "<html><body>"
+ original
+ "</body></html>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.nonEntityResolver);
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertNull(doc);
}
@Test
public void testParse_htmlEntities_catalogResolver() throws Exception {
String original = "Hëllo, World¡";
String expected = "H\u00ebllo, World\u00a1";
String xml = "<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC"
+ " \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"\">"
+ "<html><body>"
+ original
+ "</body></html>";
Document doc = XmlParseUtil.parse(xml, new SAXParseErrorHandler(),
XmlParseUtil.catalogEntityResolver);
assertTrue(saxExceptions.toString(), saxExceptions.isEmpty());
assertNotNull(doc);
Element root = doc.getDocumentElement();
String actual = XmlParseUtil.getFirstElementByTagName(root, "body");
assertEquals(expected, actual);
}
@Test
public void testParseAndGetRootElement_success() {
String xml = "<AuthnRequest><Credentials>"
+ "<Username>bar</Username><Password>afoo</Password>"
+ "</Credentials></AuthnRequest>";
Element root = XmlParseUtil.parseAndGetRootElement(xml,
ServletUtil.XMLTAG_AUTHN_REQUEST);
assertTrue(saxExceptions.toString(), saxExceptions.isEmpty());
assertEquals(ServletUtil.XMLTAG_AUTHN_REQUEST, root.getTagName());
}
@Test
public void testParseAndGetRootElement_xxe() {
String xml = "<!DOCTYPE foo ["
+ "<!ENTITY bar SYSTEM \"file://" + tempFile + "\">"
+ "]>"
+ "<AuthnRequest><Credentials>"
+ "<Username>&bar;</Username><Password>afoo</Password>"
+ "</Credentials></AuthnRequest>";
Element root = XmlParseUtil.parseAndGetRootElement(xml,
ServletUtil.XMLTAG_AUTHN_REQUEST);
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertEquals(null, root);
}
@Test
public void testParseAndGetRootElement_xinclude() {
String xml = "<?xml version=\"1.0\"?>\n"
+ "<AuthnRequest xmlns=\"foo\" "
+ "xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n"
+ "<xi:include href=\"file://" + tempFile + "\" parse=\"text\"/>\n"
+ "</data>\n";
Element root = XmlParseUtil.parseAndGetRootElement(xml,
ServletUtil.XMLTAG_AUTHN_REQUEST);
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertEquals(null, root);
}
@Test
public void testParseAndGetRootElement_doctype() throws Exception {
String xml = "<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC"
+ " \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"\">"
+ "<html><body></body></html>";
Element root = XmlParseUtil.parseAndGetRootElement(xml, "html");
assertFalse(saxExceptions.toString(), saxExceptions.isEmpty());
assertEquals(root, null);
}
@Test
public void testGetOptionalElementByTagName() throws Exception {
String xml = "<root><foo>blah</foo><bar></bar><baz/><nest><nested>oops"
+ "</nested></nest></root>";
Element root = XmlParseUtil.parseAndGetRootElement(xml, "root");
assertNotNull(root);
assertEquals("blah", XmlParseUtil.getOptionalElementByTagName(root, "foo"));
assertEquals("", XmlParseUtil.getOptionalElementByTagName(root, "bar"));
assertEquals("", XmlParseUtil.getOptionalElementByTagName(root, "baz"));
assertNull(XmlParseUtil.getOptionalElementByTagName(root, "nonexist"));
assertEquals("", XmlParseUtil.getOptionalElementByTagName(root, "nest"));
}
}