diff options
author | Raphael <raphael@google.com> | 2009-05-15 12:11:35 -0700 |
---|---|---|
committer | Raphael <raphael@google.com> | 2009-05-15 12:46:02 -0700 |
commit | c28e97a0db9c383cd656cb51f3b720dfb53b8d21 (patch) | |
tree | 30b4eac0865310bbd17a41f3ca727ee8679bb281 | |
parent | 8d9e4d6d7c53904f0769005014f3fea88c95b114 (diff) | |
download | sdk-c28e97a0db9c383cd656cb51f3b720dfb53b8d21.zip sdk-c28e97a0db9c383cd656cb51f3b720dfb53b8d21.tar.gz sdk-c28e97a0db9c383cd656cb51f3b720dfb53b8d21.tar.bz2 |
ADT #1844909: Tweak XML schema, add more tests.
Change XML schema to allow for empty <libs>, e.g. one can create
and add-on that doesn't declare any extra lib.
However enforce that <archives> contains at least one <archive>
element to prevent someone from declaring a download element
that cannot actually be downloaded.
Added a couple tests for validation of empty documents.
3 files changed, 244 insertions, 76 deletions
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd index c59197f..6c80d2e 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd @@ -86,9 +86,11 @@ <xsd:element name="desc-url" type="xsd:token" minOccurs="0" /> <xsd:element name="archives" type="sdk:archivesType" /> + <!-- An add-on can declare 0 or more libraries. --> + <xsd:element name="libs"> <xsd:complexType> - <xsd:sequence maxOccurs="unbounded"> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> <xsd:element name="lib"> <xsd:complexType> <xsd:all> @@ -135,13 +137,16 @@ </xsd:complexType> </xsd:element> - <!-- A collection of files that can be downloaded for a given architectures --> + <!-- A collection of files that can be downloaded for a given architecture. + The <archives> node is mandatory in the repository elements and the + collection must have at least one <archive> declared. + --> <xsd:complexType name="archivesType"> <xsd:annotation> <xsd:documentation>A collection of architecture-dependent archives.</xsd:documentation> </xsd:annotation> - <xsd:sequence maxOccurs="unbounded"> + <xsd:sequence minOccurs="1" maxOccurs="unbounded"> <!-- One archive file --> <xsd:element name="archive"> <xsd:complexType> diff --git a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/TestSdkRepository.java b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/TestSdkRepository.java index 68b475a..fe30239 100755 --- a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/TestSdkRepository.java +++ b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/TestSdkRepository.java @@ -16,15 +16,15 @@ package com.android.sdklib.repository;
-import com.android.sdklib.repository.SdkRepositoryConstants;
-
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.InputStream;
+import java.io.StringReader;
import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@@ -50,34 +50,10 @@ public class TestSdkRepository extends TestCase { super.tearDown();
}
- public void testValidateLocalRepositoryFile() throws Exception {
-
- InputStream xsdStream = SdkRepositoryConstants.getXsdStream();
- InputStream xmlStream = TestSdkRepository.class.getResourceAsStream("repository_sample.xml");
-
- SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-
- Schema schema = factory.newSchema(new StreamSource(xsdStream));
-
- Validator validator = schema.newValidator();
-
- CaptureErrorHandler handler = new CaptureErrorHandler();
- validator.setErrorHandler(handler);
-
- validator.validate(new StreamSource(xmlStream));
-
- String warnings = handler.getWarnings();
- if (warnings.length() > 0) {
- System.err.println(warnings);
- }
-
- String errors = handler.getErrors();
- if (errors.length() > 0) {
- System.err.println(errors);
- fail(errors);
- }
- }
-
+ /**
+ * A SAX error handler that captures the errors and warnings.
+ * This allows us to capture *all* errors and just not get an exception on the first one.
+ */
private static class CaptureErrorHandler implements ErrorHandler {
private String mWarnings = "";
@@ -92,15 +68,33 @@ public class TestSdkRepository extends TestCase { }
/**
+ * Verifies if the handler captures some errors or warnings.
+ * Prints them on stderr.
+ * Also fails the unit test if any error was generated.
+ */
+ public void verify() {
+ if (mWarnings.length() > 0) {
+ System.err.println(mWarnings);
+ }
+
+ if (mErrors.length() > 0) {
+ System.err.println(mErrors);
+ fail(mErrors);
+ }
+ }
+
+ /**
* @throws SAXException
*/
public void error(SAXParseException ex) throws SAXException {
mErrors += "Error: " + ex.getMessage() + "\n";
}
+ /**
+ * @throws SAXException
+ */
public void fatalError(SAXParseException ex) throws SAXException {
mErrors += "Fatal Error: " + ex.getMessage() + "\n";
- throw ex;
}
/**
@@ -112,4 +106,143 @@ public class TestSdkRepository extends TestCase { }
+ // --- Helpers ------------
+
+ /** Helper method that returns a validator for our XSD */
+ private Validator getValidator(CaptureErrorHandler handler) throws SAXException {
+ InputStream xsdStream = SdkRepositoryConstants.getXsdStream();
+ SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema schema = factory.newSchema(new StreamSource(xsdStream));
+ Validator validator = schema.newValidator();
+ if (handler != null) {
+ validator.setErrorHandler(handler);
+ }
+
+ return validator;
+ }
+
+ /** Validate a valid sample using an InputStream */
+ public void testValidateLocalRepositoryFile() throws Exception {
+
+ InputStream xmlStream =
+ TestSdkRepository.class.getResourceAsStream("repository_sample.xml");
+ Source source = new StreamSource(xmlStream);
+
+ CaptureErrorHandler handler = new CaptureErrorHandler();
+ Validator validator = getValidator(handler);
+ validator.validate(source);
+ handler.verify();
+ }
+
+ /** An helper that validates a string against an expected regexp. */
+ private void assertRegex(String expectedRegexp, String actualString) {
+ assertNotNull(actualString);
+ assertTrue(
+ String.format("Regexp Assertion Failed:\nExpected: %s\nActual: %s\n",
+ expectedRegexp, actualString),
+ actualString.matches(expectedRegexp));
+ }
+
+ // --- Tests ------------
+
+ /** A document should at least have a root to be valid */
+ public void testEmptyXml() throws Exception {
+ String document = "<?xml version=\"1.0\"?>";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ CaptureErrorHandler handler = new CaptureErrorHandler();
+ Validator validator = getValidator(handler);
+
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect to get this specific exception message
+ assertRegex("Premature end of file.*", e.getMessage());
+ return;
+ }
+ // We shouldn't get here
+ handler.verify();
+ fail();
+ }
+
+ /** A document with a root element containing no platform, addon, etc., is valid. */
+ public void testEmptyRootXml() throws Exception {
+ String document = "<?xml version=\"1.0\"?>" +
+ "<r:sdk-repository xmlns:r=\"http://schemas.android.com/sdk/android/repository/1\" />";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ CaptureErrorHandler handler = new CaptureErrorHandler();
+ Validator validator = getValidator(handler);
+ validator.validate(source);
+ handler.verify();
+ }
+
+ /** A document with an unknown element. */
+ public void testUnknownContentXml() throws Exception {
+ String document = "<?xml version=\"1.0\"?>" +
+ "<r:sdk-repository xmlns:r=\"http://schemas.android.com/sdk/android/repository/1\" >" +
+ "<r:unknown />" +
+ "</r:sdk-repository>";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse expression referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.a: Invalid content was found.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with an incomplete element. */
+ public void testIncompleteContentXml() throws Exception {
+ String document = "<?xml version=\"1.0\"?>" +
+ "<r:sdk-repository xmlns:r=\"http://schemas.android.com/sdk/android/repository/1\" >" +
+ "<r:platform> <r:api-level>1</r:api-level> <r:libs /> </r:platform>" +
+ "</r:sdk-repository>";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.a: Invalid content was found.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with a wrong type element. */
+ public void testWrongTypeContentXml() throws Exception {
+ String document = "<?xml version=\"1.0\"?>" +
+ "<r:sdk-repository xmlns:r=\"http://schemas.android.com/sdk/android/repository/1\" >" +
+ "<r:platform> <r:api-level>NotAnInteger</r:api-level> <r:libs /> </r:platform>" +
+ "</r:sdk-repository>";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-datatype-valid.1.2.1: 'NotAnInteger' is not a valid value.*",
+ e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
}
diff --git a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml index 0643185..fb6283d 100755 --- a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml +++ b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml @@ -17,12 +17,17 @@ <sdk:sdk-repository
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdk="http://schemas.android.com/sdk/android/repository/1">
+
+ <!-- Inner elements must be either platform, add-on, doc or tool.
+ There can be 0 or more of each, in any order. -->
+
<sdk:platform>
<sdk:version>1.0</sdk:version>
<sdk:api-level>1</sdk:api-level>
<sdk:revision>3</sdk:revision>
<sdk:description>Some optional description</sdk:description>
<sdk:desc-url>http://www.example.com/platform1.html</sdk:desc-url>
+ <!-- The archives node is mandatory and it cannot be empty. -->
<sdk:archives>
<sdk:archive os="any">
<sdk:size>65536</sdk:size>
@@ -31,6 +36,48 @@ </sdk:archive>
</sdk:archives>
</sdk:platform>
+
+ <sdk:doc>
+ <sdk:api-level>1</sdk:api-level>
+ <sdk:revision>1</sdk:revision>
+ <sdk:description>Some optional description</sdk:description>
+ <sdk:desc-url>http://www.example.com/docs.html</sdk:desc-url>
+ <sdk:archives>
+ <sdk:archive os="any">
+ <sdk:size>65536</sdk:size>
+ <sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
+ <sdk:url>http://www.example.com/docs/docs1.zip</sdk:url>
+ </sdk:archive>
+ </sdk:archives>
+ </sdk:doc>
+
+ <sdk:add-on>
+ <sdk:name>My First add-on</sdk:name>
+ <sdk:api-level>1</sdk:api-level>
+ <sdk:vendor>John Doe</sdk:vendor>
+ <sdk:revision>1</sdk:revision>
+ <sdk:description>Some optional description</sdk:description>
+ <sdk:desc-url>http://www.example.com/myfirstaddon</sdk:desc-url>
+ <sdk:archives>
+ <sdk:archive os="any">
+ <sdk:size>65536</sdk:size>
+ <sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
+ <sdk:url>http://www.example.com/add-ons/first.zip</sdk:url>
+ </sdk:archive>
+ </sdk:archives>
+ <!-- The libs node is mandatory, however it can be empty. -->
+ <sdk:libs>
+ <sdk:lib>
+ <sdk:name>android.blah.somelib</sdk:name>
+ <sdk:description>The description for this library.</sdk:description>
+ </sdk:lib>
+ <sdk:lib>
+ <!-- sdk:description is optional, name is not -->
+ <sdk:name>com.android.mymaps</sdk:name>
+ </sdk:lib>
+ </sdk:libs>
+ </sdk:add-on>
+
<sdk:platform>
<sdk:version>1.1</sdk:version>
<sdk:api-level>2</sdk:api-level>
@@ -65,31 +112,7 @@ </sdk:archive>
</sdk:archives>
</sdk:platform>
- <sdk:add-on>
- <sdk:name>My First add-on</sdk:name>
- <sdk:api-level>1</sdk:api-level>
- <sdk:vendor>John Doe</sdk:vendor>
- <sdk:revision>1</sdk:revision>
- <sdk:description>Some optional description</sdk:description>
- <sdk:desc-url>http://www.example.com/myfirstaddon</sdk:desc-url>
- <sdk:archives>
- <sdk:archive os="any">
- <sdk:size>65536</sdk:size>
- <sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
- <sdk:url>http://www.example.com/add-ons/first.zip</sdk:url>
- </sdk:archive>
- </sdk:archives>
- <sdk:libs>
- <sdk:lib>
- <sdk:name>android.blah.somelib</sdk:name>
- <sdk:description>The description for this library.</sdk:description>
- </sdk:lib>
- <sdk:lib>
- <!-- sdk:description is optional, name is not -->
- <sdk:name>com.android.mymaps</sdk:name>
- </sdk:lib>
- </sdk:libs>
- </sdk:add-on>
+
<sdk:add-on>
<sdk:name>My Second add-on</sdk:name>
<sdk:api-level>2</sdk:api-level>
@@ -117,19 +140,20 @@ </sdk:lib>
</sdk:libs>
</sdk:add-on>
- <sdk:doc>
- <sdk:api-level>1</sdk:api-level>
+
+ <sdk:tool>
<sdk:revision>1</sdk:revision>
<sdk:description>Some optional description</sdk:description>
- <sdk:desc-url>http://www.example.com/docs.html</sdk:desc-url>
+ <sdk:desc-url>http://www.example.com/tools.html</sdk:desc-url>
<sdk:archives>
<sdk:archive os="any">
<sdk:size>65536</sdk:size>
<sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
- <sdk:url>http://www.example.com/docs/docs1.zip</sdk:url>
+ <sdk:url>http://www.example.com/files/tools1.zip</sdk:url>
</sdk:archive>
</sdk:archives>
- </sdk:doc>
+ </sdk:tool>
+
<sdk:doc>
<sdk:api-level>2</sdk:api-level>
<sdk:revision>42</sdk:revision>
@@ -151,18 +175,7 @@ </sdk:archive>
</sdk:archives>
</sdk:doc>
- <sdk:tool>
- <sdk:revision>1</sdk:revision>
- <sdk:description>Some optional description</sdk:description>
- <sdk:desc-url>http://www.example.com/tools.html</sdk:desc-url>
- <sdk:archives>
- <sdk:archive os="any">
- <sdk:size>65536</sdk:size>
- <sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
- <sdk:url>http://www.example.com/files/tools1.zip</sdk:url>
- </sdk:archive>
- </sdk:archives>
- </sdk:tool>
+
<sdk:tool>
<sdk:revision>42</sdk:revision>
<sdk:archives>
@@ -183,4 +196,21 @@ </sdk:archive>
</sdk:archives>
</sdk:tool>
+
+ <sdk:add-on>
+ <sdk:name>This add-on has no libraries</sdk:name>
+ <sdk:api-level>4</sdk:api-level>
+ <sdk:vendor>Joe Bar</sdk:vendor>
+ <sdk:revision>3</sdk:revision>
+ <sdk:archives>
+ <sdk:archive os="any" arch="any">
+ <sdk:size>65536</sdk:size>
+ <sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
+ <sdk:url>distrib/imnotanarchiveimadoctorjim.zip</sdk:url>
+ </sdk:archive>
+ </sdk:archives>
+ <!-- The libs node is mandatory, however it can be empty. -->
+ <sdk:libs />
+ </sdk:add-on>
+
</sdk:sdk-repository>
|