Merge "Adding tests to parse document attributes from the DOM."
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
index 1283eeb..991a707 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DOMImplementationImpl.java
@@ -41,7 +41,7 @@
 
     public Document createDocument(String namespaceURI, String qualifiedName,
             DocumentType doctype) throws DOMException {
-        return new DocumentImpl(this, namespaceURI, qualifiedName, doctype);
+        return new DocumentImpl(this, namespaceURI, qualifiedName, doctype, null);
     }
 
     public DocumentType createDocumentType(String qualifiedName,
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index b2f16d1..e297280 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -48,11 +48,23 @@
 
     private DOMImplementation domImplementation;
 
+    /*
+     * The default values of these fields are specified by the Document
+     * interface.
+     */
+    private String documentUri;
+    private String inputEncoding;
+    private String xmlEncoding;
+    private String xmlVersion = "1.0";
+    private boolean xmlStandalone = false;
+    private boolean strictErrorChecking = true;
+
     public DocumentImpl(DOMImplementationImpl impl, String namespaceURI,
-            String qualifiedName, DocumentType doctype) {
+            String qualifiedName, DocumentType doctype, String inputEncoding) {
         super(null);
 
         this.domImplementation = impl;
+        this.inputEncoding = inputEncoding;
         // this.document = this;
         
         if (doctype != null) {
@@ -304,43 +316,43 @@
     }
 
     public String getInputEncoding() {
-        throw new UnsupportedOperationException(); // TODO
+        return inputEncoding;
     }
 
     public String getXmlEncoding() {
-        throw new UnsupportedOperationException(); // TODO
+        return xmlEncoding;
     }
 
     public boolean getXmlStandalone() {
-        throw new UnsupportedOperationException(); // TODO
+        return xmlStandalone;
     }
 
     public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
-        throw new UnsupportedOperationException(); // TODO
+        this.xmlStandalone = xmlStandalone;
     }
 
     public String getXmlVersion() {
-        throw new UnsupportedOperationException(); // TODO
+        return xmlVersion;
     }
 
     public void setXmlVersion(String xmlVersion) throws DOMException {
-        throw new UnsupportedOperationException(); // TODO
+        this.xmlVersion = xmlVersion;
     }
 
     public boolean getStrictErrorChecking() {
-        throw new UnsupportedOperationException(); // TODO
+        return strictErrorChecking;
     }
 
     public void setStrictErrorChecking(boolean strictErrorChecking) {
-        throw new UnsupportedOperationException(); // TODO
+        this.strictErrorChecking = strictErrorChecking;
     }
 
     public String getDocumentURI() {
-        throw new UnsupportedOperationException(); // TODO
+        return documentUri;
     }
 
-    public void setDocumentURI(String documentURI) {
-        throw new UnsupportedOperationException(); // TODO
+    public void setDocumentURI(String documentUri) {
+        this.documentUri = documentUri;
     }
 
     public Node adoptNode(Node source) throws DOMException {
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
index ca2ff98..4b273fe 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -100,25 +100,27 @@
         String namespaceURI = null;
         String qualifiedName = null;
         DocumentType doctype = null;
-        DocumentImpl document = new DocumentImpl(dom, namespaceURI, qualifiedName, doctype);
+        String inputEncoding = source.getEncoding();
+        String systemId = source.getSystemId();
+        DocumentImpl document = new DocumentImpl(
+                dom, namespaceURI, qualifiedName, doctype, inputEncoding);
+        document.setDocumentURI(systemId);
 
         try {
             KXmlParser parser = new KXmlParser();
             parser.keepNamespaceAttributes();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
-                    namespaceAware);
-            
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, namespaceAware);
+
             if (source.getByteStream() != null) {
-                parser.setInput(source.getByteStream(), source.getEncoding());
+                parser.setInput(source.getByteStream(), inputEncoding);
             } else if (source.getCharacterStream() != null) {
                 parser.setInput(source.getCharacterStream());
-            } else if (source.getSystemId() != null) {
-                URL url = new URL(source.getSystemId());
+            } else if (systemId != null) {
+                URL url = new URL(systemId);
                 URLConnection urlConnection = url.openConnection();
                 urlConnection.connect();
-                String encoding = source.getEncoding();
-                // TODO: if null, extract the encoding from the Content-Type header?
-                parser.setInput(urlConnection.getInputStream(), encoding);
+                // TODO: if null, extract the inputEncoding from the Content-Type header?
+                parser.setInput(urlConnection.getInputStream(), inputEncoding);
             } else {
                 throw new SAXParseException(
                         "InputSource needs a stream, reader or URI", null);
@@ -143,7 +145,7 @@
             LocatorImpl locator = new LocatorImpl();
 
             locator.setPublicId(source.getPublicId());
-            locator.setSystemId(source.getSystemId());
+            locator.setSystemId(systemId);
             locator.setLineNumber(ex.getLineNumber());
             locator.setColumnNumber(ex.getColumnNumber());
 
diff --git a/libcore/xml/src/test/java/tests/xml/AllTests.java b/libcore/xml/src/test/java/tests/xml/AllTests.java
index 597e35e..beabd08 100644
--- a/libcore/xml/src/test/java/tests/xml/AllTests.java
+++ b/libcore/xml/src/test/java/tests/xml/AllTests.java
@@ -24,6 +24,7 @@
     public static Test suite() {
         TestSuite suite = tests.TestSuiteFactory.createTestSuite();
 
+        suite.addTestSuite(DeclarationTest.class);
         suite.addTestSuite(DomTest.class);
         suite.addTestSuite(SimpleParserTest.class);
         suite.addTestSuite(SimpleBuilderTest.class);
diff --git a/libcore/xml/src/test/java/tests/xml/DeclarationTest.java b/libcore/xml/src/test/java/tests/xml/DeclarationTest.java
new file mode 100644
index 0000000..8fea844
--- /dev/null
+++ b/libcore/xml/src/test/java/tests/xml/DeclarationTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 tests.xml;
+
+import junit.framework.TestCase;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Test the parsing of the XML declaration, plus the additional document fields
+ * captured during parsing.
+ */
+public class DeclarationTest extends TestCase {
+
+    private String systemIdA;
+    private Document documentA;
+
+    private String systemIdB;
+    private Document documentB;
+
+    @Override protected void setUp() throws Exception {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+
+        systemIdA = stringToSystemId(
+                "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\" ?><foo />");
+        InputSource inputSourceA = new InputSource(systemIdA);
+        inputSourceA.setEncoding("US-ASCII");
+        documentA = builder.parse(inputSourceA);
+
+        systemIdB = stringToSystemId(
+                "<?xml version=\"1.1\" encoding=\"US-ASCII\" standalone=\"yes\" ?><foo />");
+        InputSource inputSourceB = new InputSource(systemIdB);
+        inputSourceB.setEncoding("ISO-8859-1");
+        documentB = builder.parse(inputSourceB);
+    }
+
+    private String stringToSystemId(String contents) throws IOException {
+        File file = File.createTempFile("temp", "xml");
+        file.deleteOnExit();
+        OutputStream out = new FileOutputStream(file);
+        out.write(contents.getBytes("UTF-8"));
+        out.close();
+        return "file:" + file;
+    }
+
+    /**
+     * XML parsers are advised of the document's character set via two channels:
+     * via the declaration and also the document's input source. To test that
+     * each of these winds up in the correct location in the document model, we
+     * supply different names for each. This is only safe because for the subset
+     * of characters in the document, the character sets are equivalent.
+     */
+    public void testGetInputEncoding() throws Exception {
+        assertEquals("US-ASCII", documentA.getInputEncoding());
+        assertEquals("ISO-8859-1", documentB.getInputEncoding());
+    }
+
+    public void testGetXmlEncoding() throws Exception {
+        String message = "This implementation doesn't parse the encoding from the XML declaration";
+        assertEquals(message, "ISO-8859-1", documentA.getXmlEncoding());
+        assertEquals(message, "US-ASCII", documentB.getXmlEncoding());
+    }
+
+    public void testGetXmlVersion() throws Exception {
+        String message = "This implementation doesn't parse the version from the XML declaration";
+        assertEquals(message, "1.0", documentA.getXmlVersion());
+        assertEquals(message, "1.1", documentB.getXmlVersion());
+    }
+
+    public void testGetXmlStandalone() throws Exception {
+        String message = "This implementation doesn't parse standalone from the XML declaration";
+        assertEquals(message, false, documentA.getXmlStandalone());
+        assertEquals(message, true, documentB.getXmlStandalone());
+    }
+
+    public void testGetDocumentUri() throws Exception {
+        assertEquals(systemIdA, documentA.getDocumentURI());
+        assertEquals(systemIdB, documentB.getDocumentURI());
+    }
+}