aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java256
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java256
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationTest.java143
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManagerTest.java185
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleTest.java99
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java797
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ControlPointTest.java73
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilitiesTest.java206
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java368
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinderTest.java128
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeOverlayTest.java75
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutPointTest.java64
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PointTestCases.java107
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLoggerTest.java82
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManagerTest.java120
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttributeTest.java109
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElementTest.java343
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java343
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/MockNodeProxy.java68
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeFactoryTest.java123
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngineTest.java37
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java77
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleterTest.java151
23 files changed, 4210 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java
new file mode 100644
index 000000000..0e528674a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/ExplodeRenderingHelperTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010 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.editors.layout;
+
+import com.android.SdkConstants;
+import com.android.ide.eclipse.adt.internal.editors.mock.MockXmlNode;
+
+import org.w3c.dom.Node;
+
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+public class ExplodeRenderingHelperTest extends TestCase {
+
+ private final HashSet<String> mLayoutNames = new HashSet<String>();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mLayoutNames.add("LinearLayout");
+ mLayoutNames.add("RelativeLayout");
+ }
+
+ public void testSingleHorizontalLinearLayout() {
+ // Single layout, horizontal, 2 buttons.
+ MockXmlNode layout = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()} );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(1, helper.getHeightPadding());
+ assertEquals(1, helper.getWidthPadding());
+ }
+
+ public void testSingleVerticalLinearLayout() {
+ // Single layout, horizontal, with 2 buttons.
+ // LinearLayout(H:[Button Button])
+ MockXmlNode layout = createLinearLayout(false /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()} );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(1, helper.getWidthPadding());
+ assertEquals(1, helper.getHeightPadding());
+ }
+
+ public void testEmbeddedLinearLayouts() {
+ /*
+ * LinearLayout(vertical):
+ * LinearLayout(H:[Button Button])
+ * LinearLayout(H:[Button Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+ MockXmlNode layout = createLinearLayout(false /*horizontal*/,
+ new MockXmlNode[] {
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()}),
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton(), createButton()}),
+ } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void testSimpleRelativeLayoutWithOneLinearLayouts() {
+ /*
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 2 in y
+ */
+ MockXmlNode layout = createRelativeLayout(
+ new MockXmlNode[] {
+ createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()}),
+ } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(2, helper.getHeightPadding());
+ }
+
+ public void /*test*/RelativeLayoutWithVerticalLinearLayouts() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * Children of the relative layouts, one below the other.
+ * Each with only buttons in them.
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ * ^
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+
+ // create the linearlayouts.
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()});
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton()});
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ // position linear2 below linear1
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "layout_below", "@+id/linear1");
+
+
+ MockXmlNode layout = createRelativeLayout(new MockXmlNode[] { linear1, linear2 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void /*test*/RelativeLayoutWithVerticalLinearLayouts2() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * Children of the relative layouts, one above the other.
+ * Each with only buttons in them.
+ * RelativeLayout:
+ * LinearLayout(H:[Button Button])
+ * v
+ * LinearLayout(H:[Button Button])
+ *
+ * Result should be 2 in x, 3 in y
+ */
+
+ // create the linearlayouts.
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton() } );
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton(), createButton() } );
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ // position linear2 below linear1
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/linear1");
+
+
+ MockXmlNode layout = createRelativeLayout(new MockXmlNode[] { linear1, linear2 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(2, helper.getWidthPadding());
+ assertEquals(3, helper.getHeightPadding());
+ }
+
+ public void /*test*/ComplexRelativeLayout() {
+ //FIXME: Reenable once the relative layout are properly supported.
+ /*
+ * RelativeLayout:
+ *
+ * < LinearLayout1(V: [button]) > LinearLayout2(V: [button])
+ * v
+ * Button1 > LinearLayout3(V: [button]) < Button2
+ * v
+ * < LinearLayout4(V: [button])
+ * ^
+ * <LinearLayout5(V: [button])
+ *
+ * Result should be 4 in x, 5 in y
+ */
+
+ // create the elements
+ MockXmlNode button1 = createButton();
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/button1");
+
+ MockXmlNode button2 = createButton();
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/button2");
+
+ MockXmlNode linear1 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear1");
+
+ MockXmlNode linear2 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear2.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear2");
+
+ MockXmlNode linear3 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear3.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear3");
+
+ MockXmlNode linear4 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear4.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear4");
+
+ MockXmlNode linear5 = createLinearLayout(true /*horizontal*/,
+ new MockXmlNode[] { createButton() } );
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "id", "@+id/linear5");
+
+
+ // link them
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toLeftOf", "@+id/linear3");
+
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear3");
+
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear3");
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_toLeftOf", "@+id/linear2");
+ linear1.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/button2");
+
+ linear3.addAttributes(SdkConstants.NS_RESOURCES, "layout_above", "@+id/linear4");
+
+ linear4.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/button1");
+
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "layout_toRightOf", "@+id/linear4");
+ linear5.addAttributes(SdkConstants.NS_RESOURCES, "layout_below", "@+id/linear4");
+
+ MockXmlNode layout = createRelativeLayout(
+ new MockXmlNode[] {
+ button1, button2, linear1, linear2, linear3, linear4, linear5 } );
+
+ ExplodedRenderingHelper helper = new ExplodedRenderingHelper(layout, mLayoutNames);
+ assertEquals(4, helper.getWidthPadding());
+ assertEquals(5, helper.getHeightPadding());
+ }
+
+
+ // ----- helper to deal with mocks
+
+ private MockXmlNode createButton() {
+ return new MockXmlNode(null, "Button", Node.ELEMENT_NODE, null);
+ }
+
+ private MockXmlNode createLinearLayout(boolean horizontal, MockXmlNode[] children) {
+ MockXmlNode layout = new MockXmlNode(null, "LinearLayout", Node.ELEMENT_NODE, children);
+
+ layout.addAttributes(SdkConstants.NS_RESOURCES, "orientation",
+ horizontal ? "horizontal" : "vertical");
+
+ return layout;
+ }
+
+ private MockXmlNode createRelativeLayout(MockXmlNode[] children) {
+ MockXmlNode layout = new MockXmlNode(null, "RelativeLayout", Node.ELEMENT_NODE, children);
+
+ return layout;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java
new file mode 100644
index 000000000..5cac663d7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParserTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2008 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.editors.layout;
+
+import com.android.SdkConstants;
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.mock.MockXmlNode;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.resources.Density;
+
+import org.w3c.dom.Node;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.util.HashMap;
+
+import junit.framework.TestCase;
+
+public class UiElementPullParserTest extends TestCase {
+
+ private UiElementNode ui;
+ private HashMap<String, String> button1Map;
+ private HashMap<String, String> button2Map;
+ private HashMap<String, String> textMap;
+
+ private TextAttributeDescriptor createTextAttrDesc(String xmlName) {
+ return new TextAttributeDescriptor(
+ xmlName, // xmlLocalName
+ SdkConstants.NS_RESOURCES,
+ new AttributeInfo(xmlName, Format.STRING_SET)
+ );
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ // set up some basic descriptors.
+ // We have button, textview, linear layout, relative layout.
+ // only the layouts have children (all 4 descriptors possible)
+ // Also add some dummy attributes.
+ ElementDescriptor buttonDescriptor = new ElementDescriptor("Button", "Button", "", "",
+ new AttributeDescriptor[] {
+ createTextAttrDesc("name"),
+ createTextAttrDesc("text"),
+ },
+ new ElementDescriptor[] {}, false);
+
+ ElementDescriptor textDescriptor = new ElementDescriptor("TextView", "TextView", "", "",
+ new AttributeDescriptor[] {
+ createTextAttrDesc("name"),
+ createTextAttrDesc("text"),
+ },
+ new ElementDescriptor[] {}, false);
+
+ ElementDescriptor linearDescriptor = new ElementDescriptor("LinearLayout", "Linear Layout",
+ "", "",
+ new AttributeDescriptor[] {
+ createTextAttrDesc("orientation"),
+ },
+ new ElementDescriptor[] { }, false);
+
+ ElementDescriptor relativeDescriptor = new ElementDescriptor("RelativeLayout",
+ "Relative Layout", "", "",
+ new AttributeDescriptor[] {
+ createTextAttrDesc("orientation"),
+ },
+ new ElementDescriptor[] { }, false);
+
+ ElementDescriptor[] a = new ElementDescriptor[] {
+ buttonDescriptor, textDescriptor, linearDescriptor, relativeDescriptor
+ };
+
+ linearDescriptor.setChildren(a);
+ relativeDescriptor.setChildren(a);
+
+ // document descriptor
+ ElementDescriptor rootDescriptor = new ElementDescriptor("root", "", "", "",
+ new AttributeDescriptor[] { }, a, false);
+
+
+ ui = new UiElementNode(rootDescriptor);
+
+ /* create a dummy XML file.
+ * <LinearLayout android:orientation="vertical">
+ * <Button android:name="button1" android:text="button1text"/>
+ * <RelativeLayout android:orientation="toto">
+ * <Button android:name="button2" android:text="button2text"/>
+ * <TextView android:name="text1" android:text="text1text"/>
+ * </RelativeLayout>
+ * </LinearLayout>
+ */
+ MockXmlNode button1 = new MockXmlNode(null /* namespace */, "Button", Node.ELEMENT_NODE,
+ null);
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "name", "button1");
+ button1.addAttributes(SdkConstants.NS_RESOURCES, "text", "button1text");
+
+ // create a map of the attributes we add to the multi-attribute nodes so that
+ // we can more easily test the values when we parse the XML.
+ // This is due to some attributes showing in a certain order for a node and in a different
+ // order in another node. Since the order doesn't matter, we just simplify the test.
+ button1Map = new HashMap<String, String>();
+ button1Map.put("name", "button1");
+ button1Map.put("text", "button1text");
+
+ MockXmlNode button2 = new MockXmlNode(null /* namespace */, "Button", Node.ELEMENT_NODE,
+ null);
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "name", "button2");
+ button2.addAttributes(SdkConstants.NS_RESOURCES, "text", "button2text");
+
+ button2Map = new HashMap<String, String>();
+ button2Map.put("name", "button2");
+ button2Map.put("text", "button2text");
+
+ MockXmlNode text = new MockXmlNode(null /* namespace */, "TextView", Node.ELEMENT_NODE,
+ null);
+ text.addAttributes(SdkConstants.NS_RESOURCES, "name", "text1");
+ text.addAttributes(SdkConstants.NS_RESOURCES, "text", "text1text");
+
+ textMap = new HashMap<String, String>();
+ textMap.put("name", "text1");
+ textMap.put("text", "text1text");
+
+ MockXmlNode relative = new MockXmlNode(null /* namespace */, "RelativeLayout",
+ Node.ELEMENT_NODE, new MockXmlNode[] { button2, text });
+ relative.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "toto");
+
+ MockXmlNode linear = new MockXmlNode(null /* namespace */, "LinearLayout",
+ Node.ELEMENT_NODE, new MockXmlNode[] { button1, relative });
+ linear.addAttributes(SdkConstants.NS_RESOURCES, "orientation", "vertical");
+
+ MockXmlNode root = new MockXmlNode(null /* namespace */, "root", Node.ELEMENT_NODE,
+ new MockXmlNode[] { linear });
+
+ // put the namespace/prefix in place
+ root.setPrefix(SdkConstants.NS_RESOURCES, "android");
+
+ // load the xml into the UiElementNode
+ ui.loadFromXmlNode(root);
+
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testParser() {
+ try {
+ // wrap the parser around the ui element node, and start parsing
+ UiElementPullParser parser = new UiElementPullParser(
+ ui, // model
+ false, // explodedView
+ null, // explodeNodes
+ Density.MEDIUM, // density (default from ConfigurationComposite)
+ null // iProject
+ );
+
+ assertEquals(XmlPullParser.START_DOCUMENT, parser.getEventType());
+
+ // top level Linear layout
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("LinearLayout", parser.getName());
+ assertEquals(1, parser.getAttributeCount());
+ assertEquals("orientation", parser.getAttributeName(0));
+ assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(0));
+ assertEquals("android", parser.getAttributePrefix(0));
+ assertEquals("vertical", parser.getAttributeValue(0));
+
+ // Button
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("Button", parser.getName());
+ assertEquals(2, parser.getAttributeCount());
+ check(parser, 0, button1Map);
+ check(parser, 1, button1Map);
+ // end of button
+ assertEquals(XmlPullParser.END_TAG, parser.next());
+
+ // Relative Layout
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("RelativeLayout", parser.getName());
+ assertEquals(1, parser.getAttributeCount());
+ assertEquals("orientation", parser.getAttributeName(0));
+ assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(0));
+ assertEquals("android", parser.getAttributePrefix(0));
+ assertEquals("toto", parser.getAttributeValue(0));
+
+ // Button
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("Button", parser.getName());
+ assertEquals(2, parser.getAttributeCount());
+ check(parser, 0, button2Map);
+ check(parser, 1, button2Map);
+ // end of button
+ assertEquals(XmlPullParser.END_TAG, parser.next());
+
+ // TextView
+ assertEquals(XmlPullParser.START_TAG, parser.next());
+ assertEquals("TextView", parser.getName());
+ assertEquals(2, parser.getAttributeCount());
+ check(parser, 0, textMap);
+ check(parser, 1, textMap);
+ // end of TextView
+ assertEquals(XmlPullParser.END_TAG, parser.next());
+
+ // end of RelativeLayout
+ assertEquals(XmlPullParser.END_TAG, parser.next());
+
+
+ // end of top level linear layout
+ assertEquals(XmlPullParser.END_TAG, parser.next());
+
+ assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ assertTrue(false);
+ }
+ }
+
+ /**
+ * Receives a {@link XmlPullParser} at the START_TAG level, and checks the i-th attribute
+ * to be present in the {@link HashMap} with the proper (name, value)
+ * @param parser
+ * @param i
+ * @param map
+ */
+ private void check(UiElementPullParser parser, int i, HashMap<String, String> map) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+
+ String referenceValue = map.get(name);
+ assertNotNull(referenceValue);
+ assertEquals(referenceValue, value);
+
+ assertEquals(SdkConstants.NS_RESOURCES, parser.getAttributeNamespace(i));
+ assertEquals("android", parser.getAttributePrefix(i));
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationTest.java
new file mode 100644
index 000000000..5b07d7b88
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.editors.layout.configuration;
+
+import static com.android.ide.common.resources.configuration.LocaleQualifier.FAKE_VALUE;
+
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.ide.common.resources.configuration.LocaleQualifier;
+import com.android.resources.Density;
+import com.android.sdklib.devices.Device;
+import com.android.sdklib.devices.DeviceManager;
+import com.android.sdklib.devices.Screen;
+import com.android.utils.StdLogger;
+import com.google.common.collect.Lists;
+
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class ConfigurationTest extends TestCase {
+ private Configuration createConfiguration() throws Exception {
+ // Using reflection instead since we want to pass null to
+ // a constructor marked with @NonNull, so the test won't compile.
+ Constructor<Configuration> constructor =
+ Configuration.class.getDeclaredConstructor(ConfigurationChooser.class);
+ constructor.setAccessible(true);
+ ConfigurationChooser chooser = null;
+ return constructor.newInstance(chooser);
+ }
+
+ public void test() throws Exception {
+ Configuration configuration = createConfiguration();
+ assertNotNull(configuration);
+ configuration.setTheme("@style/Theme");
+ assertEquals("@style/Theme", configuration.getTheme());
+
+ DeviceManager deviceManager = DeviceManager.createInstance(
+ null /*osSdkPath*/,
+ new StdLogger(StdLogger.Level.VERBOSE));
+ Collection<Device> devices = deviceManager.getDevices(DeviceManager.DeviceFilter.DEFAULT);
+ assertNotNull(devices);
+ assertTrue(devices.size() > 0);
+ configuration.setDevice(devices.iterator().next(), false);
+
+ // Check syncing
+ FolderConfiguration folderConfig = configuration.getFullConfig();
+ assertEquals(FAKE_VALUE, folderConfig.getLocaleQualifier().getLanguage());
+ assertEquals(FAKE_VALUE, folderConfig.getLocaleQualifier().getRegion());
+ assertEquals(Locale.ANY, configuration.getLocale());
+
+ Locale language = Locale.create(new LocaleQualifier("nb"));
+ configuration.setLocale(language, true /* skipSync */);
+ assertEquals(FAKE_VALUE, folderConfig.getLocaleQualifier().getLanguage());
+ assertEquals(FAKE_VALUE, folderConfig.getLocaleQualifier().getRegion());
+
+ configuration.setLocale(language, false /* skipSync */);
+ assertEquals(FAKE_VALUE, folderConfig.getLocaleQualifier().getRegion());
+ assertEquals("nb", folderConfig.getLocaleQualifier().getLanguage());
+
+ assertEquals("2.7in QVGA::nb-__:+Theme::notnight::", configuration.toPersistentString());
+
+ configuration.setActivity("foo.bar.FooActivity");
+ configuration.setTheme("@android:style/Theme.Holo.Light");
+
+ assertEquals("2.7in QVGA",
+ ConfigurationChooser.getDeviceLabel(configuration.getDevice(), true));
+ assertEquals("2.7in QVGA",
+ ConfigurationChooser.getDeviceLabel(configuration.getDevice(), false));
+ assertEquals("Light",
+ ConfigurationChooser.getThemeLabel(configuration.getTheme(), true));
+ assertEquals("Theme.Holo.Light",
+ ConfigurationChooser.getThemeLabel(configuration.getTheme(), false));
+ assertEquals("nb",
+ ConfigurationChooser.getLocaleLabel(null, configuration.getLocale(), true));
+ assertEquals("Norwegian Bokm\u00e5l (nb)",
+ ConfigurationChooser.getLocaleLabel(null, configuration.getLocale(), false));
+
+ assertEquals("FooActivity",
+ ConfigurationChooser.getActivityLabel(configuration.getActivity(), true));
+ assertEquals("foo.bar.FooActivity",
+ ConfigurationChooser.getActivityLabel(configuration.getActivity(), false));
+
+ assertEquals("2.7in QVGA::nb-__:-Theme.Holo.Light::notnight::foo.bar.FooActivity",
+ configuration.toPersistentString());
+
+ assertEquals(Density.MEDIUM, configuration.getDensity());
+ Screen screen = configuration.getDevice().getDefaultHardware().getScreen();
+ assertEquals(145.0f, screen.getXdpi(), 0.001);
+ assertEquals(145.0f, screen.getYdpi(), 0.001);
+ }
+
+ public void testCopy() throws Exception {
+ Configuration configuration = createConfiguration();
+ assertNotNull(configuration);
+ configuration.setTheme("@style/Theme");
+ assertEquals("@style/Theme", configuration.getTheme());
+ DeviceManager deviceManager = DeviceManager.createInstance(
+ null /*osSdkPath*/,
+ new StdLogger(StdLogger.Level.VERBOSE));
+ List<Device> devices = Lists.newArrayList(deviceManager.getDevices(DeviceManager.DeviceFilter.DEFAULT));
+ assertNotNull(devices);
+ assertTrue(devices.size() > 0);
+ configuration.setDevice(devices.get(0), false);
+ configuration.setActivity("foo.bar.FooActivity");
+ configuration.setTheme("@android:style/Theme.Holo.Light");
+ Locale locale = Locale.create(new LocaleQualifier("nb"));
+ configuration.setLocale(locale, false /* skipSync */);
+
+ Configuration copy = Configuration.copy(configuration);
+ assertEquals(locale, copy.getLocale());
+ assertEquals("foo.bar.FooActivity", copy.getActivity());
+ assertEquals("@android:style/Theme.Holo.Light", copy.getTheme());
+ assertEquals(devices.get(0), copy.getDevice());
+
+ // Make sure edits to master does not affect the child
+ configuration.setLocale(Locale.ANY, false);
+ configuration.setTheme("@android:style/Theme.Holo");
+ configuration.setDevice(devices.get(1), true);
+
+ assertTrue(copy.getFullConfig().getLocaleQualifier().equals(locale.qualifier));
+ assertEquals(locale, copy.getLocale());
+ assertEquals("foo.bar.FooActivity", copy.getActivity());
+ assertEquals("@android:style/Theme.Holo.Light", copy.getTheme());
+ assertEquals(devices.get(0), copy.getDevice());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManagerTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManagerTest.java
new file mode 100644
index 000000000..4286aaa30
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManagerTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2012 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.editors.layout.configuration;
+
+import com.android.SdkConstants;
+import com.android.ide.common.resources.LocaleManager;
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+
+import org.eclipse.swt.graphics.Image;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class FlagManagerTest extends TestCase {
+ public void testGetFlagImage() {
+ FlagManager manager = FlagManager.get();
+ Image us = manager.getFlag("US");
+ Image gb = manager.getFlag("GB");
+ Image ca = manager.getFlag("CA");
+ Image es = manager.getFlag("ES");
+ Image br = manager.getFlag("BR");
+ Image pt = manager.getFlag("PT");
+ assertSame(us, manager.getFlag("en", "US"));
+ assertSame(gb, manager.getFlag("en", "GB"));
+ assertSame(ca, manager.getFlag("en", "CA"));
+ Locale.setDefault(Locale.US);
+ assertSame(us, manager.getFlag("en", null));
+ Locale.setDefault(Locale.UK);
+ assertSame(gb, manager.getFlag("en", null));
+ Locale.setDefault(Locale.CANADA);
+ assertSame(ca, manager.getFlag("en", null));
+ assertSame(manager.getFlag("NO"), manager.getFlag("nb", null));
+ assertSame(manager.getFlag("FR"), manager.getFlag("fr", null));
+
+ Locale.setDefault(new Locale("pt", "br"));
+ assertSame(br, manager.getFlag("pt", null));
+ assertSame(pt, manager.getFlag("pt", "PT"));
+ Locale.setDefault(new Locale("pt", "pt"));
+ assertSame(pt, manager.getFlag("pt", null));
+ assertSame(br, manager.getFlag("pt", "BR"));
+
+ // Special cases where we have custom flags
+ assertNotSame(gb, manager.getFlag("cy", null)); // Wales
+ assertNotSame(es, manager.getFlag("ca", null)); // Catalonia
+
+ // Aliases - http://developer.android.com/reference/java/util/Locale.html
+ assertSame(manager.getFlag("yi", null), manager.getFlag("ji", null));
+ assertSame(manager.getFlag("in", null), manager.getFlag("id", null));
+ assertSame(manager.getFlag("iw", null), manager.getFlag("he", null));
+ assertSame(us, manager.getFlagForFolderName("values-en-rUS"));
+ assertSame(gb, manager.getFlagForFolderName("values-en-rGB"));
+ Locale.setDefault(Locale.CANADA);
+ assertSame(ca, manager.getFlagForFolderName("values-en"));
+ }
+
+ public void testAvailableImages() {
+ // Images we have from WindowBuilder (which are really the famfamfam
+ // icons;
+ // see http://www.famfamfam.com/lab/icons/flags)
+ String[] icons = new String[] {
+ "ad", "ae", "af", "ag", "ai", "al", "am", "ao", "ar", "as", "at", "au", "aw", "ax",
+ "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "br",
+ "bs", "bt", "bv", "bw", "by", "bz", "ca", "catalonia", "cc", "cd", "cf", "cg",
+ "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cx", "cy", "cz", "de",
+ "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "england", "er", "es", "et",
+ "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi",
+ "gl", "gm", "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn",
+ "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "jm",
+ "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", "la",
+ "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me",
+ "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv",
+ "mw", "mx", "my", "mz", "na", "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr",
+ "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", "ps",
+ "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "scotland",
+ "sd", "se", "sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st",
+ "sv", "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to",
+ "tr", "tt", "tv", "tw", "tz", "ua", "ug", "um", "us", "uy", "uz", "va", "vc", "ve",
+ "vg", "vi", "vn", "vu", "wales", "wf", "ws", "ye", "yt", "za", "zm", "zw"
+ };
+
+ Set<String> sImages = new HashSet<String>(100);
+ for (String code : icons) {
+ if (code.length() > 2) {
+ continue;
+ }
+ code = code.toUpperCase(Locale.US);
+ sImages.add(code);
+
+ if (!LocaleManager.isValidRegionCode(code)) {
+ System.out.println("No region name found for region code " + code);
+ }
+ }
+
+ Set<String> unused = Sets.newHashSet(LocaleManager.getRegionCodes(false));
+ Set<String> reachable = Sets.newHashSet();
+ Multimap<String, String> regionToLanguages = ArrayListMultimap.create();
+ for (String language : LocaleManager.getLanguageCodes(false)) {
+ for (String region : LocaleManager.getRelevantRegions(language)) {
+ reachable.add(region);
+ regionToLanguages.put(region, language);
+ }
+ }
+ unused.removeAll(reachable);
+
+ for (String region : reachable) {
+ if (!sImages.contains(region)) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("No icon found for region ").append(region).append(" ")
+ .append(LocaleManager.getRegionName(region));
+ sb.append(", used for languages ");
+
+ for (String language : regionToLanguages.get(region)) {
+ sb.append(language).append("(").append(LocaleManager.getLanguageName(language))
+ .append(") ");
+ }
+ System.out.println(sb.toString());
+ }
+ }
+
+ // Known regions that we don't have language to region mappings for
+ unused.remove("AQ");
+ unused.remove("VA");
+ unused.remove("GS");
+ unused.remove("TF");
+ unused.remove("BV");
+ unused.remove("HM");
+
+ if (!unused.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("The following icons are not referenced by any of the "
+ + "language to country bindings:");
+ for (String code : unused) {
+ sb.append(code.toLowerCase(Locale.US)).append(SdkConstants.DOT_PNG).append(" (");
+ sb.append(LocaleManager.getRegionName(code)).append(") ");
+ }
+ System.out.println(sb.toString());
+ }
+ }
+
+ public void testMissingFlag() {
+ Image icon = FlagManager.get().getFlag("AQ");
+ assertNotNull(icon);
+ assertSame(FlagManager.get().getEmptyIcon(), icon);
+
+ icon = FlagManager.get().getFlag("AQ");
+ assertNotNull(icon);
+ assertSame(FlagManager.get().getEmptyIcon(), icon);
+
+ icon = FlagManager.get().getFlag("WO"); // Not used in ISO 3166-1
+ assertNotNull(icon);
+ assertSame(FlagManager.get().getEmptyIcon(), icon);
+ }
+
+ public void testKnownFlag() {
+ Image icon = FlagManager.get().getFlag("US");
+ assertNotNull(icon);
+ assertNotSame(FlagManager.get().getEmptyIcon(), icon);
+ }
+}
+
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleTest.java
new file mode 100644
index 000000000..904ade39c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 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.editors.layout.configuration;
+
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.ide.common.resources.configuration.LocaleQualifier;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class LocaleTest extends TestCase {
+ public void test1() {
+ Locale locale = Locale.create("en-rUS");
+ assertEquals("en", locale.qualifier.getLanguage());
+ assertEquals("US", locale.qualifier.getRegion());
+ assertTrue(locale.hasLanguage());
+ assertTrue(locale.hasRegion());
+ }
+
+ public void test2() {
+ Locale locale = Locale.create("zh");
+ assertEquals("zh", locale.qualifier.getLanguage());
+ assertNull(locale.qualifier.getRegion());
+ assertTrue(locale.hasLanguage());
+ assertFalse(locale.hasRegion());
+ }
+
+ public void testEquals() {
+ Locale locale = Locale.create("zh");
+ assertEquals("zh", locale.qualifier.getLanguage());
+ assertNull(locale.qualifier.getRegion());
+ assertTrue(locale.hasLanguage());
+ assertFalse(locale.hasRegion());
+ }
+
+ public void test() {
+ LocaleQualifier qualifier1 = LocaleQualifier.getQualifier("nb");
+ LocaleQualifier qualifier2 = LocaleQualifier.getQualifier("no");
+ LocaleQualifier qualifier3 = LocaleQualifier.getQualifier("nb-rNO");
+ LocaleQualifier qualifier4 = LocaleQualifier.getQualifier("nb-rSE");
+ LocaleQualifier qualifier5 = LocaleQualifier.getQualifier("no-rSE");
+ assertNotNull(qualifier1);
+ assertNotNull(qualifier2);
+ assertNotNull(qualifier3);
+ assertNotNull(qualifier4);
+ assertNotNull(qualifier5);
+
+ assertEquals(Locale.ANY, Locale.ANY);
+ assertFalse(Locale.ANY.hasLanguage());
+ assertFalse(Locale.ANY.hasRegion());
+ // noinspection ConstantConditions
+ assertFalse(Locale.create(new LocaleQualifier(LocaleQualifier.FAKE_VALUE)).hasLanguage());
+ // noinspection ConstantConditions
+ assertFalse(Locale.create(new LocaleQualifier(LocaleQualifier.FAKE_VALUE)).hasRegion());
+
+ assertEquals(Locale.create(qualifier1), Locale.create(qualifier1));
+ assertTrue(Locale.create(qualifier1).hasLanguage());
+ assertFalse(Locale.create(qualifier1).hasRegion());
+ assertTrue(Locale.create(qualifier3).hasLanguage());
+ assertTrue(Locale.create(qualifier3).hasRegion());
+
+ assertEquals(Locale.create(qualifier3), Locale.create(qualifier3));
+ assertEquals(Locale.create(qualifier1), Locale.create(qualifier1));
+ assertTrue(Locale.create(qualifier1).equals(Locale.create(qualifier1)));
+ assertTrue(Locale.create(qualifier3).equals(Locale.create(qualifier3)));
+ assertFalse(Locale.create(qualifier3).equals(Locale.create(qualifier4)));
+ assertFalse(Locale.create(qualifier1).equals(Locale.create(qualifier3)));
+ assertFalse(Locale.create(qualifier1).equals(Locale.create(qualifier2)));
+ assertFalse(Locale.create(qualifier3).equals(Locale.create(qualifier5)));
+ assertEquals("nb", Locale.create(qualifier1).toString());
+ assertEquals("nb-NO", Locale.create(qualifier3).toString());
+
+ assertEquals(Locale.create(qualifier1), Locale.create("b+nb"));
+ assertEquals(Locale.create(qualifier3), Locale.create("b+nb+NO"));
+ }
+
+ public void testFolderConfig() {
+ FolderConfiguration config = new FolderConfiguration();
+ assertEquals(Locale.ANY, Locale.create(config));
+ config.setLocaleQualifier(LocaleQualifier.getQualifier("en"));
+ assertEquals(Locale.create("en"), Locale.create(config));
+ config.setLocaleQualifier(LocaleQualifier.getQualifier("en-rUS"));
+ assertEquals(Locale.create("en-rUS"), Locale.create(config));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java
new file mode 100644
index 000000000..5996f01c0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import com.android.ide.common.rendering.api.Capability;
+import com.android.ide.common.rendering.api.DataBindingItem;
+import com.android.ide.common.rendering.api.MergeCookie;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.utils.Pair;
+
+import org.eclipse.swt.graphics.Rectangle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class CanvasViewInfoTest extends TestCase {
+
+ public static ViewElementDescriptor createDesc(String name, String fqn, boolean hasChildren) {
+ if (hasChildren) {
+ return new ViewElementDescriptor(name, name, fqn, "", "", new AttributeDescriptor[0],
+ new AttributeDescriptor[0], new ElementDescriptor[1], false);
+ } else {
+ return new ViewElementDescriptor(name, fqn);
+ }
+ }
+
+ public static UiViewElementNode createNode(UiViewElementNode parent, String fqn,
+ boolean hasChildren) {
+ String name = fqn.substring(fqn.lastIndexOf('.') + 1);
+ ViewElementDescriptor descriptor = createDesc(name, fqn, hasChildren);
+ if (parent == null) {
+ // All node hierarchies should be wrapped inside a document node at the root
+ parent = new UiViewElementNode(createDesc("doc", "doc", true));
+ }
+ return (UiViewElementNode) parent.appendNewUiChild(descriptor);
+ }
+
+ public static UiViewElementNode createNode(String fqn, boolean hasChildren) {
+ return createNode(null, fqn, hasChildren);
+ }
+
+ public void testNormalCreate() throws Exception {
+ normal(true);
+ }
+
+ public void testNormalCreateLayoutLib5() throws Exception {
+ normal(false);
+ }
+
+ private void normal(boolean layoutlib5) {
+
+ // Normal view hierarchy, no null keys anywhere
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("Button", child1Node, 0, 0, 50, 20);
+ UiViewElementNode child2Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child2 = new ViewInfo("Button", child2Node, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertSame(rootView.getUiViewNode(), rootNode);
+ assertEquals(2, rootView.getChildren().size());
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+ CanvasViewInfo childView2 = rootView.getChildren().get(1);
+
+ assertEquals("Button", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), child1Node);
+
+ assertEquals("Button", childView2.getName());
+ assertSame(rootView, childView2.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), childView2.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), childView2.getSelectionRect());
+ assertSame(childView2.getUiViewNode(), child2Node);
+ }
+
+ public void testShowIn() throws Exception {
+ showIn(false);
+ }
+
+ public void testShowInLayoutLib5() throws Exception {
+ showIn(true);
+ }
+
+ public void showIn(boolean layoutlib5) throws Exception {
+
+ // Test rendering of "Show Included In" (included content rendered
+ // within an outer content that has null keys)
+
+ ViewInfo root = new ViewInfo("LinearLayout", null, 10, 10, 100, 100);
+ ViewInfo child1 = new ViewInfo("CheckBox", null, 0, 0, 50, 20);
+ UiViewElementNode child2Node = createNode("android.widget.RelativeLayout", true);
+ ViewInfo child2 = new ViewInfo("RelativeLayout", child2Node, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+ UiViewElementNode child21Node = createNode("android.widget.Button", false);
+ ViewInfo child21 = new ViewInfo("RadioButton", child21Node, 0, 20, 70, 25);
+ child2.setChildren(Arrays.asList(child21));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertNull(rootView.getUiViewNode());
+ assertEquals(1, rootView.getChildren().size());
+ CanvasViewInfo includedView = rootView.getChildren().get(0);
+
+ assertEquals("RelativeLayout", includedView.getName());
+ assertSame(rootView, includedView.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect());
+ assertSame(includedView.getUiViewNode(), child2Node);
+
+ CanvasViewInfo grandChild = includedView.getChildren().get(0);
+ assertNotNull(grandChild);
+ assertEquals("RadioButton", grandChild.getName());
+ assertSame(child21Node, grandChild.getUiViewNode());
+ assertEquals(new Rectangle(10, 50, 69, 4), grandChild.getAbsRect());
+ assertEquals(new Rectangle(10, 50, 69, 5), grandChild.getSelectionRect());
+ }
+
+ public void testIncludeTag() throws Exception {
+ boolean layoutlib5 = true;
+
+ // Test rendering of included views on layoutlib 5+ (e.g. has <include> tag)
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20);
+ UiViewElementNode child2Node = createNode(rootNode, "include", true);
+ ViewInfo child2 = new ViewInfo("RelativeLayout", child2Node, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+ ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25);
+ child2.setChildren(Arrays.asList(child21));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(2, rootView.getChildren().size());
+
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+ CanvasViewInfo includedView = rootView.getChildren().get(1);
+
+ assertEquals("CheckBox", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), child1Node);
+
+ assertEquals("RelativeLayout", includedView.getName());
+ assertSame(rootView, includedView.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect());
+ assertSame(includedView.getUiViewNode(), child2Node);
+ assertEquals(0, includedView.getChildren().size());
+ }
+
+ public void testNoIncludeTag() throws Exception {
+ boolean layoutlib5 = false;
+
+ // Test rendering of included views on layoutlib 4- (e.g. no <include> tag cookie
+ // in view info)
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20);
+ UiViewElementNode child2Node = createNode(rootNode, "include", true);
+ ViewInfo child2 = new ViewInfo("RelativeLayout", null /* layoutlib 4 */, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+ ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25);
+ child2.setChildren(Arrays.asList(child21));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(2, rootView.getChildren().size());
+
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+ CanvasViewInfo includedView = rootView.getChildren().get(1);
+
+ assertEquals("CheckBox", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), child1Node);
+
+ assertEquals("RelativeLayout", includedView.getName());
+ assertSame(rootView, includedView.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect());
+ assertSame(includedView.getUiViewNode(), child2Node);
+ assertEquals(0, includedView.getChildren().size());
+ }
+
+ public void testMergeMatching() throws Exception {
+ boolean layoutlib5 = false;
+
+ // Test rendering of MULTIPLE included views or when there is no simple match
+ // between view info and ui element node children
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20);
+ UiViewElementNode multiChildNode1 = createNode(rootNode, "foo", true);
+ UiViewElementNode multiChildNode2 = createNode(rootNode, "bar", true);
+ ViewInfo child2 = new ViewInfo("RelativeLayout", null, 0, 20, 70, 25);
+ ViewInfo child3 = new ViewInfo("AbsoluteLayout", null, 10, 40, 50, 15);
+ root.setChildren(Arrays.asList(child1, child2, child3));
+ ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25);
+ child2.setChildren(Arrays.asList(child21));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertTrue(rootView.isRoot());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(3, rootView.getChildren().size());
+
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+ assertFalse(childView1.isRoot());
+ CanvasViewInfo includedView1 = rootView.getChildren().get(1);
+ assertFalse(includedView1.isRoot());
+ CanvasViewInfo includedView2 = rootView.getChildren().get(2);
+ assertFalse(includedView1.isRoot());
+
+ assertEquals("CheckBox", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), child1Node);
+
+ assertEquals("RelativeLayout", includedView1.getName());
+ assertSame(multiChildNode1, includedView1.getUiViewNode());
+ assertEquals("foo", includedView1.getUiViewNode().getDescriptor().getXmlName());
+ assertSame(multiChildNode2, includedView2.getUiViewNode());
+ assertEquals("AbsoluteLayout", includedView2.getName());
+ assertEquals("bar", includedView2.getUiViewNode().getDescriptor().getXmlName());
+ assertSame(rootView, includedView1.getParent());
+ assertSame(rootView, includedView2.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), includedView1.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), includedView1.getSelectionRect());
+ assertEquals(new Rectangle(20, 50, 39, -26), includedView2.getAbsRect());
+ assertEquals(new Rectangle(20, 35, 39, 5), includedView2.getSelectionRect());
+ assertEquals(0, includedView1.getChildren().size());
+ assertEquals(0, includedView2.getChildren().size());
+ }
+
+ public void testMerge() throws Exception {
+ boolean layoutlib5 = false;
+
+ // Test rendering of MULTIPLE included views or when there is no simple match
+ // between view info and ui element node children
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20);
+ UiViewElementNode multiChildNode = createNode(rootNode, "foo", true);
+ ViewInfo child2 = new ViewInfo("RelativeLayout", null, 0, 20, 70, 25);
+ ViewInfo child3 = new ViewInfo("AbsoluteLayout", null, 10, 40, 50, 15);
+ root.setChildren(Arrays.asList(child1, child2, child3));
+ ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25);
+ child2.setChildren(Arrays.asList(child21));
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("LinearLayout", rootView.getName());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(2, rootView.getChildren().size());
+
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+ CanvasViewInfo includedView = rootView.getChildren().get(1);
+
+ assertEquals("CheckBox", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), child1Node);
+
+ assertEquals("RelativeLayout", includedView.getName());
+ assertSame(rootView, includedView.getParent());
+ assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect());
+ assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect());
+ assertEquals(0, includedView.getChildren().size());
+ assertSame(multiChildNode, includedView.getUiViewNode());
+ }
+
+ public void testInsertMerge() throws Exception {
+ boolean layoutlib5 = false;
+
+ // Test rendering of MULTIPLE included views or when there is no simple match
+ // between view info and ui element node children
+
+ UiViewElementNode mergeNode = createNode("merge", true);
+ UiViewElementNode rootNode = createNode(mergeNode, "android.widget.Button", false);
+ ViewInfo root = new ViewInfo("Button", rootNode, 10, 10, 100, 100);
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("merge", rootView.getName());
+ assertSame(rootView.getUiViewNode(), mergeNode);
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect());
+ assertNull(rootView.getParent());
+ assertSame(mergeNode, rootView.getUiViewNode());
+ assertEquals(1, rootView.getChildren().size());
+
+ CanvasViewInfo childView1 = rootView.getChildren().get(0);
+
+ assertEquals("Button", childView1.getName());
+ assertSame(rootView, childView1.getParent());
+ assertEquals(new Rectangle(10, 10, 89, 89), childView1.getAbsRect());
+ assertEquals(new Rectangle(10, 10, 89, 89), childView1.getSelectionRect());
+ assertSame(childView1.getUiViewNode(), rootNode);
+ }
+
+ public void testUnmatchedMissing() throws Exception {
+ boolean layoutlib5 = false;
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100);
+ List<ViewInfo> children = new ArrayList<ViewInfo>();
+ // Should be matched up with corresponding node:
+ Set<Integer> missingKeys = new HashSet<Integer>();
+ // Should not be matched with any views, but should get view created:
+ Set<Integer> extraKeys = new HashSet<Integer>();
+ // Should not be matched with any nodes
+ Set<Integer> extraViews = new HashSet<Integer>();
+ int numViews = 30;
+ missingKeys.add(0);
+ missingKeys.add(4);
+ missingKeys.add(14);
+ missingKeys.add(29);
+ extraKeys.add(9);
+ extraKeys.add(20);
+ extraKeys.add(22);
+ extraViews.add(18);
+ extraViews.add(24);
+
+ List<String> expectedViewNames = new ArrayList<String>();
+ List<String> expectedNodeNames = new ArrayList<String>();
+
+ for (int i = 0; i < numViews; i++) {
+ UiViewElementNode childNode = null;
+ if (!extraViews.contains(i)) {
+ childNode = createNode(rootNode, "childNode" + i, false);
+ }
+ Object cookie = missingKeys.contains(i) || extraViews.contains(i) ? null : childNode;
+ ViewInfo childView = new ViewInfo("childView" + i, cookie,
+ 0, i * 20, 50, (i + 1) * 20);
+ children.add(childView);
+
+ if (!extraViews.contains(i)) {
+ expectedViewNames.add("childView" + i);
+ expectedNodeNames.add("childNode" + i);
+ }
+
+ if (extraKeys.contains(i)) {
+ createNode(rootNode, "extraNodeAt" + i, false);
+
+ expectedViewNames.add("extraNodeAt" + i);
+ expectedNodeNames.add("extraNodeAt" + i);
+ }
+ }
+ root.setChildren(children);
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+
+ // dump(root, 0);
+ // dump(rootView, 0);
+
+ assertEquals("LinearLayout", rootView.getName());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(numViews + extraKeys.size() - extraViews.size(), rootNode.getUiChildren()
+ .size());
+ assertEquals(numViews + extraKeys.size() - extraViews.size(),
+ rootView.getChildren().size());
+ assertEquals(expectedViewNames.size(), rootView.getChildren().size());
+ for (int i = 0, n = rootView.getChildren().size(); i < n; i++) {
+ CanvasViewInfo childView = rootView.getChildren().get(i);
+ String expectedViewName = expectedViewNames.get(i);
+ String expectedNodeName = expectedNodeNames.get(i);
+ assertEquals(expectedViewName, childView.getName());
+ assertNotNull(childView.getUiViewNode());
+ assertEquals(expectedNodeName, childView.getUiViewNode().getDescriptor().getXmlName());
+ }
+ }
+
+ public void testMergeCookies() throws Exception {
+ boolean layoutlib5 = true;
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100);
+
+ // Create the merge cookies in the opposite order to ensure that we don't
+ // apply our own logic when matching up views with nodes
+ LinkedList<MergeCookie> cookies = new LinkedList<MergeCookie>();
+ for (int i = 0; i < 10; i++) {
+ UiViewElementNode node = createNode(rootNode, "childNode" + i, false);
+ cookies.addFirst(new MergeCookie(node));
+ }
+ Iterator<MergeCookie> it = cookies.iterator();
+ ArrayList<ViewInfo> children = new ArrayList<ViewInfo>();
+ for (int i = 0; i < 10; i++) {
+ ViewInfo childView = new ViewInfo("childView" + i, it.next(), 0, i * 20, 50,
+ (i + 1) * 20);
+ children.add(childView);
+ }
+ root.setChildren(children);
+
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+
+ assertEquals("LinearLayout", rootView.getName());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ for (int i = 0, n = rootView.getChildren().size(); i < n; i++) {
+ CanvasViewInfo childView = rootView.getChildren().get(i);
+ assertEquals("childView" + i, childView.getName());
+ assertEquals("childNode" + (9 - i), childView.getUiViewNode().getDescriptor()
+ .getXmlName());
+ }
+ }
+
+ public void testMergeCookies2() throws Exception {
+ boolean layoutlib5 = true;
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100);
+
+ UiViewElementNode node1 = createNode(rootNode, "childNode1", false);
+ UiViewElementNode node2 = createNode(rootNode, "childNode2", false);
+ MergeCookie cookie1 = new MergeCookie(node1);
+ MergeCookie cookie2 = new MergeCookie(node2);
+
+ // Sets alternating merge cookies and checks whether the node sibling lists are
+ // okay and merged correctly
+
+ ArrayList<ViewInfo> children = new ArrayList<ViewInfo>();
+ for (int i = 0; i < 10; i++) {
+ Object cookie = (i % 2) == 0 ? cookie1 : cookie2;
+ ViewInfo childView = new ViewInfo("childView" + i, cookie, 0, i * 20, 50,
+ (i + 1) * 20);
+ children.add(childView);
+ }
+ root.setChildren(children);
+
+ Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5);
+ CanvasViewInfo rootView = result.getFirst();
+ List<Rectangle> bounds = result.getSecond();
+ assertNull(bounds);
+ assertNotNull(rootView);
+
+ assertEquals("LinearLayout", rootView.getName());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(10, rootView.getChildren().size());
+ assertEquals(2, rootView.getUniqueChildren().size());
+ for (int i = 0, n = rootView.getChildren().size(); i < n; i++) {
+ CanvasViewInfo childView = rootView.getChildren().get(i);
+ assertEquals("childView" + i, childView.getName());
+ Object cookie = (i % 2) == 0 ? node1 : node2;
+ assertSame(cookie, childView.getUiViewNode());
+ List<CanvasViewInfo> nodeSiblings = childView.getNodeSiblings();
+ assertEquals(5, nodeSiblings.size());
+ }
+ List<CanvasViewInfo> nodeSiblings = rootView.getChildren().get(0).getNodeSiblings();
+ for (int j = 0; j < 5; j++) {
+ assertEquals("childView" + (j * 2), nodeSiblings.get(j).getName());
+ }
+ nodeSiblings = rootView.getChildren().get(1).getNodeSiblings();
+ for (int j = 0; j < 5; j++) {
+ assertEquals("childView" + (j * 2 + 1), nodeSiblings.get(j).getName());
+ }
+ }
+
+ public void testIncludeBounds() throws Exception {
+ boolean layoutlib5 = true;
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100);
+
+ UiViewElementNode node1 = createNode(rootNode, "childNode1", false);
+ UiViewElementNode node2 = createNode(rootNode, "childNode2", false);
+ MergeCookie cookie1 = new MergeCookie(node1);
+ MergeCookie cookie2 = new MergeCookie(node2);
+
+ // Sets alternating merge cookies and checks whether the node sibling lists are
+ // okay and merged correctly
+
+ ArrayList<ViewInfo> children = new ArrayList<ViewInfo>();
+ for (int i = 0; i < 10; i++) {
+ Object cookie = (i % 2) == 0 ? cookie1 : cookie2;
+ ViewInfo childView = new ViewInfo("childView" + i, cookie, 0, i * 20, 50,
+ (i + 1) * 20);
+ children.add(childView);
+ }
+ root.setChildren(children);
+
+ Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5);
+ CanvasViewInfo rootView = result.getFirst();
+ List<Rectangle> bounds = result.getSecond();
+ assertNotNull(rootView);
+
+ assertEquals("included", rootView.getName());
+ assertNull(rootView.getParent());
+ assertNull(rootView.getUiViewNode());
+ assertEquals(10, rootView.getChildren().size());
+ assertEquals(2, rootView.getUniqueChildren().size());
+ for (int i = 0, n = rootView.getChildren().size(); i < n; i++) {
+ CanvasViewInfo childView = rootView.getChildren().get(i);
+ assertEquals("childView" + i, childView.getName());
+ Object cookie = (i % 2) == 0 ? node1 : node2;
+ assertSame(cookie, childView.getUiViewNode());
+ List<CanvasViewInfo> nodeSiblings = childView.getNodeSiblings();
+ assertEquals(5, nodeSiblings.size());
+ }
+ List<CanvasViewInfo> nodeSiblings = rootView.getChildren().get(0).getNodeSiblings();
+ for (int j = 0; j < 5; j++) {
+ assertEquals("childView" + (j * 2), nodeSiblings.get(j).getName());
+ }
+ nodeSiblings = rootView.getChildren().get(1).getNodeSiblings();
+ for (int j = 0; j < 5; j++) {
+ assertEquals("childView" + (j * 2 + 1), nodeSiblings.get(j).getName());
+ }
+
+ // Only show the primary bounds as included
+ assertEquals(2, bounds.size());
+ assertEquals(new Rectangle(0, 0, 49, 19), bounds.get(0));
+ assertEquals(new Rectangle(0, 20, 49, 19), bounds.get(1));
+ }
+
+ public void testIncludeBounds2() throws Exception {
+ includeBounds2(false);
+ }
+
+ public void testIncludeBounds2LayoutLib5() throws Exception {
+ includeBounds2(true);
+ }
+
+ public void includeBounds2(boolean layoutlib5) throws Exception {
+
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100);
+
+ UiViewElementNode node1 = createNode(rootNode, "childNode1", false);
+ UiViewElementNode node2 = createNode(rootNode, "childNode2", false);
+
+ ViewInfo childView1 = new ViewInfo("childView1", node1, 0, 20, 50, 40);
+ ViewInfo childView2 = new ViewInfo("childView2", node2, 0, 40, 50, 60);
+
+ root.setChildren(Arrays.asList(childView1, childView2));
+
+ Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5);
+ CanvasViewInfo rootView = result.getFirst();
+ List<Rectangle> bounds = result.getSecond();
+ assertNotNull(rootView);
+
+ assertEquals("included", rootView.getName());
+ assertNull(rootView.getParent());
+ assertNull(rootView.getUiViewNode());
+ assertEquals(2, rootView.getChildren().size());
+ assertEquals(2, rootView.getUniqueChildren().size());
+
+ Rectangle bounds1 = bounds.get(0);
+ Rectangle bounds2 = bounds.get(1);
+ assertEquals(new Rectangle(0, 20, 49, 19), bounds1);
+ assertEquals(new Rectangle(0, 40, 49, 19), bounds2);
+ }
+
+ public void testCookieWorkaround() throws Exception {
+ UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true);
+ ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100);
+
+ UiViewElementNode node2 = createNode(rootNode, "childNode2", false);
+ MergeCookie mergeCookie = new MergeCookie(root);
+
+ ViewInfo childView1 = new ViewInfo("childView1", mergeCookie, 0, 20, 50, 40);
+ ViewInfo childView2 = new ViewInfo("childView2", node2, 0, 40, 50, 60);
+
+ root.setChildren(Arrays.asList(childView1, childView2));
+
+ Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, true);
+ CanvasViewInfo rootView = result.getFirst();
+ List<Rectangle> bounds = result.getSecond();
+ assertNotNull(rootView);
+
+ assertEquals("included", rootView.getName());
+ assertNull(rootView.getParent());
+ assertNull(rootView.getUiViewNode());
+ // childView1 should have been removed since it has the wrong merge cookie
+ assertEquals(1, rootView.getChildren().size());
+ assertEquals(1, rootView.getUniqueChildren().size());
+
+ Rectangle bounds1 = bounds.get(0);
+ assertEquals(new Rectangle(0, 40, 49, 19), bounds1);
+ }
+
+ public void testGestureOverlayView() throws Exception {
+ boolean layoutlib5 = true;
+
+ // Test rendering of included views on layoutlib 5+ (e.g. has <include> tag)
+
+ UiViewElementNode rootNode = createNode("android.gesture.GestureOverlayView", true);
+ UiViewElementNode childNode = createNode(rootNode, "android.widget.LinearLayout", false);
+ UiViewElementNode grandChildNode = createNode(childNode, "android.widget.Button", false);
+ ViewInfo root = new ViewInfo("GestureOverlayView", rootNode, 10, 10, 100, 100);
+ ViewInfo child = new ViewInfo("LinearLayout", childNode, 0, 0, 50, 20);
+ root.setChildren(Collections.singletonList(child));
+ ViewInfo grandChild = new ViewInfo("Button", grandChildNode, 0, 20, 70, 25);
+ child.setChildren(Collections.singletonList(grandChild));
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst();
+ assertNotNull(rootView);
+ assertEquals("GestureOverlayView", rootView.getName());
+
+ assertTrue(rootView.isRoot());
+ assertNull(rootView.getParent());
+ assertSame(rootNode, rootView.getUiViewNode());
+ assertEquals(1, rootView.getChildren().size());
+
+ CanvasViewInfo childView = rootView.getChildren().get(0);
+ assertEquals("LinearLayout", childView.getName());
+
+ // This should also be a root for the special case that the root is
+ assertTrue(childView.isRoot());
+
+ assertEquals(1, childView.getChildren().size());
+ CanvasViewInfo grandChildView = childView.getChildren().get(0);
+ assertEquals("Button", grandChildView.getName());
+ assertFalse(grandChildView.isRoot());
+ }
+
+ public void testListView() throws Exception {
+ // For ListViews we get AdapterItemReferences as cookies. Ensure that this
+ // works properly.
+ //
+ // android.widget.FrameLayout [0,50,320,480] <FrameLayout>
+ // android.widget.ListView [0,0,320,430] <ListView>
+ // android.widget.LinearLayout [0,0,320,17] SessionParams$AdapterItemReference
+ // android.widget.TextView [0,0,73,17]
+ // android.widget.LinearLayout [0,18,320,35] SessionParams$AdapterItemReference
+ // android.widget.TextView [0,0,73,17]
+ // android.widget.LinearLayout [0,36,320,53] SessionParams$AdapterItemReference
+ // android.widget.TextView [0,0,73,17]
+ // ...
+
+ UiViewElementNode rootNode = createNode("FrameLayout", true);
+ UiViewElementNode childNode = createNode(rootNode, "ListView", false);
+ /*UiViewElementNode grandChildNode =*/ createNode(childNode, "LinearLayout", false);
+ /*UiViewElementNode greatGrandChildNode =*/ createNode(childNode, "TextView", false);
+ DataBindingItem dataBindingItem = new DataBindingItem("foo");
+
+ ViewInfo root = new ViewInfo("FrameLayout", rootNode, 0, 50, 320, 480);
+ ViewInfo child = new ViewInfo("ListView", childNode, 0, 0, 320, 430);
+ root.setChildren(Collections.singletonList(child));
+ ViewInfo grandChild = new ViewInfo("LinearLayout", dataBindingItem, 0, 0, 320, 17);
+ child.setChildren(Collections.singletonList(grandChild));
+ ViewInfo greatGrandChild = new ViewInfo("Button", null, 0, 0, 73, 17);
+ grandChild.setChildren(Collections.singletonList(greatGrandChild));
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, true /*layoutlib5*/).getFirst();
+ assertNotNull(rootView);
+
+ assertEquals("FrameLayout", rootView.getName());
+ assertEquals(1, rootView.getChildren().size());
+ assertSame(rootNode, rootView.getUiViewNode());
+
+ CanvasViewInfo childView = rootView.getChildren().get(0);
+ assertEquals("ListView", childView.getName());
+ assertEquals(0, childView.getChildren().size());
+ assertSame(childNode, childView.getUiViewNode());
+ }
+
+ /**
+ * Dumps out the given {@link ViewInfo} hierarchy to standard out.
+ * Useful during development.
+ *
+ * @param graphicalEditor the editor associated with this hierarchy
+ * @param root the root of the {@link ViewInfo} hierarchy
+ */
+ public static void dump(GraphicalEditorPart graphicalEditor, ViewInfo root) {
+ System.out.println("\n\nRendering:");
+ boolean supportsEmbedding = graphicalEditor.renderingSupports(Capability.EMBEDDED_LAYOUT);
+ System.out.println("Supports Embedded Layout=" + supportsEmbedding);
+ System.out.println("Rendering context=" + graphicalEditor.getIncludedWithin());
+ dump(root, 0);
+ }
+
+ /** Helper for {@link #dump(GraphicalEditorPart, ViewInfo)} */
+ public static void dump(ViewInfo info, int depth) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < depth; i++) {
+ sb.append(" ");
+ }
+ sb.append(info.getClassName());
+ sb.append(" [");
+ sb.append(info.getLeft());
+ sb.append(",");
+ sb.append(info.getTop());
+ sb.append(",");
+ sb.append(info.getRight());
+ sb.append(",");
+ sb.append(info.getBottom());
+ sb.append("] ");
+ Object cookie = info.getCookie();
+ if (cookie instanceof UiViewElementNode) {
+ sb.append(" ");
+ UiViewElementNode node = (UiViewElementNode) cookie;
+ sb.append("<");
+ sb.append(node.getDescriptor().getXmlName());
+ sb.append("> ");
+ } else if (cookie != null) {
+ sb.append(" cookie=" + cookie);
+ }
+
+ System.out.println(sb.toString());
+
+ for (ViewInfo child : info.getChildren()) {
+ dump(child, depth + 1);
+ }
+ }
+
+ /** Helper for {@link #dump(GraphicalEditorPart, ViewInfo)} */
+ public static void dump(CanvasViewInfo info, int depth) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < depth; i++) {
+ sb.append(" ");
+ }
+ sb.append(info.getName());
+ sb.append(" [");
+ sb.append(info.getAbsRect());
+ sb.append("], node=");
+ sb.append(info.getUiViewNode());
+
+ System.out.println(sb.toString());
+
+ for (CanvasViewInfo child : info.getChildren()) {
+ dump(child, depth + 1);
+ }
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ControlPointTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ControlPointTest.java
new file mode 100644
index 000000000..366691e61
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ControlPointTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import org.eclipse.swt.events.MouseEvent;
+
+public class ControlPointTest extends PointTestCases {
+ public void testCreateFromMouseEvent() throws Exception {
+ MouseEvent mouseEvent = canvasMouseEvent(10, 20, 0);
+
+ ControlPoint point = ControlPoint.create(mCanvas, mouseEvent);
+ assertEquals(10, point.x);
+ assertEquals(20, point.y);
+ }
+
+ public void testCreateFromCoordinates() throws Exception {
+ ControlPoint point = ControlPoint.create(mCanvas, 10, 20);
+ assertEquals(10, point.x);
+ assertEquals(20, point.y);
+ }
+
+ public void testConvertToLayout() throws Exception {
+ ControlPoint point = ControlPoint.create(new TestLayoutCanvas(), 10, 20);
+ assertEquals(10, point.x);
+ assertEquals(20, point.y);
+
+ LayoutPoint layoutPoint = point.toLayout();
+ assertNotNull(layoutPoint);
+ assertEquals(40, layoutPoint.x);
+ assertEquals(60, layoutPoint.y);
+
+ // For sanity let's also convert back and verify
+ ControlPoint controlPoint = layoutPoint.toControl();
+ assertNotNull(controlPoint);
+ assertNotSame(controlPoint, point);
+ assertEquals(point, controlPoint);
+ assertEquals(10, controlPoint.x);
+ assertEquals(20, controlPoint.y);
+ }
+
+ public void testEquals() throws Exception {
+ ControlPoint point1 = ControlPoint.create(mCanvas, 1, 1);
+ ControlPoint point2 = ControlPoint.create(mCanvas, 1, 2);
+ ControlPoint point3 = ControlPoint.create(mCanvas, 2, 1);
+ ControlPoint point2b = ControlPoint.create(mCanvas, 1, 2);
+
+ assertFalse(point2.equals(null));
+
+ assertEquals(point2, point2);
+ assertEquals(point2, point2b);
+ assertEquals(point2.hashCode(), point2b.hashCode());
+ assertNotSame(point2, point2b);
+
+ assertFalse(point1.equals(point2));
+ assertFalse(point1.equals(point3));
+ assertFalse(point2.equals(point3));
+ assertFalse(point1.equals(point2));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilitiesTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilitiesTest.java
new file mode 100644
index 000000000..6576bea3a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilitiesTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 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.editors.layout.gle2;
+
+import static com.android.SdkConstants.ANDROID_URI;
+import static com.android.SdkConstants.TOOLS_URI;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.Arrays;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class DomUtilitiesTest extends TestCase {
+
+ public void testIsEquivalent() throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document1 = builder.newDocument();
+ Document document2 = builder.newDocument();
+ document1.appendChild(document1.createElement("root"));
+ document2.appendChild(document2.createElement("root"));
+
+ assertFalse(DomUtilities.isEquivalent(null, null));
+ Element root1 = document1.getDocumentElement();
+ assertFalse(DomUtilities.isEquivalent(null, root1));
+ Element root2 = document2.getDocumentElement();
+ assertFalse(DomUtilities.isEquivalent(root2, null));
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+
+ root1.appendChild(document1.createTextNode(" "));
+ // Differences in text are NOT significant!
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+ root2.appendChild(document2.createTextNode(" "));
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+
+ Element foo1 = document1.createElement("foo");
+ Element foo2 = document2.createElement("foo");
+ root1.appendChild(foo1);
+ assertFalse(DomUtilities.isEquivalent(root1, root2));
+ root2.appendChild(foo2);
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+
+ root1.appendChild(document1.createElement("bar"));
+ assertFalse(DomUtilities.isEquivalent(root1, root2));
+ root2.appendChild(document2.createElement("bar"));
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+
+ // Add attributes in opposite order
+ foo1.setAttribute("attribute1", "value1");
+ foo1.setAttribute("attribute2", "value2");
+ assertFalse(DomUtilities.isEquivalent(root1, root2));
+ foo2.setAttribute("attribute2", "value2");
+ foo2.setAttribute("attribute1", "valueWrong");
+ assertFalse(DomUtilities.isEquivalent(root1, root2));
+ foo2.setAttribute("attribute1", "value1");
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+ foo2.setAttributeNS(TOOLS_URI, "foo", "bar");
+ assertTrue(DomUtilities.isEquivalent(root1, root2));
+ foo2.setAttributeNS(ANDROID_URI, "foo", "bar");
+ assertFalse(DomUtilities.isEquivalent(root1, root2));
+
+ // TODO - test different tag names
+ // TODO - test different name spaces!
+ }
+
+ public void testIsContiguous() throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+ document.appendChild(document.createElement("root"));
+ Element root = document.getDocumentElement();
+ root.appendChild(document.createTextNode(" "));
+ Element foo = document.createElement("foo");
+ root.appendChild(foo);
+ root.appendChild(document.createTextNode(" "));
+ Element bar = document.createElement("bar");
+ root.appendChild(bar);
+ Element baz = document.createElement("baz");
+ root.appendChild(baz);
+
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(foo)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(foo, bar)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(foo, bar, baz)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(foo, bar, baz)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(bar, baz, foo)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(baz, bar, foo)));
+ assertTrue(DomUtilities.isContiguous(Arrays.asList(baz, foo, bar)));
+
+ assertFalse(DomUtilities.isContiguous(Arrays.asList(foo, baz)));
+ assertFalse(DomUtilities.isContiguous(Arrays.asList(root, baz)));
+ }
+
+ public void testGetCommonAncestor() throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+
+ // A
+ // / \
+ // B C
+ // / \
+ // D E
+
+ document.appendChild(document.createElement("A"));
+ Element a = document.getDocumentElement();
+ assertSame(a, DomUtilities.getCommonAncestor(a, a));
+
+ Element b = document.createElement("B");
+ a.appendChild(b);
+ Element c = document.createElement("C");
+ a.appendChild(c);
+ Element d = document.createElement("D");
+ c.appendChild(d);
+ Element e = document.createElement("E");
+ c.appendChild(e);
+
+ assertSame(a, DomUtilities.getCommonAncestor(a, b));
+ assertSame(a, DomUtilities.getCommonAncestor(b, a));
+ assertSame(a, DomUtilities.getCommonAncestor(b, c));
+ assertSame(a, DomUtilities.getCommonAncestor(b, d));
+ assertSame(a, DomUtilities.getCommonAncestor(b, e));
+ assertSame(a, DomUtilities.getCommonAncestor(a, e));
+
+ assertSame(c, DomUtilities.getCommonAncestor(d, e));
+ assertSame(c, DomUtilities.getCommonAncestor(c, e));
+ assertSame(c, DomUtilities.getCommonAncestor(d, c));
+ assertSame(c, DomUtilities.getCommonAncestor(c, c));
+ }
+
+ public void testGetDepth() throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+
+ // A
+ // / \
+ // B C
+ // / \
+ // D E
+
+ document.appendChild(document.createElement("A"));
+ Element a = document.getDocumentElement();
+ assertSame(a, DomUtilities.getCommonAncestor(a, a));
+ Element b = document.createElement("B");
+ a.appendChild(b);
+ Element c = document.createElement("C");
+ a.appendChild(c);
+ Element d = document.createElement("D");
+ c.appendChild(d);
+ Element e = document.createElement("E");
+ c.appendChild(e);
+
+ assertEquals(0, DomUtilities.getDepth(document));
+
+ assertEquals(1, DomUtilities.getDepth(a));
+ assertEquals(2, DomUtilities.getDepth(b));
+ assertEquals(2, DomUtilities.getDepth(c));
+ assertEquals(3, DomUtilities.getDepth(d));
+ assertEquals(3, DomUtilities.getDepth(e));
+ }
+
+ public void testHasChildren() throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setValidating(false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+ assertFalse(DomUtilities.hasElementChildren(document));
+ document.appendChild(document.createElement("A"));
+ Element a = document.getDocumentElement();
+ assertFalse(DomUtilities.hasElementChildren(a));
+ a.appendChild(document.createTextNode("foo"));
+ assertFalse(DomUtilities.hasElementChildren(a));
+ Element b = document.createElement("B");
+ a.appendChild(b);
+ assertTrue(DomUtilities.hasElementChildren(a));
+ assertFalse(DomUtilities.hasElementChildren(b));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
new file mode 100644
index 000000000..d1c56c233
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageUtilsTest.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import com.android.ide.common.api.Rect;
+
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class ImageUtilsTest extends TestCase {
+ public void testCropBlank() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNull(crop);
+ }
+
+ public void testCropBlankPre() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(5, 5, 80, 80));
+ assertNull(crop);
+ }
+
+ public void testCropNonblank() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, false));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNotNull(crop);
+ assertEquals(image.getWidth(), crop.getWidth());
+ assertEquals(image.getHeight(), crop.getHeight());
+ }
+
+ public void testCropSomething() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, null);
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropSomethingPre() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(0, 0, 100, 100));
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropSomethingPre2() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropBlank(image, new Rect(5, 5, 80, 80));
+ assertNotNull(crop);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFF00FF00, crop.getRGB(0, 0));
+ assertEquals(0xFF00FF00, crop.getRGB(49, 49));
+ }
+
+ public void testCropColor() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFF00FF00, null);
+ assertNull(crop);
+ }
+
+ public void testCropNonColor() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFFFF0000, null);
+ assertNotNull(crop);
+ assertEquals(image.getWidth(), crop.getWidth());
+ assertEquals(image.getHeight(), crop.getHeight());
+ }
+
+ public void testCropColorSomething() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFFFF0000, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFF00FF00, null);
+ assertEquals(50, crop.getWidth());
+ assertEquals(50, crop.getHeight());
+ assertEquals(0xFFFF0000, crop.getRGB(0, 0));
+ assertEquals(0xFFFF0000, crop.getRGB(49, 49));
+ }
+
+ public void testNothingTodo() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ BufferedImage crop = ImageUtils.cropColor(image, 0xFFFF0000, new Rect(40, 40, 0, 0));
+ assertNull(crop);
+ }
+
+ public void testContainsDarkPixels() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.dispose();
+
+ assertFalse(ImageUtils.containsDarkPixels(image));
+
+ image.setRGB(50, 50, 0xFFFFFFFF);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFFAAAAAA);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFF00FF00);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFFFF8800);
+ assertFalse(ImageUtils.containsDarkPixels(image));
+ image.setRGB(50, 50, 0xFF333333);
+ assertTrue(ImageUtils.containsDarkPixels(image));
+
+ }
+
+ public void testGetBoundingRectangle() {
+ assertEquals(null, ImageUtils.getBoundingRectangle(Collections.<Rectangle> emptyList()));
+
+ assertEquals(new Rectangle(1, 2, 3, 4), ImageUtils.getBoundingRectangle(Arrays
+ .asList(new Rectangle(1, 2, 3, 4))));
+ assertEquals(new Rectangle(1, 2, 3, 4), ImageUtils.getBoundingRectangle(Arrays
+ .asList(new Rectangle(1, 2, 3, 4), new Rectangle(1, 2, 1, 1))));
+ assertEquals(new Rectangle(5, 5, 25, 25), ImageUtils.getBoundingRectangle(Arrays.asList(
+ new Rectangle(10, 10, 20, 20), new Rectangle(5, 5, 1, 1))));
+ }
+
+ /**
+ * Paints a set of {@link Rectangle} object out of a rendered {@link BufferedImage}
+ * such that the resulting image is transparent except for a minimum bounding
+ * rectangle of the selected elements.
+ *
+ * @param image the source image
+ * @param rectangles the set of rectangles to copy
+ * @param boundingBox the bounding rectangle of the set of rectangles to copy, can be
+ * computed by {@link ImageUtils#getBoundingRectangle}
+ * @param scale a scale factor to apply to the result, e.g. 0.5 to shrink the
+ * destination down 50%, 1.0 to leave it alone and 2.0 to zoom in by
+ * doubling the image size
+ * @return a rendered image, or null
+ */
+ public static BufferedImage drawRectangles(BufferedImage image,
+ List<Rectangle> rectangles, Rectangle boundingBox, double scale) {
+
+ // This code is not a test. When I implemented image cropping, I first implemented
+ // it for BufferedImages (since it's easier; easy image painting, easy scaling,
+ // easy transparency handling, etc). However, this meant that we would need to
+ // convert the SWT images from the ImageOverlay to BufferedImages, crop and convert
+ // back; not ideal, so I rewrote it in SWT (see SwtUtils). However, I
+ // don't want to throw away the code in case we start keeping BufferedImages rather
+ // than SWT images or need it for other purposes, but rather than place it in the
+ // production codebase I'm leaving this utility here in the associated ImageUtils
+ // test class. It was used like this:
+ // @formatter:off
+ //
+ // BufferedImage wholeImage = SwtUtils.convertToAwt(image);
+ // BufferedImage result = ImageUtils.cropSelection(wholeImage,
+ // rectangles, boundingBox, scale);
+ // e.image = SwtUtils.convertToSwt(image.getDevice(), result, true,
+ // DRAG_TRANSPARENCY);
+ //
+ // @formatter:on
+
+ if (boundingBox == null) {
+ return null;
+ }
+
+ int destWidth = (int) (scale * boundingBox.width);
+ int destHeight = (int) (scale * boundingBox.height);
+ BufferedImage dest = new BufferedImage(destWidth, destHeight, image.getType());
+
+ Graphics2D g = dest.createGraphics();
+
+ for (Rectangle bounds : rectangles) {
+ int dx1 = bounds.x - boundingBox.x;
+ int dy1 = bounds.y - boundingBox.y;
+ int dx2 = dx1 + bounds.width;
+ int dy2 = dy1 + bounds.height;
+
+ dx1 *= scale;
+ dy1 *= scale;
+ dx2 *= scale;
+ dy2 *= scale;
+
+ int sx1 = bounds.x;
+ int sy1 = bounds.y;
+ int sx2 = sx1 + bounds.width;
+ int sy2 = sy1 + bounds.height;
+
+ g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
+ }
+
+ g.dispose();
+
+ return dest;
+ }
+
+ public void testSubImage() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFFFF0000, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage sub = ImageUtils.subImage(image, 25, 25, 35, 45);
+ assertEquals(10, sub.getWidth());
+ assertEquals(20, sub.getHeight());
+ assertEquals(0xFFFF0000, sub.getRGB(0, 0));
+ assertEquals(0xFFFF0000, sub.getRGB(9, 9));
+
+ sub = ImageUtils.subImage(image, 23, 23, 23 + 5, 23 + 5);
+ assertEquals(5, sub.getWidth());
+ assertEquals(5, sub.getHeight());
+ assertEquals(0xFF00FF00, sub.getRGB(0, 0));
+ assertEquals(0xFFFF0000, sub.getRGB(4, 4));
+ }
+
+ public void testGetColor() throws Exception {
+ assertEquals(0xFF000000, ImageUtils.getColor("#000"));
+ assertEquals(0xFF000000, ImageUtils.getColor("#000000"));
+ assertEquals(0xABCDEF91, ImageUtils.getColor("#ABCDEF91"));
+ }
+
+ public void testGetBrightness() throws Exception {
+ assertEquals(96, ImageUtils.getBrightness(0x456789));
+ assertEquals(198, ImageUtils.getBrightness(0xABCDEF));
+
+ assertEquals(0, ImageUtils.getBrightness(0x0));
+ assertEquals(255, ImageUtils.getBrightness(0xFFFFFF));
+ assertEquals(299*255/1000, ImageUtils.getBrightness(0xFF0000));
+ assertEquals(587*255/1000, ImageUtils.getBrightness(0x00FF00));
+ assertEquals(114*255/1000, ImageUtils.getBrightness(0x0000FF));
+ }
+
+ public void testColorConversion() throws Exception {
+ assertEquals(0, ImageUtils.rgbToInt(ImageUtils.intToRgb(0), 0));
+ assertEquals(0xFFFFFFFF, ImageUtils.rgbToInt(ImageUtils.intToRgb(0xFFFFFF), 0xFF));
+ assertEquals(0x12345678, ImageUtils.rgbToInt(ImageUtils.intToRgb(0x345678), 0x12));
+ }
+
+ public void testScaleImage() throws Exception {
+ BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
+ Graphics g = image.getGraphics();
+ g.setColor(new Color(0xFF00FF00, true));
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ g.setColor(new Color(0xFFFF0000, true));
+ g.fillRect(25, 25, 50, 50);
+ g.dispose();
+
+ BufferedImage scaled = ImageUtils.scale(image, 0.5, 0.5);
+ assertEquals(50, scaled.getWidth());
+ assertEquals(50, scaled.getHeight());
+ assertEquals(0xFF00FF00, scaled.getRGB(0, 0));
+ assertEquals(0xFF00FF00, scaled.getRGB(49, 49));
+ assertEquals(0xFFFF0000, scaled.getRGB(25, 25));
+
+ scaled = ImageUtils.scale(image, 2.0, 2.0);
+ assertEquals(200, scaled.getWidth());
+ assertEquals(200, scaled.getHeight());
+ assertEquals(0xFF00FF00, scaled.getRGB(0, 0));
+ assertEquals(0xFF00FF00, scaled.getRGB(48, 48));
+ assertEquals(0xFFFF0000, scaled.getRGB(100, 100));
+ assertEquals(0xFF00FF00, scaled.getRGB(199, 199));
+
+ scaled = ImageUtils.scale(image, 0.25, 0.25);
+ assertEquals(25, scaled.getWidth());
+ assertEquals(25, scaled.getHeight());
+ assertEquals(0xFF00FF00, scaled.getRGB(0, 0));
+ assertEquals(0xFF00FF00, scaled.getRGB(24, 24));
+ assertEquals(0xFFFF0000, scaled.getRGB(13, 13));
+
+ scaled = ImageUtils.scale(image, 0.25, 0.25, 75, 95);
+ assertEquals(100, scaled.getWidth());
+ assertEquals(120, scaled.getHeight());
+ assertEquals(0xFF00FF00, scaled.getRGB(0, 0));
+ assertEquals(0xFF00FF00, scaled.getRGB(24, 24));
+ assertEquals(0xFFFF0000, scaled.getRGB(13, 13));
+
+ }
+
+ public void testCreateColoredImage() throws Exception {
+ BufferedImage image = ImageUtils.createColoredImage(120, 110, new RGB(0xFE, 0xFD, 0xFC));
+ assertEquals(120, image.getWidth());
+ assertEquals(110, image.getHeight());
+ assertEquals(0xFFFEFDFC, image.getRGB(0, 0));
+ assertEquals(0xFFFEFDFC, image.getRGB(50, 50));
+ assertEquals(0xFFFEFDFC, image.getRGB(119, 109));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinderTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinderTest.java
new file mode 100644
index 000000000..c86623cd6
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeFinderTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class IncludeFinderTest extends TestCase {
+ public void testEncodeDecode1() throws Exception {
+ // Test ending with just a key
+ String s = "bar,baz,foo";
+ assertEquals(s, IncludeFinder.encodeMap(IncludeFinder.decodeMap(s)));
+ }
+
+ public void testDecode1() throws Exception {
+ // Test ending with just a key
+ String s = "foo";
+ assertTrue(IncludeFinder.decodeMap(s).containsKey("foo"));
+ assertEquals(0, IncludeFinder.decodeMap(s).get("foo").size());
+ }
+
+ public void testDecode2() throws Exception {
+ // Test ending with just a key
+ String s = "foo=>{bar,baz}";
+ assertTrue(IncludeFinder.decodeMap(s).containsKey("foo"));
+ assertEquals("[bar, baz]",
+ IncludeFinder.decodeMap(s).get("foo").toString());
+ }
+
+ public void testNoBlanks() throws Exception {
+ // Make sure we skip the },
+ String s = "foo=>{bar,baz},bar";
+ assertNull(IncludeFinder.decodeMap(s).get(""));
+ }
+
+ public void testEncodeDecode2() throws Exception {
+ // Test ending with just a key
+ String s = "bar,key1=>{value1,value2},key2=>{value3,value4}";
+ assertEquals(s, IncludeFinder.encodeMap(IncludeFinder.decodeMap(s)));
+ }
+
+ public void testUpdates() throws Exception {
+ IncludeFinder finder = IncludeFinder.create();
+ assertEquals(null, finder.getIncludedBy("foo"));
+
+ finder.setIncluded("bar", Arrays.<String>asList("foo", "baz"), false);
+ finder.setIncluded("baz", Arrays.<String>asList("foo"), false);
+ assertEquals(Arrays.asList("bar", "baz"), finder.getIncludedBy("foo"));
+ finder.setIncluded("bar", Collections.<String>emptyList(), false);
+ assertEquals(Arrays.asList("baz"), finder.getIncludedBy("foo"));
+ finder.setIncluded("baz", Collections.<String>emptyList(), false);
+ assertEquals(Collections.emptyList(), finder.getIncludedBy("foo"));
+ }
+
+ public void testFindIncludes() throws Exception {
+ String xml =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " android:layout_width=\"match_parent\"\n" +
+ " android:layout_height=\"match_parent\"\n" +
+ " android:orientation=\"vertical\" >\n" +
+ "\n" +
+ " <RadioButton\n" +
+ " android:id=\"@+id/radioButton1\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:text=\"RadioButton\" />\n" +
+ "\n" +
+ " <include\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " layout=\"@layout/layout3\" />\n" +
+ "\n" +
+ " <include\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " layout=\"@layout/layout4\" />\n" +
+ "\n" +
+ "</LinearLayout>";
+ List<String> includes = IncludeFinder.findIncludes(xml);
+ Collections.sort(includes);
+ assertEquals(Arrays.asList("layout3", "layout4"), includes);
+ }
+
+ public void testFindFragments() throws Exception {
+ String xml =
+ "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " xmlns:tools=\"http://schemas.android.com/tools\"\n" +
+ " android:layout_width=\"match_parent\"\n" +
+ " android:layout_height=\"match_parent\"\n" +
+ " tools:context=\".MainActivity\" >\n" +
+ "\n" +
+ " <fragment\n" +
+ " android:id=\"@+id/fragment1\"\n" +
+ " android:name=\"android.app.ListFragment\"\n" +
+ " android:layout_width=\"wrap_content\"\n" +
+ " android:layout_height=\"wrap_content\"\n" +
+ " android:layout_alignParentLeft=\"true\"\n" +
+ " android:layout_alignParentTop=\"true\"\n" +
+ " android:layout_marginLeft=\"58dp\"\n" +
+ " android:layout_marginTop=\"74dp\"\n" +
+ " tools:layout=\"@layout/myfragment\" />\n" +
+ "\n" +
+ "</RelativeLayout>";
+ List<String> includes = IncludeFinder.findIncludes(xml);
+ Collections.sort(includes);
+ assertEquals(Arrays.asList("myfragment"), includes);
+ }
+
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeOverlayTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeOverlayTest.java
new file mode 100644
index 000000000..a96b1a387
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/IncludeOverlayTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import org.eclipse.swt.graphics.Rectangle;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class IncludeOverlayTest extends TestCase {
+
+ public void testSubtractRectangles() throws Exception {
+ checkSubtract(new Rectangle(0, 0, 100, 80), Collections.<Rectangle> emptyList());
+
+ checkSubtract(new Rectangle(0, 0, 100, 80), Arrays.asList(new Rectangle(50, 50, 20, 20)));
+
+ checkSubtract(new Rectangle(0, 0, 100, 80), Arrays.asList(new Rectangle(50, 50, 20, 20),
+ new Rectangle(90, 90, 10, 10)));
+
+ checkSubtract(new Rectangle(0, 0, 100, 80), Arrays.asList(new Rectangle(50, 50, 20, 20),
+ new Rectangle(90, 90, 10, 10), new Rectangle(0, 0, 10, 10)));
+
+ }
+
+ private void checkSubtract(Rectangle rectangle, List<Rectangle> holes) {
+ Collection<Rectangle> result = IncludeOverlay.subtractRectangles(rectangle, holes);
+
+ // Do some Monte Carlo testing - pick random coordinates and check that if they
+ // are within one of the holes then they are not in the result list and vice versa
+ Random random = new Random(42L);
+ for (int i = 0; i < 1000; i++) {
+ int x = random.nextInt(rectangle.width);
+ int y = random.nextInt(rectangle.height);
+
+ boolean inHole = false;
+ for (Rectangle hole : holes) {
+ if (hole.contains(x, y)) {
+ inHole = true;
+ }
+ }
+
+ boolean inResult = false;
+ for (Rectangle r : result) {
+ if (r.contains(x, y)) {
+ inResult = true;
+ break;
+ }
+ }
+
+ if (inHole == inResult) {
+ fail("Wrong result at (" + x + "," + y + ") for rectangle=" + rectangle
+ + " and holes=" + holes + " where inHole=inResult="
+ + inResult);
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutPointTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutPointTest.java
new file mode 100644
index 000000000..c053de854
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutPointTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+public class LayoutPointTest extends PointTestCases {
+ public void testCreateFromCoordinates() throws Exception {
+ LayoutPoint point = LayoutPoint.create(mCanvas, 10, 20);
+ assertEquals(10, point.x);
+ assertEquals(20, point.y);
+ }
+
+ public void testEquals() throws Exception {
+ LayoutPoint point1 = LayoutPoint.create(mCanvas, 1, 1);
+ LayoutPoint point2 = LayoutPoint.create(mCanvas, 1, 2);
+ LayoutPoint point3 = LayoutPoint.create(mCanvas, 2, 1);
+ LayoutPoint point2b = LayoutPoint.create(mCanvas, 1, 2);
+
+ assertFalse(point2.equals(null));
+
+ assertEquals(point2, point2);
+ assertEquals(point2, point2b);
+ assertEquals(point2.hashCode(), point2b.hashCode());
+ assertNotSame(point2, point2b);
+
+ assertFalse(point1.equals(point2));
+ assertFalse(point1.equals(point3));
+ assertFalse(point2.equals(point3));
+ assertFalse(point1.equals(point2));
+ }
+
+ public void testConvertToControl() throws Exception {
+ LayoutPoint point = LayoutPoint.create(new TestLayoutCanvas(), 10, 20);
+ assertEquals(10, point.x);
+ assertEquals(20, point.y);
+
+ ControlPoint controlPoint = point.toControl();
+ assertNotNull(controlPoint);
+ assertEquals(-5, controlPoint.x);
+ assertEquals(0, controlPoint.y);
+
+ // For sanity let's also convert back and verify
+ LayoutPoint layoutPoint = controlPoint.toLayout();
+ assertNotNull(layoutPoint);
+ assertNotSame(layoutPoint, point);
+ assertEquals(point, layoutPoint);
+ assertEquals(10, layoutPoint.x);
+ assertEquals(20, layoutPoint.y);
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PointTestCases.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PointTestCases.java
new file mode 100644
index 000000000..91d0e133f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PointTestCases.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Shell;
+
+import junit.framework.TestCase;
+
+/**
+ * Common utilities for the point tests {@link LayoutPointTest} and
+ * {@link ControlPointTest}
+ */
+public class PointTestCases extends TestCase {
+ LayoutCanvas mCanvas = new TestLayoutCanvas();
+
+ protected MouseEvent canvasMouseEvent(int x, int y, int stateMask) {
+ Event event = new Event();
+ event.x = x;
+ event.y = y;
+ event.stateMask = stateMask;
+ event.widget = mCanvas;
+ MouseEvent mouseEvent = new MouseEvent(event);
+ return mouseEvent;
+ }
+
+ /** Mock implementation of LayoutCanvas */
+ protected static class TestLayoutCanvas extends LayoutCanvas {
+ float mScaleX;
+
+ float mScaleY;
+
+ float mTranslateX;
+
+ float mTranslateY;
+
+ public TestLayoutCanvas(float scaleX, float scaleY, float translateX, float translateY) {
+ super(null, null, new Shell(), 0);
+
+ this.mScaleX = scaleX;
+ this.mScaleY = scaleY;
+ this.mTranslateX = translateX;
+ this.mTranslateY = translateY;
+ }
+
+ public TestLayoutCanvas() {
+ this(2.0f, 2.0f, 20.0f, 20.0f);
+ }
+
+ @Override
+ CanvasTransform getHorizontalTransform() {
+ ScrollBar scrollBar = new List(this, SWT.V_SCROLL|SWT.H_SCROLL).getHorizontalBar();
+ return new TestCanvasTransform(scrollBar, mScaleX, mTranslateX);
+ }
+
+ @Override
+ CanvasTransform getVerticalTransform() {
+ ScrollBar scrollBar = new List(this, SWT.V_SCROLL|SWT.H_SCROLL).getVerticalBar();
+ return new TestCanvasTransform(scrollBar, mScaleY, mTranslateY);
+ }
+ }
+
+ static class TestCanvasTransform extends CanvasTransform {
+ float mScale;
+
+ float mTranslate;
+
+ public TestCanvasTransform(ScrollBar scrollBar, float scale, float translate) {
+ super(null, scrollBar);
+ this.mScale = scale;
+ this.mTranslate = translate;
+ }
+
+ @Override
+ public int translate(int value) {
+ return (int) ((value - mTranslate) / mScale);
+ }
+
+ @Override
+ public int inverseTranslate(int value) {
+ return (int) (value * mScale + mTranslate);
+ }
+ }
+
+ public void testDummy() {
+ // To avoid JUnit warning that this class contains no tests, even though
+ // this is an abstract class and JUnit shouldn't try
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLoggerTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLoggerTest.java
new file mode 100644
index 000000000..c28d9a966
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLoggerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import junit.framework.TestCase;
+
+public class RenderLoggerTest extends TestCase {
+ public void testLogger1() throws Exception {
+ RenderLogger l = new RenderLogger("foo", null);
+ assertFalse(l.hasProblems());
+ }
+
+ public void testLogger2() throws Exception {
+ RenderLogger l = new RenderLogger("foo", null);
+ assertFalse(l.hasProblems());
+ l.fidelityWarning(null, "No perspective Transforms", null, null);
+ l.fidelityWarning(null, "No GPS", null, null);
+ assertTrue(l.hasProblems());
+ assertEquals("The graphics preview in the layout editor may not be accurate:\n"
+ + "* No perspective Transforms\n" + "* No GPS\n", l.getProblems(true));
+ assertFalse(l.seenTag("foo"));
+ assertFalse(l.seenTag(null));
+ }
+
+ public void testLogger3() throws Exception {
+ RenderLogger l = new RenderLogger("foo", null);
+ assertFalse(l.hasProblems());
+ l.error("timeout", "Sample Error", new RuntimeException(), null);
+ l.warning("slow", "Sample warning", null);
+ assertTrue(l.hasProblems());
+ assertEquals("Sample Error\n" + "Sample warning\n"
+ + "Exception details are logged in Window > Show View > Error Log",
+ l.getProblems(true));
+ assertFalse(l.seenTag("foo"));
+ assertTrue(l.seenTag("timeout"));
+ assertTrue(l.seenTag("slow"));
+ assertFalse(l.seenTagPrefix("foo"));
+ assertTrue(l.seenTagPrefix("timeout"));
+ assertTrue(l.seenTagPrefix("slow"));
+ assertTrue(l.seenTagPrefix("time"));
+ assertFalse(l.seenTagPrefix("timeouts"));
+ }
+
+ public void testLoggerSuppressWarnings() throws Exception {
+ RenderLogger l = new RenderLogger("foo", null);
+ assertFalse(l.hasProblems());
+ RenderLogger.ignoreFidelityWarning("No perspective Transforms");
+ l.fidelityWarning(null, "No perspective Transforms", null, null);
+ l.fidelityWarning(null, "No GPS", null, null);
+ assertTrue(l.hasProblems());
+ assertEquals("The graphics preview in the layout editor may not be accurate:\n"
+ + "* No GPS\n", l.getProblems(true));
+ assertEquals("", l.getProblems(false));
+ assertFalse(l.seenTag("foo"));
+ assertFalse(l.seenTag(null));
+
+ l = new RenderLogger("foo", null);
+ assertFalse(l.hasProblems());
+ RenderLogger.ignoreFidelityWarning("No perspective Transforms");
+ RenderLogger.ignoreFidelityWarning("No GPS");
+ l.fidelityWarning(null, "No perspective Transforms", null, null);
+ l.fidelityWarning(null, "No GPS", null, null);
+ assertFalse(l.hasProblems());
+ assertEquals("", l.getProblems(true));
+ assertFalse(l.seenTag("foo"));
+ assertFalse(l.seenTag(null));
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManagerTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManagerTest.java
new file mode 100644
index 000000000..b29f9f3c5
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManagerTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 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.editors.layout.gle2;
+
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+
+import org.eclipse.swt.widgets.Shell;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class SelectionManagerTest extends TestCase {
+ private SelectionManager createManager() {
+ LayoutCanvas canvas = new LayoutCanvas(null, null, new Shell(), 0);
+ return new SelectionManager(canvas);
+ }
+
+ public void testEmpty() {
+ SelectionManager manager = createManager();
+
+ assertNotNull(manager.getSelections());
+ assertEquals(0, manager.getSelections().size());
+ assertFalse(manager.hasMultiSelection());
+ assertTrue(manager.isEmpty());
+ }
+
+ public void testBasic() {
+ SelectionManager manager = createManager();
+ assertTrue(manager.isEmpty());
+
+ UiViewElementNode rootNode = CanvasViewInfoTest.createNode("android.widget.LinearLayout",
+ true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = CanvasViewInfoTest.createNode(rootNode,
+ "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("Button1", child1Node, 0, 0, 50, 20);
+ UiViewElementNode child2Node = CanvasViewInfoTest.createNode(rootNode,
+ "android.widget.Button", false);
+ ViewInfo child2 = new ViewInfo("Button2", child2Node, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, true /* layoutlib5 */).getFirst();
+ assertNotNull(rootView);
+
+ manager.selectMultiple(Arrays.asList(rootView, rootView.getChildren().get(0), rootView
+ .getChildren().get(1)));
+ assertEquals(3, manager.getSelections().size());
+ assertFalse(manager.isEmpty());
+ assertTrue(manager.hasMultiSelection());
+
+ // Expect read-only result; ensure that's the case
+ try {
+ manager.getSelections().remove(0);
+ fail("Result should be read only collection");
+ } catch (Exception e) {
+ ; //ok, what we expected
+ }
+
+ manager.selectNone();
+ assertEquals(0, manager.getSelections().size());
+ assertTrue(manager.isEmpty());
+
+ manager.selectSingle(rootView);
+ assertEquals(1, manager.getSelections().size());
+ assertFalse(manager.isEmpty());
+ assertSame(rootView, manager.getSelections().get(0).getViewInfo());
+
+ manager.selectMultiple(Arrays.asList(rootView, rootView.getChildren().get(0), rootView
+ .getChildren().get(1)));
+ assertEquals(3, manager.getSelections().size());
+
+ manager.deselect(rootView.getChildren().get(0));
+ assertEquals(2, manager.getSelections().size());
+ manager.deselect(rootView);
+ assertEquals(1, manager.getSelections().size());
+ assertSame(rootView.getChildren().get(1), manager.getSelections().get(0).getViewInfo());
+ }
+
+ public void testSelectParent() {
+ SelectionManager manager = createManager();
+ assertTrue(manager.isEmpty());
+
+ UiViewElementNode rootNode = CanvasViewInfoTest.createNode("android.widget.LinearLayout",
+ true);
+ ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100);
+ UiViewElementNode child1Node = CanvasViewInfoTest.createNode(rootNode,
+ "android.widget.Button", false);
+ ViewInfo child1 = new ViewInfo("Button1", child1Node, 0, 0, 50, 20);
+ UiViewElementNode child2Node = CanvasViewInfoTest.createNode(rootNode,
+ "android.widget.Button", false);
+ ViewInfo child2 = new ViewInfo("Button2", child2Node, 0, 20, 70, 25);
+ root.setChildren(Arrays.asList(child1, child2));
+ CanvasViewInfo rootView = CanvasViewInfo.create(root, true /* layoutlib5 */).getFirst();
+ assertNotNull(rootView);
+
+ manager.selectMultiple(Arrays.asList(rootView.getChildren().get(0)));
+ assertEquals(1, manager.getSelections().size());
+ assertFalse(manager.isEmpty());
+ assertSame(rootView.getChildren().get(0), manager.getSelections().get(0).getViewInfo());
+
+ manager.selectParent();
+ assertEquals(1, manager.getSelections().size());
+ assertFalse(manager.isEmpty());
+ assertSame(rootView, manager.getSelections().get(0).getViewInfo());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttributeTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttributeTest.java
new file mode 100755
index 000000000..f4f8eb81a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttributeTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import com.android.SdkConstants;
+
+import junit.framework.TestCase;
+
+public class SimpleAttributeTest extends TestCase {
+
+ private SimpleAttribute a;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ a = new SimpleAttribute(SdkConstants.NS_RESOURCES, "name", "value = with space ");
+ }
+
+ public final void testSimpleAttribute() {
+ assertEquals(SdkConstants.NS_RESOURCES, a.getUri());
+ assertEquals("name", a.getName());
+ assertEquals("value = with space ", a.getValue());
+ }
+
+ public final void testGetUri() {
+ assertEquals(SdkConstants.NS_RESOURCES, a.getUri());
+ }
+
+ public final void testGetName() {
+ assertEquals("name", a.getName());
+ }
+
+ public final void testGetValue() {
+ assertEquals("value = with space ", a.getValue());
+ }
+
+ public final void testToString() {
+ assertEquals(
+ "@name:" + SdkConstants.NS_RESOURCES + "=value = with space \n",
+ a.toString());
+ }
+
+ public final void testParseString() {
+ String s = "@name:" + SdkConstants.NS_RESOURCES + "=value = with space \n";
+ SimpleAttribute b = SimpleAttribute.parseString(s);
+ assertEquals(a, b);
+ }
+
+ public final void testEqualsObject() {
+ assertFalse(a.equals(null));
+ assertFalse(a.equals(new Object()));
+
+ // wrong name
+ assertFalse(a.equals(new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "wrong name",
+ "value = with space ")));
+ // wrong value
+ assertFalse(a.equals(new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "name",
+ "value")));
+ // wrong uri
+ assertFalse(a.equals(new SimpleAttribute("uri", "name", "value = with space ")));
+ // all fields wrong
+ assertFalse(a.equals(new SimpleAttribute("uri", "wrong name", "value")));
+
+ assertTrue(a.equals(new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "name",
+ "value = with space ")));
+ }
+
+ public final void testHashCode() {
+
+ int ah = a.hashCode();
+
+ assertFalse(ah == new Object().hashCode());
+
+ // wrong name
+ assertFalse(ah == new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "wrong name",
+ "value = with space ").hashCode());
+ // wrong value
+ assertFalse(ah == new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "name",
+ "value").hashCode());
+ // wrong uri
+ assertFalse(ah == new SimpleAttribute("uri", "name", "value = with space ").hashCode());
+ // all fields wrong
+ assertFalse(ah == new SimpleAttribute("uri", "wrong name", "value").hashCode());
+
+ assertEquals(ah, new SimpleAttribute(SdkConstants.NS_RESOURCES,
+ "name",
+ "value = with space ").hashCode());
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElementTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElementTest.java
new file mode 100755
index 000000000..091aa378c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElementTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import com.android.ide.common.api.Rect;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class SimpleElementTest extends TestCase {
+
+ private SimpleElement e;
+
+ /**
+ * Helper method to compare arrays' *content* is equal (instead of object identity).
+ * Also produces a suitable output to understand mismatch, if any.
+ * <p/>
+ * Pre-requisite: The arrays' elements must properly implement {@link Object#equals(Object)}
+ * and a sensible {@link Object#toString()}.
+ */
+ private static void assertArrayEquals(Object[] expected, Object[] actual) {
+ if (!Arrays.equals(expected, actual)) {
+ // In case of failure, transform the arguments into strings and let
+ // assertEquals(string) handle it as it can produce a nice diff of the string.
+ String strExpected = expected == null ? "(null)" : Arrays.toString(expected);
+ String strActual = actual == null ? "(null)" : Arrays.toString(actual);
+
+ if (strExpected.equals(strActual)) {
+ fail(String.format("Array not equal:\n Expected[%d]=%s\n Actual[%d]=%s",
+ expected == null ? 0 : expected.length,
+ strExpected,
+ actual == null ? 0 : actual.length,
+ strActual));
+ } else {
+ assertEquals(strExpected, strActual);
+ }
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ e = new SimpleElement("android.view.LinearLayout", // fqcn
+ "android.view.FrameLayout", // parentFqcn
+ new Rect(10, 5, 60, 40), // bounds
+ new Rect(0, 0, 320, 480)); // parentBounds
+ }
+
+ public final void testGetFqcn() {
+ assertEquals("android.view.LinearLayout", e.getFqcn());
+ }
+
+ public final void testGetParentFqcn() {
+ assertEquals("android.view.FrameLayout", e.getParentFqcn());
+ }
+
+ public final void testGetBounds() {
+ assertEquals(new Rect(10, 5, 60, 40), e.getBounds());
+ }
+
+ public final void testGetParentBounds() {
+ assertEquals(new Rect(0, 0, 320, 480), e.getParentBounds());
+ }
+
+ public final void testToString() {
+ assertEquals("{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "}\n",
+ e.toString());
+
+ e.addAttribute(new SimpleAttribute("uri", "name", "value"));
+ e.addAttribute(new SimpleAttribute("my-uri", "second-name", "my = value "));
+
+ assertEquals("{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "@name:uri=value\n" +
+ "@second-name:my-uri=my = value \n" +
+ "}\n",
+ e.toString());
+
+ SimpleElement e2 = new SimpleElement("android.view.Button",
+ "android.view.LinearLayout",
+ new Rect(10, 20, 30, 40),
+ new Rect(0, 0, 320, 480));
+ e2.addAttribute(new SimpleAttribute("uri1", "name1", "value1"));
+ SimpleElement e3 = new SimpleElement("android.view.CheckBox",
+ "android.view.LinearLayout",
+ new Rect(-1, -2, -3, -4), // invalid rect is ignored
+ new Rect(-1, -2, -3, -4)); // invalid rectis ignored
+ e3.addAttribute(new SimpleAttribute("uri2", "name2", "value2"));
+ e3.addAttribute(new SimpleAttribute("uri3", "name3", "value3"));
+ e.addInnerElement(e2);
+ e.addInnerElement(e3);
+
+ assertEquals("{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "@name:uri=value\n" +
+ "@second-name:my-uri=my = value \n" +
+ "{V=3,N=android.view.Button,P=android.view.LinearLayout,R=10 20 30 40,Q=0 0 320 480\n" +
+ "@name1:uri1=value1\n" +
+ "}\n" +
+ "{V=3,N=android.view.CheckBox,P=android.view.LinearLayout\n" +
+ "@name2:uri2=value2\n" +
+ "@name3:uri3=value3\n" +
+ "}\n" +
+ "}\n",
+ e.toString());
+ }
+
+ public final void testParseString() {
+ assertArrayEquals(
+ new SimpleElement[] { new SimpleElement("android.view.LinearLayout",
+ null, null, null) },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout\n" +
+ "}\n"));
+
+ assertArrayEquals(
+ new SimpleElement[] { new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ null, null) },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout\n" +
+ "}\n"));
+
+ assertArrayEquals(
+ new SimpleElement[] { new SimpleElement("android.view.LinearLayout",
+ null,
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)) },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "}\n"));
+
+
+ assertArrayEquals(
+ new SimpleElement[] { e },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "}\n"));
+
+
+ e.addAttribute(new SimpleAttribute("uri", "name", "value"));
+ e.addAttribute(new SimpleAttribute("my-uri", "second-name", "my = value "));
+
+ assertArrayEquals(
+ new SimpleElement[] { e },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "@name:uri=value\n" +
+ "@second-name:my-uri=my = value \n" +
+ "}\n"));
+
+
+ SimpleElement e2 = new SimpleElement("android.view.Button",
+ "android.view.LinearLayout",
+ new Rect(10, 20, 30, 40),
+ new Rect(0, 0, 320, 480));
+ e2.addAttribute(new SimpleAttribute("uri1", "name1", "value1"));
+ SimpleElement e3 = new SimpleElement("android.view.CheckBox",
+ "android.view.LinearLayout",
+ new Rect(-1, -2, -3, -4),
+ new Rect(-1, -2, -3, -4));
+ e3.addAttribute(new SimpleAttribute("uri2", "name2", "value2"));
+ e3.addAttribute(new SimpleAttribute("uri3", "name3", "value3"));
+ e.addInnerElement(e2);
+ e.addInnerElement(e3);
+
+ assertArrayEquals(
+ new SimpleElement[] { e },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "@name:uri=value\n" +
+ "@second-name:my-uri=my = value \n" +
+ "{V=3,N=android.view.Button,P=android.view.LinearLayout,R=10 20 30 40,Q=0 0 320 480\n" +
+ "@name1:uri1=value1\n" +
+ "}\n" +
+ "{V=3,N=android.view.CheckBox,P=android.view.LinearLayout,R=-1 -2 -3 -4,Q=-1 -2 -3 -4\n" +
+ "@name2:uri2=value2\n" +
+ "@name3:uri3=value3\n" +
+ "}\n" +
+ "}\n"));
+
+ // Parse string can also parse an array of elements
+ assertArrayEquals(
+ new SimpleElement[] { e, e2, e3 },
+ SimpleElement.parseString(
+ "{V=3,N=android.view.LinearLayout,P=android.view.FrameLayout,R=10 5 60 40,Q=0 0 320 480\n" +
+ "@name:uri=value\n" +
+ "@second-name:my-uri=my = value \n" +
+ "{V=3,N=android.view.Button,P=android.view.LinearLayout,R=10 20 30 40,Q=0 0 320 480\n" +
+ "@name1:uri1=value1\n" +
+ "}\n" +
+ "{V=3,N=android.view.CheckBox,P=android.view.LinearLayout,R=-1 -2 -3 -4\n" +
+ "@name2:uri2=value2\n" +
+ "@name3:uri3=value3\n" +
+ "}\n" +
+ "}\n" +
+ "{V=3,N=android.view.Button,P=android.view.LinearLayout,R=10 20 30 40,Q=0 0 320 480\n" +
+ "@name1:uri1=value1\n" +
+ "}\n" +
+ "{V=3,N=android.view.CheckBox,P=android.view.LinearLayout,R=-1 -2 -3 -4,Q=-1 -2 -3 -4\n" +
+ "@name2:uri2=value2\n" +
+ "@name3:uri3=value3\n" +
+ "}\n"));
+
+ }
+
+ public final void testAddGetAttribute() {
+ assertNotNull(e.getAttributes());
+ assertArrayEquals(
+ new SimpleAttribute[] {},
+ e.getAttributes());
+
+ e.addAttribute(new SimpleAttribute("uri", "name", "value"));
+ assertArrayEquals(
+ new SimpleAttribute[] { new SimpleAttribute("uri", "name", "value") },
+ e.getAttributes());
+
+ e.addAttribute(new SimpleAttribute("my-uri", "second-name", "value"));
+ assertArrayEquals(
+ new SimpleAttribute[] { new SimpleAttribute("uri", "name", "value"),
+ new SimpleAttribute("my-uri", "second-name", "value") },
+ e.getAttributes());
+
+ assertNull(e.getAttribute("unknown uri", "name"));
+ assertNull(e.getAttribute("uri", "unknown name"));
+ assertEquals(new SimpleAttribute("uri", "name", "value"),
+ e.getAttribute("uri", "name"));
+ assertEquals(new SimpleAttribute("my-uri", "second-name", "value"),
+ e.getAttribute("my-uri", "second-name"));
+ }
+
+ public final void testAddGetInnerElements() {
+ assertNotNull(e.getInnerElements());
+ assertArrayEquals(
+ new SimpleElement[] {},
+ e.getInnerElements());
+
+ e.addInnerElement(new SimpleElement("android.view.Button", null, null, null));
+ assertArrayEquals(
+ new SimpleElement[] { new SimpleElement("android.view.Button", null, null, null) },
+ e.getInnerElements());
+
+ e.addInnerElement(new SimpleElement("android.view.CheckBox", null, null, null));
+ assertArrayEquals(
+ new SimpleElement[] { new SimpleElement("android.view.Button", null, null, null),
+ new SimpleElement("android.view.CheckBox", null, null, null) },
+ e.getInnerElements());
+ }
+
+ public final void testEqualsObject() {
+ assertFalse(e.equals(null));
+ assertFalse(e.equals(new Object()));
+
+ assertNotSame(new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)),
+ e);
+ assertEquals(new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)),
+ e);
+ assertTrue(e.equals(new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480))));
+
+ // not the same FQCN
+ assertFalse(e.equals(new SimpleElement("android.view.Button",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480))));
+
+ // not the same parent
+ assertFalse(e.equals(new SimpleElement("android.view.LinearLayout",
+ "android.view.LinearLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480))));
+
+ // not the same bounds
+ assertFalse(e.equals(new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 25, 30, 40),
+ new Rect(0, 0, 320, 480))));
+
+ // not the same parent bounds
+ assertFalse(e.equals(new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(10, 100, 160, 240))));
+ }
+
+ public final void testHashCode() {
+ int he = e.hashCode();
+
+ assertEquals(he, new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)).hashCode());
+
+
+ // not the same FQCN
+ assertFalse(he == new SimpleElement("android.view.Button",
+ "android.view.FrameLayout",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)).hashCode());
+
+ // not the same parent
+ assertFalse(he == new SimpleElement("android.view.LinearLayout",
+ "android.view.Button",
+ new Rect(10, 5, 60, 40),
+ new Rect(0, 0, 320, 480)).hashCode());
+
+ // not the same bounds
+ assertFalse(he == new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 25, 30, 40),
+ new Rect(0, 0, 320, 480)).hashCode());
+
+ // not the same parent bounds
+ assertFalse(he == new SimpleElement("android.view.LinearLayout",
+ "android.view.FrameLayout",
+ new Rect(10, 25, 30, 40),
+ new Rect(10, 100, 160, 240)).hashCode());
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java
new file mode 100644
index 000000000..de7999c24
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtilsTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gle2;
+
+import com.android.ide.common.api.Rect;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class SwtUtilsTest extends TestCase {
+
+ public void testImageConvertNoAlpha() throws Exception {
+ // Note: We need an TYPE_INT_ARGB SWT image here (instead of TYPE_INT_ARGB_PRE) to
+ // prevent the alpha from being pre-multiplied into the RGB when drawing the image.
+ BufferedImage inImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = inImage.getGraphics();
+ g.setColor(new Color(0xAA112233, true));
+ g.fillRect(0, 0, inImage.getWidth(), inImage.getHeight());
+ g.dispose();
+
+ Shell shell = new Shell();
+ Display display = shell.getDisplay();
+
+ // Convert the RGB image, effectively discarding the alpha channel entirely.
+ Image outImage = SwtUtils.convertToSwt(display, inImage, false, -1);
+ assertNotNull(outImage);
+
+ ImageData outData = outImage.getImageData();
+ assertEquals(inImage.getWidth(), outData.width);
+ assertEquals(inImage.getHeight(), outData.height);
+ assertNull(outData.alphaData);
+ assertEquals(SWT.TRANSPARENCY_NONE, outData.getTransparencyType());
+
+ PaletteData inPalette = SwtUtils.getAwtPaletteData(inImage.getType());
+ PaletteData outPalette = outData.palette;
+
+ for (int y = 0; y < outData.height; y++) {
+ for (int x = 0; x < outData.width; x++) {
+ // Note: we can't compare pixel directly as integers since convertToSwt() might
+ // have changed the RGBA ordering depending on the platform (e.g. it will on
+ // Windows.)
+ RGB expected = inPalette.getRGB( inImage.getRGB( x, y));
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+ }
+ }
+
+ // Convert back to AWT and compare with original AWT image
+ BufferedImage awtImage = SwtUtils.convertToAwt(outImage);
+ assertNotNull(awtImage);
+
+ // Both image have the same RGBA ordering
+ assertEquals(BufferedImage.TYPE_INT_ARGB, inImage.getType());
+ assertEquals(BufferedImage.TYPE_INT_ARGB, awtImage.getType());
+
+ int awtAlphaMask = 0xFF000000;
+
+ for (int y = 0; y < outData.height; y++) {
+ for (int x = 0; x < outData.width; x++) {
+ // Note: we can compare pixels as integers since we just
+ // asserted both images have the same color image type except
+ // for the content of the alpha channel.
+ int actual = awtImage.getRGB(x, y);
+ assertEquals(awtAlphaMask, actual & awtAlphaMask);
+ assertEquals(awtAlphaMask | inImage.getRGB(x, y), awtImage.getRGB(x, y));
+ }
+ }
+ }
+
+ public void testImageConvertGlobalAlpha() throws Exception {
+ BufferedImage inImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = inImage.getGraphics();
+ g.setColor(new Color(0xAA112233, true));
+ g.fillRect(0, 0, inImage.getWidth(), inImage.getHeight());
+ g.dispose();
+
+ Shell shell = new Shell();
+ Display display = shell.getDisplay();
+
+ Image outImage = SwtUtils.convertToSwt(display, inImage, false, 128);
+ assertNotNull(outImage);
+
+ ImageData outData = outImage.getImageData();
+ assertEquals(inImage.getWidth(), outData.width);
+ assertEquals(inImage.getHeight(), outData.height);
+ assertEquals(128, outData.alpha);
+ assertEquals(SWT.TRANSPARENCY_NONE, outData.getTransparencyType());
+ assertNull(outData.alphaData);
+
+ PaletteData inPalette = SwtUtils.getAwtPaletteData(inImage.getType());
+ PaletteData outPalette = outData.palette;
+
+ for (int y = 0; y < outData.height; y++) {
+ for (int x = 0; x < outData.width; x++) {
+
+ RGB expected = inPalette.getRGB( inImage.getRGB( x, y));
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+ }
+ }
+ }
+
+ public void testImageConvertAlpha() throws Exception {
+ BufferedImage inImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = inImage.getGraphics();
+ g.setColor(new Color(0xAA112233, true));
+ g.fillRect(0, 0, inImage.getWidth(), inImage.getHeight());
+ g.dispose();
+
+ Shell shell = new Shell();
+ Display display = shell.getDisplay();
+
+ Image outImage = SwtUtils.convertToSwt(display, inImage, true, -1);
+ assertNotNull(outImage);
+
+ ImageData outData = outImage.getImageData();
+ assertEquals(inImage.getWidth(), outData.width);
+ assertEquals(inImage.getHeight(), outData.height);
+ assertEquals(SWT.TRANSPARENCY_ALPHA, outData.getTransparencyType());
+
+ PaletteData inPalette = SwtUtils.getAwtPaletteData(inImage.getType());
+ PaletteData outPalette = outData.palette;
+
+ for (int y = 0; y < outData.height; y++) {
+ for (int x = 0; x < outData.width; x++) {
+ RGB expected = inPalette.getRGB( inImage.getRGB( x, y));
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+
+ // Note: >> instead of >>> since we will compare with byte (a signed number)
+ int expectedAlpha = inImage.getRGB(x, y) >> 24;
+ int actualAlpha = outData.alphaData[y * outData.width + x];
+ assertEquals(expectedAlpha, actualAlpha);
+ }
+ }
+ }
+
+ public void testImageConvertAlphaMultiplied() throws Exception {
+ BufferedImage inImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = inImage.getGraphics();
+ g.setColor(new Color(0xAA112233, true));
+ g.fillRect(0, 0, inImage.getWidth(), inImage.getHeight());
+ g.dispose();
+
+ Shell shell = new Shell();
+ Display display = shell.getDisplay();
+ Image outImage = SwtUtils.convertToSwt(display, inImage, true, 32);
+ assertNotNull(outImage);
+
+ // Expected alpha is 0xAA from the AWT input image pre-multiplied by 32 in convertToSwt.
+ int expectedAlpha = (0xAA * 32) >> 8;
+
+ ImageData outData = outImage.getImageData();
+ assertEquals(inImage.getWidth(), outData.width);
+ assertEquals(inImage.getHeight(), outData.height);
+ assertEquals(SWT.TRANSPARENCY_ALPHA, outData.getTransparencyType());
+
+ PaletteData inPalette = SwtUtils.getAwtPaletteData(inImage.getType());
+ PaletteData outPalette = outData.palette;
+
+ for (int y = 0; y < outData.height; y++) {
+ for (int x = 0; x < outData.width; x++) {
+ RGB expected = inPalette.getRGB( inImage.getRGB( x, y));
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+
+ byte actualAlpha = outData.alphaData[y * outData.width + x];
+ assertEquals(expectedAlpha, actualAlpha);
+ }
+ }
+ }
+
+ public final void testSetRectangle() {
+ Rect r = new Rect(1, 2, 3, 4);
+ Rectangle r2 = new Rectangle(3, 4, 20, 30);
+ SwtUtils.set(r, r2);
+
+ assertEquals(3, r.x);
+ assertEquals(4, r.y);
+ assertEquals(20, r.w);
+ assertEquals(30, r.h);
+ }
+
+ public final void testRectRectangle() {
+ Rectangle r = new Rectangle(3, 4, 20, 30);
+ Rect r2 = SwtUtils.toRect(r);
+
+ assertEquals(3, r2.x);
+ assertEquals(4, r2.y);
+ assertEquals(20, r2.w);
+ assertEquals(30, r2.h);
+ }
+
+ public final void testCropEmpty() {
+ Image image = createSampleImage(256, 256);
+ Image result = SwtUtils.drawRectangles(image, Collections.<Rectangle> emptyList(), null,
+ 1.0, (byte) 121);
+ assertNull(result);
+ }
+
+ public final void testCrop1() {
+ Image image = createSampleImage(256, 256);
+
+ byte alpha = 121;
+ double scale = 1.0;
+
+ List<Rectangle> items = new ArrayList<Rectangle>();
+ items.add(new Rectangle(30, 60, 20, 20));
+ Image result =
+ SwtUtils.drawRectangles(image, items, ImageUtils.getBoundingRectangle(items),
+ scale, alpha);
+
+ assertNotNull(result);
+ ImageData outData = result.getImageData();
+ assertEquals(20, outData.width);
+ assertEquals(20, outData.height);
+
+ PaletteData outPalette = outData.palette;
+ assertNotNull(outPalette);
+
+ byte[] outAlphaData = outData.alphaData;
+ assertNotNull(outAlphaData);
+
+ for (int y = 0; y < 20; y++) {
+ for (int x = 0; x < 20; x++) {
+ int r = y + 60;
+ int g = x + 30;
+
+ RGB expected = new RGB(r, g, 0);
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+
+ byte actualAlpha = outAlphaData[y*20+x];
+ assertEquals(alpha, actualAlpha);
+ }
+ }
+ }
+
+ public final void testCrop2() {
+ Image image = createSampleImage(256, 256);
+
+ byte alpha = 121;
+ double scale = 1.0;
+
+ List<Rectangle> items = new ArrayList<Rectangle>();
+ items.add(new Rectangle(10, 10, 20, 20));
+ items.add(new Rectangle(110, 80, 20, 20));
+ Image result =
+ SwtUtils.drawRectangles(image, items, ImageUtils.getBoundingRectangle(items),
+ scale, alpha);
+
+ assertNotNull(result);
+ ImageData outData = result.getImageData();
+ assertEquals(120, outData.width);
+ assertEquals(90, outData.height);
+
+ PaletteData outPalette = outData.palette;
+ assertNotNull(outPalette);
+
+ byte[] outAlphaData = outData.alphaData;
+ assertNotNull(outAlphaData);
+
+ for (int y = 0; y < 20; y++) {
+ for (int x = 0; x < 20; x++) {
+ int r = y + 10;
+ int g = x + 10;
+
+ RGB expected = new RGB(r, g, 0);
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+
+ assertEquals(alpha, outAlphaData[y*120+x]);
+ }
+ }
+ for (int y = 70; y < 90; y++) {
+ for (int x = 100; x < 120; x++) {
+ int r = y + 10;
+ int g = x + 10;
+
+ RGB expected = new RGB(r, g, 0);
+ RGB actual = outPalette.getRGB(outData.getPixel(x, y));
+ assertEquals(expected, actual);
+
+ assertEquals(alpha, outAlphaData[y*120+x]);
+ }
+ }
+ assertEquals(0, outAlphaData[40]);
+ }
+
+ /**
+ * Crop test utility: Create a sample image patterned with red=y and green=x, suitable
+ * for checking that in image copying operations we've copied and scaled the right
+ * bits. (Obviously the red/green will be mod'ed with 256).
+ *
+ * @param imageWidth the width of the target image
+ * @param imageHeight the height of the target image
+ * @return a new image with a red/green pattern
+ */
+ private Image createSampleImage(int imageWidth, int imageHeight) {
+ Shell shell = new Shell();
+ Display display = shell.getDisplay();
+
+ ImageData data = new ImageData(imageWidth, imageHeight, 32, new PaletteData(0x00FF0000,
+ 0x0000FF00, 0x000000FF));
+ for (int y = 0; y < imageHeight; y++) {
+ for (int x = 0; x < imageWidth; x++) {
+ int pixelValue = (y & 0xFF) << 16 | (x & 0xFF) << 8;
+ data.setPixel(x, y, pixelValue);
+ }
+ }
+ Image image = new Image(display, data);
+ return image;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/MockNodeProxy.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/MockNodeProxy.java
new file mode 100755
index 000000000..433d3903d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/MockNodeProxy.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gre;
+
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+
+/**
+ * Mocks a {@link NodeProxy}, creating it using an XML local name and generating
+ * a made-up {@link UiViewElementNode} and a {@link ViewDescriptor} on the fly.
+ */
+public class MockNodeProxy extends NodeProxy {
+
+ /**
+ * Generates a {@link NodeProxy} using an FQCN (e.g. android.view.View)
+ * and making the last segment of the FQCN the XML name of the view (e.g. "View")
+ * and wraps it as a {@link NodeProxy}.
+ *
+ * @param fqcn The fully qualified name of the class to wrap, e.g. "android.view.Button".
+ * @param bounds The bounds of a the view in the canvas. Must be either: <br/>
+ * - a valid rect for a view that is actually in the canvas <br/>
+ * - <b>*or*</b> null (or an invalid rect) for a view that has just been added dynamically
+ * to the model. We never store a null bounds rectangle in the node, a null rectangle
+ * will be converted to an invalid rectangle.
+ * @param factory A {@link NodeFactory} to create unique children nodes.
+ */
+ public MockNodeProxy(String fqcn, Rectangle bounds, NodeFactory factory) {
+ super(makeUiViewNode(fqcn), bounds, factory);
+ }
+
+ /**
+ * Generates a {@link ViewElementDescriptor} using an FQCN (e.g. android.view.View)
+ * and making the last segment of the FQCN the XML name of the view (e.g. "View").
+ *
+ * @param fqcn The fully qualified name of the class to wrap, e.g. "android.view.Button"
+ * @return A new view element node with a new descriptor for the FQCN and an XML name
+ * matching the last FQCN segment (e.g. "Button")
+ */
+ private static UiViewElementNode makeUiViewNode(String fqcn) {
+ String xmlName = fqcn;
+ int pos = xmlName.lastIndexOf('.');
+ if (pos > 0) {
+ xmlName = xmlName.substring(pos + 1);
+ }
+
+ ViewElementDescriptor desc = new ViewElementDescriptor(xmlName, fqcn);
+ UiViewElementNode uiNode = new UiViewElementNode(desc);
+ return uiNode;
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeFactoryTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeFactoryTest.java
new file mode 100755
index 000000000..0e6d33db3
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeFactoryTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gre;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Rect;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class NodeFactoryTest extends TestCase {
+
+ private NodeFactory m;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ m = new NodeFactory(null);
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ m = null;
+ }
+
+ public final void testCreateCanvasViewInfo() {
+ ViewElementDescriptor ved = new ViewElementDescriptor("xml", "com.example.MyJavaClass");
+ UiViewElementNode uiv = new UiViewElementNode(ved);
+ ViewInfo lvi = new ViewInfo("name", uiv, 10, 12, 110, 120);
+ CanvasViewInfo cvi = CanvasViewInfo.create(lvi, true /* layoutlib5 */).getFirst();
+
+ // Create a NodeProxy.
+ NodeProxy proxy = m.create(cvi);
+
+ // getNode() is our only internal implementation method.
+ assertNotNull(proxy);
+ assertSame(uiv, proxy.getNode());
+
+ // Groovy scripts only see the INode interface so we want to primarily test that.
+ INode inode = proxy;
+ assertEquals(new Rect(10, 12, 110-10-1, 120-12-1), inode.getBounds());
+ assertTrue(Arrays.equals(new INode[0], inode.getChildren()));
+ assertEquals("com.example.MyJavaClass", inode.getFqcn());
+ assertNull(inode.getParent());
+ assertSame(inode, inode.getRoot());
+
+ }
+
+ public final void testCreateUiViewElementNode() {
+ ViewElementDescriptor ved = new ViewElementDescriptor("xml", "com.example.MyJavaClass");
+ UiViewElementNode uiv = new UiViewElementNode(ved);
+
+ // Create a NodeProxy.
+ NodeProxy proxy = m.create(uiv);
+
+ // getNode() is our only internal implementation method.
+ assertNotNull(proxy);
+ assertSame(uiv, proxy.getNode());
+
+ // Groovy scripts only see the INode interface so we want to primarily test that.
+ INode inode = proxy;
+ // Nodes constructed using this create() method do not have valid bounds.
+ // There should be one invalid bound rectangle.
+ assertNotNull(inode.getBounds());
+ assertFalse(inode.getBounds().isValid());
+ // All the other properties should be set correctly.
+ assertTrue(Arrays.equals(new INode[0], inode.getChildren()));
+ assertEquals("com.example.MyJavaClass", inode.getFqcn());
+ assertNull(inode.getParent());
+ assertSame(inode, inode.getRoot());
+ }
+
+ public final void testCreateDup() {
+ ViewElementDescriptor ved = new ViewElementDescriptor("xml", "com.example.MyJavaClass");
+ UiViewElementNode uiv = new UiViewElementNode(ved);
+ ViewInfo lvi = new ViewInfo("name", uiv, 10, 12, 110, 120);
+ CanvasViewInfo cvi = CanvasViewInfo.create(lvi, true /* layoutlib5 */).getFirst();
+
+ // NodeProxies are cached. Creating the same one twice returns the same proxy.
+ NodeProxy proxy1 = m.create(cvi);
+ NodeProxy proxy2 = m.create(cvi);
+ assertSame(proxy2, proxy1);
+ }
+
+ public final void testClear() {
+ ViewElementDescriptor ved = new ViewElementDescriptor("xml", "com.example.MyJavaClass");
+ UiViewElementNode uiv = new UiViewElementNode(ved);
+ ViewInfo lvi = new ViewInfo("name", uiv, 10, 12, 110, 120);
+ CanvasViewInfo cvi = CanvasViewInfo.create(lvi, true /* layoutlib5 */).getFirst();
+
+ // NodeProxies are cached. Creating the same one twice returns the same proxy.
+ NodeProxy proxy1 = m.create(cvi);
+ NodeProxy proxy2 = m.create(cvi);
+ assertSame(proxy2, proxy1);
+
+ // Clearing the cache will force it create a new proxy.
+ m.clear();
+ NodeProxy proxy3 = m.create(cvi);
+ assertNotSame(proxy1, proxy3);
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngineTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngineTest.java
new file mode 100755
index 000000000..d9a1a3dc1
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngineTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 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.editors.layout.gre;
+
+import junit.framework.TestCase;
+
+public class RulesEngineTest extends TestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testDummy() {
+ // Here to avoid warning that RulesEngineTest is empty
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java
new file mode 100644
index 000000000..50d438cdb
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gre/ViewMetadataRepositoryTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 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.editors.layout.gre;
+
+import com.android.ide.common.api.IViewMetadata.FillPreference;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository.RenderMode;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class ViewMetadataRepositoryTest extends TestCase {
+ public void testSingleton() throws Exception {
+ assertSame(ViewMetadataRepository.get(), ViewMetadataRepository.get());
+ }
+
+ public void testBasic() throws Exception {
+ ViewMetadataRepository repository = ViewMetadataRepository.get();
+
+ assertEquals(FillPreference.WIDTH_IN_VERTICAL,
+ repository.getFillPreference("android.widget.Spinner"));
+ assertEquals(FillPreference.NONE,
+ repository.getFillPreference("foo.bar"));
+ }
+
+ // Ensure that all basenames referenced in the metadata refer to other views in the file
+ // (e.g. no typos)
+ public void testRelatedTo() throws Exception {
+ // Make sure unit tests are run with assertions on
+ boolean assertionsEnabled = false;
+ assert assertionsEnabled = true; // Intentional assignment
+ assertTrue("This unit test must be run with assertions enabled (-ea)", assertionsEnabled);
+
+ ViewMetadataRepository repository = ViewMetadataRepository.get();
+ for (String fqcn : repository.getAllFqcns()) {
+ repository.getRelatedTo(fqcn);
+ }
+ }
+
+ public void testSkip() throws Exception {
+ ViewMetadataRepository repository = ViewMetadataRepository.get();
+ assertTrue(repository.getSkip("merge"));
+ assertFalse(repository.getSkip("android.widget.Button"));
+ }
+
+ public void testRenderMode() throws Exception {
+ ViewMetadataRepository repository = ViewMetadataRepository.get();
+ assertEquals(RenderMode.NORMAL, repository.getRenderMode("android.widget.Button"));
+ assertEquals(RenderMode.SKIP, repository.getRenderMode("android.widget.LinearLayout"));
+ assertEquals(RenderMode.ALONE, repository.getRenderMode("android.widget.TabHost"));
+ }
+
+ public void testGetTopAttributes() throws Exception {
+ ViewMetadataRepository repository = ViewMetadataRepository.get();
+ assertEquals(Arrays.asList("id", "text", "style"),
+ repository.getTopAttributes("android.widget.RadioButton"));
+ assertEquals(Arrays.asList("id", "gravity", "paddingLeft", "paddingRight", "checkMark",
+ "textAppearance"),
+ repository.getTopAttributes("android.widget.CheckedTextView"));
+ assertEquals(Arrays.asList("id"),
+ repository.getTopAttributes("android.widget.NonExistent"));
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleterTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleterTest.java
new file mode 100644
index 000000000..0014fe574
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/properties/ValueCompleterTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 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.editors.layout.properties;
+
+import static com.android.SdkConstants.ANDROID_URI;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.api.IAttributeInfo;
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.layout.TestAttributeInfo;
+import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
+
+import org.eclipse.jface.fieldassist.IContentProposal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("javadoc")
+public class ValueCompleterTest extends TestCase {
+ private void checkCompletion(String text, int offset,
+ String property, EnumSet<Format> formats, String[] values,
+ List<String> expected) {
+ assertTrue(text.length() >= offset);
+
+ TestAttributeInfo info =
+ new TestAttributeInfo(property, formats, "unittest", values, values, null);
+ TestValueCompleter completer = new TestValueCompleter(
+ new TestTextAttributeDescriptor(property, info));
+ IContentProposal[] proposals = completer.getProposals(text, offset);
+ List<String> actual = new ArrayList<String>();
+ for (IContentProposal proposal : proposals) {
+ String content = proposal.getContent();
+ actual.add(content);
+ }
+ assertEquals(expected.toString(), actual.toString());
+ }
+
+ public void test() throws Exception {
+ checkCompletion("@android:string", 3, "text",
+ EnumSet.of(Format.REFERENCE), null,
+ Arrays.asList(new String[] { }));
+ }
+
+ public void test1a() throws Exception {
+ checkCompletion("matc", 4, "layout_width",
+ EnumSet.of(Format.DIMENSION, Format.ENUM),
+ new String[] { "fill_parent", "match_parent", "wrap_content" },
+
+ Arrays.asList(new String[] { "match_parent", "fill_parent", "wrap_content" }));
+ }
+
+ public void test1b() throws Exception {
+ checkCompletion("fi", 2, "layout_width",
+ EnumSet.of(Format.DIMENSION, Format.ENUM),
+ new String[] { "fill_parent", "match_parent", "wrap_content" },
+
+ Arrays.asList(new String[] { "fill_parent", "match_parent", "wrap_content" }));
+ }
+
+ public void test2() throws Exception {
+ checkCompletion("50", 2, "layout_width",
+ EnumSet.of(Format.DIMENSION, Format.ENUM),
+ new String[] { "fill_parent", "match_parent", "wrap_content" },
+
+ Arrays.asList(new String[] { "50dp", "fill_parent", "match_parent",
+ "wrap_content" }));
+ }
+
+ public void test3() throws Exception {
+ checkCompletion("42", 2, "textSize",
+ EnumSet.of(Format.DIMENSION),
+ null,
+
+ Arrays.asList(new String[] { "42sp", "42dp" }));
+ }
+
+ public void test4() throws Exception {
+ checkCompletion("", 0, "gravity",
+ EnumSet.of(Format.FLAG),
+ new String[] { "top", "bottom", "left", "right", "center" },
+
+ Arrays.asList(new String[] { "top", "bottom", "left", "right", "center" }));
+ }
+
+ public void test5() throws Exception {
+ checkCompletion("left", 4, "gravity",
+ EnumSet.of(Format.FLAG),
+ new String[] { "top", "bottom", "left", "right", "center" },
+
+ Arrays.asList(new String[] {
+ "left", "left|top", "left|bottom", "left|right", "left|center" }));
+ }
+
+ public void test6() throws Exception {
+ checkCompletion("left|top", 8, "gravity",
+ EnumSet.of(Format.FLAG),
+ new String[] { "top", "bottom", "left", "right", "center" },
+
+ Arrays.asList(new String[] {
+ "left|top", "left|top|bottom", "left|top|right", "left|top|center" }));
+ }
+
+ // TODO ?android
+
+ private class TestTextAttributeDescriptor extends TextAttributeDescriptor {
+ public TestTextAttributeDescriptor(String xmlLocalName, IAttributeInfo attrInfo) {
+ super(xmlLocalName, ANDROID_URI, attrInfo);
+ }
+ }
+
+ private class TestValueCompleter extends ValueCompleter {
+ private final AttributeDescriptor mDescriptor;
+
+ TestValueCompleter(AttributeDescriptor descriptor) {
+ mDescriptor = descriptor;
+ assert descriptor.getAttributeInfo() != null;
+ }
+
+ @Override
+ @Nullable
+ protected CommonXmlEditor getEditor() {
+ return null;
+ }
+
+ @Override
+ @NonNull
+ protected AttributeDescriptor getDescriptor() {
+ return mDescriptor;
+ }
+ }
+}