diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout')
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; + } + } +} |