diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java new file mode 100755 index 000000000..871020ce0 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.eclipse.adt.internal.sdk; + + +import java.io.InputStream; + +/** + * Public constants for the sdk-repository XML Schema. + */ +public class LayoutConfigsXsd { + + /** The XML namespace of the layout-configs XML. */ + public static final String NS_LAYOUT_CONFIG_XSD = + "http://schemas.android.com/sdk/android/layout-configs/1"; //$NON-NLS-1$ + + /** + * The "layout-configs" element is the root element of this schema. + * + * It must contain one or more "device" elements that each define the configurations + * available for a given device. + * + * These definitions are used in the Graphical Layout Editor in the + * Android Development Tools (ADT) plugin for Eclipse. + */ + public static final String NODE_LAYOUT_CONFIGS = "layout-configs"; //$NON-NLS-1$ + + /** + * A device element must contain at most one "default" element followed + * by one or more ""config" elements. + * + * The "default" element defines all the default parameters inherited + * by the following "config" elements. Each "config" element can override + * the default values, if any. + * + * A "device" element also has a required "name" attribute that represents + * the user-interface name of this device. + */ + public static final String NODE_DEVICE = "device"; //$NON-NLS-1$ + + /** + * The "default" element contains zero or more of all the parameter elements + * listed below. It defines all the parameters that are common to all + * declared "config" elements. + */ + public static final String NODE_DEFAULT = "default"; //$NON-NLS-1$ + + /** + * The "config" element contains zero or more of all the parameter elements + * listed below. The parameters from the "default" element (if present) are + * automatically inherited and can be overridden. + */ + public static final String NODE_CONFIG = "config"; //$NON-NLS-1$ + + + public static final String NODE_SCREEN_SIZE = "screen-size"; //$NON-NLS-1$ + + public static final String NODE_SCREEN_RATIO = "screen-ratio"; //$NON-NLS-1$ + + public static final String NODE_SCREEN_ORIENTATION = "screen-orientation"; //$NON-NLS-1$ + + public static final String NODE_PIXEL_DENSITY = "pixel-density"; //$NON-NLS-1$ + + public static final String NODE_TOUCH_TYPE = "touch-type"; //$NON-NLS-1$ + + public static final String NODE_KEYBOARD_STATE = "keyboard-state"; //$NON-NLS-1$ + + public static final String NODE_TEXT_INPUT_METHOD = "text-input-method"; //$NON-NLS-1$ + + public static final String NODE_NAV_METHOD = "nav-method"; //$NON-NLS-1$ + + public static final String NODE_SCREEN_DIMENSION = "screen-dimension"; //$NON-NLS-1$ + + public static final String NODE_SIZE = "size"; //$NON-NLS-1$ + + /** + * The "name" attribute, used by both the "device" and the "config" + * elements. It represents the user-interface name of these objects. + */ + public static final String ATTR_NAME = "name"; //$NON-NLS-1$ + + /** + * Helper to get an input stream of the layout config XML schema. + */ + public static InputStream getXsdStream() { + return LayoutConfigsXsd.class.getResourceAsStream("layout-configs.xsd"); //$NON-NLS-1$ + } + +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd new file mode 100755 index 000000000..e0452292b --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd @@ -0,0 +1,209 @@ + + + + + + + + The "layout-configs" element is the root element of this schema. + + It must contain one or more "device" elements that each define the configurations + available for a given device. + + These definitions are used in the Graphical Layout Editor in the + Android Development Tools (ADT) plugin for Eclipse. + + + + + + + + + + + A device element must contain at most one "default" element + followed by one or more "config" elements. + + The "default" element defines all the default parameters + inherited by the following "config" elements. + Each "config" element can override the default values, if any. + + A "device" element also has a required "name" attribute that + represents the user-interface name of this device. + + + + + + + + + + + + + + + + + + + + + + + + The parametersType define all the parameters that can happen either in a + "default" element or in a named "config" element. + Each parameter element can appear once at most. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The configType defines the content of a "config" element in a "device" element. + + A "config" element can have all the parameters elements defined by + "parameterType". It also has a required "name" attribute that indicates the + user-interface name for this configuration. + + + + + + + + + + + diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java new file mode 100755 index 000000000..f4ad1bb9b --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.eclipse.adt.internal.sdk; + +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; +import javax.xml.validation.Validator; + +import junit.framework.TestCase; + +/** + * Tests local validation of a Layout-Configs sample XMLs using an XML Schema validator. + */ +public class TestLayoutConfisXsd extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * 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 = ""; + private String mErrors = ""; + + @SuppressWarnings("unused") + public String getErrors() { + return mErrors; + } + + @SuppressWarnings("unused") + public String getWarnings() { + return mWarnings; + } + + /** + * 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"; + } + + /** + * @throws SAXException + */ + public void warning(SAXParseException ex) throws SAXException { + mWarnings += "Warning: " + ex.getMessage() + "\n"; + } + + } + + // --- Helpers ------------ + + /** Helper method that returns a validator for our XSD */ + private Validator getValidator(CaptureErrorHandler handler) throws SAXException { + InputStream xsdStream = LayoutConfigsXsd.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 = + TestLayoutConfisXsd.class.getResourceAsStream("config_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 = ""; + + 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 an unknown element. */ + public void testUnknownContentXml() throws Exception { + String document = "" + + "" + + "" + + ""; + + 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 missing attribute in a device element. */ + public void testIncompleteContentXml() throws Exception { + String document = "" + + "" + + "" + + ""; + + 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.4: Attribute 'name' must appear on element 'd:device'.", e.getMessage()); + return; + } + // If we get here, the validator has not failed as we expected it to. + fail(); + } + + /** A document with a root element containing no device element is not valid. */ + public void testEmptyRootXml() throws Exception { + String document = "" + + ""; + + 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.b: The content of element 'd:layout-configs' is not complete.*", e.getMessage()); + return; + } + // If we get here, the validator has not failed as we expected it to. + fail(); + } + + /** A document with an empty device element is not valid. */ + public void testEmptyDeviceXml() throws Exception { + String document = "" + + "" + + "" + + ""; + + 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.b: The content of element 'd:device' is not complete.*", e.getMessage()); + return; + } + // If we get here, the validator has not failed as we expected it to. + fail(); + } + + /** A document with two default elements in a device element is not valid. */ + public void testTwoDefaultsXml() throws Exception { + String document = "" + + "" + + "" + + " " + + " " + + "" + + ""; + + 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 starting with element 'd:default'.*", e.getMessage()); + return; + } + // If we get here, the validator has not failed as we expected it to. + fail(); + } + + /** The default elements must be defined before the config one. It's invalid if after. */ + public void testDefaultConfigOrderXml() throws Exception { + String document = "" + + "" + + "" + + " " + + " " + + "" + + ""; + + 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 starting with element 'd:default'.*", e.getMessage()); + return; + } + // If we get here, the validator has not failed as we expected it to. + fail(); + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml new file mode 100755 index 000000000..29f48cd10 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml @@ -0,0 +1,129 @@ + + + + + + + small + long + port + ldpi + notouch + keysexposed + nokeys + dpad + + 240 + 480 + + + + + keyshidden + port + + + keyshidden + land + + + keysexposed + land + + + + small + + + medium + + + large + + + + long + + + notlong + + + + port + + + land + + + square + + + + ldpi + + + mdpi + + + hdpi + + + + notouch + + + stylus + + + finger + + + + nokeys + + + qwerty + + + 12key + + + + dpad + + + trackball + + + wheel + + + nonav + + + + + + + + medium + + + +