1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.layoutlib.bridge.impl; 18 19 import org.junit.Test; 20 import org.kxml2.io.KXmlParser; 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 24 import java.io.StringReader; 25 26 import static com.android.SdkConstants.NS_RESOURCES; 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertNotSame; 29 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 30 import static org.xmlpull.v1.XmlPullParser.END_TAG; 31 import static org.xmlpull.v1.XmlPullParser.START_TAG; 32 33 34 public class LayoutParserWrapperTest { 35 @Test 36 @SuppressWarnings("StatementWithEmptyBody") // some for loops need to be empty statements. testDataBindingLayout()37 public void testDataBindingLayout() throws Exception { 38 LayoutParserWrapper parser = getParserFromString(sDataBindingLayout); 39 parser.peekTillLayoutStart(); 40 assertEquals("Expected START_TAG", START_TAG, parser.next()); 41 assertEquals("RelativeLayout", parser.getName()); 42 for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT; 43 next = parser.next()); 44 assertEquals("Expected START_TAG", START_TAG, parser.getEventType()); 45 assertEquals("TextView", parser.getName()); 46 assertEquals("layout_width incorrect for first text view.", "wrap_content", 47 parser.getAttributeValue(NS_RESOURCES, "layout_width")); 48 // Ensure that data-binding part is stripped. 49 assertEquals("Bound attribute android:text incorrect", "World", 50 parser.getAttributeValue(NS_RESOURCES, "text")); 51 assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first", 52 parser.getAttributeValue(NS_RESOURCES, "id")); 53 for (int next = parser.next(); 54 (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT; 55 next = parser.next()); 56 assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType()); 57 assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next()); 58 } 59 60 @Test 61 @SuppressWarnings("StatementWithEmptyBody") testNonDataBindingLayout()62 public void testNonDataBindingLayout() throws Exception { 63 LayoutParserWrapper parser = getParserFromString(sNonDataBindingLayout); 64 parser.peekTillLayoutStart(); 65 assertEquals("Expected START_TAG", START_TAG, parser.next()); 66 assertEquals("RelativeLayout", parser.getName()); 67 for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT; 68 next = parser.next()); 69 assertEquals("Expected START_TAG", START_TAG, parser.getEventType()); 70 assertEquals("TextView", parser.getName()); 71 assertEquals("layout_width incorrect for first text view.", "wrap_content", 72 parser.getAttributeValue(NS_RESOURCES, "layout_width")); 73 // Ensure that value isn't modified. 74 assertEquals("Bound attribute android:text incorrect", "@{user.firstName,default=World}", 75 parser.getAttributeValue(NS_RESOURCES, "text")); 76 assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first", 77 parser.getAttributeValue(NS_RESOURCES, "id")); 78 for (int next = parser.next(); 79 (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT; 80 next = parser.next()); 81 assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType()); 82 assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next()); 83 } 84 getParserFromString(String layoutContent)85 private static LayoutParserWrapper getParserFromString(String layoutContent) throws 86 XmlPullParserException { 87 XmlPullParser parser = new KXmlParser(); 88 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 89 parser.setInput(new StringReader(layoutContent)); 90 return new LayoutParserWrapper(parser); 91 } 92 93 private static final String sDataBindingLayout = 94 //language=XML 95 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + 96 "<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 97 " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" + 98 " xmlns:tools=\"http://schemas.android.com/tools\"\n" + 99 " tools:context=\".MainActivity\"\n" + 100 " tools:showIn=\"@layout/activity_main\">\n" + 101 "\n" + 102 " <data>\n" + 103 "\n" + 104 " <variable\n" + 105 " name=\"user\"\n" + 106 " type=\"com.example.User\" />\n" + 107 " <variable\n" + 108 " name=\"activity\"\n" + 109 " type=\"com.example.MainActivity\" />\n" + 110 " </data>\n" + 111 "\n" + 112 " <RelativeLayout\n" + 113 " android:layout_width=\"match_parent\"\n" + 114 " android:layout_height=\"match_parent\"\n" + 115 " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + 116 " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + 117 " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + 118 " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + 119 " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" + 120 " >\n" + 121 "\n" + 122 " <TextView\n" + 123 " android:id=\"@+id/first\"\n" + 124 " android:layout_width=\"wrap_content\"\n" + 125 " android:layout_alignParentStart=\"true\"\n" + 126 " android:layout_alignParentLeft=\"true\"\n" + 127 " android:layout_height=\"wrap_content\"\n" + 128 " android:text=\"@{user.firstName,default=World}\" />\n" + 129 "\n" + 130 " <TextView\n" + 131 " android:id=\"@+id/last\"\n" + 132 " android:layout_width=\"wrap_content\"\n" + 133 " android:layout_height=\"wrap_content\"\n" + 134 " android:layout_toEndOf=\"@id/first\"\n" + 135 " android:layout_toRightOf=\"@id/first\"\n" + 136 " android:text=\"@{user.lastName,default=Hello}\" />\n" + 137 "\n" + 138 " <Button\n" + 139 " android:layout_width=\"wrap_content\"\n" + 140 " android:layout_height=\"wrap_content\"\n" + 141 " android:layout_below=\"@id/last\"\n" + 142 " android:text=\"Submit\"\n" + 143 " android:onClick=\"@{activity.onClick}\"/>\n" + 144 " </RelativeLayout>\n" + 145 "</layout>"; 146 147 private static final String sNonDataBindingLayout = 148 //language=XML 149 "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 150 " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" + 151 " android:layout_width=\"match_parent\"\n" + 152 " android:layout_height=\"match_parent\"\n" + 153 " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + 154 " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + 155 " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + 156 " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + 157 " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" + 158 ">\n" + 159 "\n" + 160 " <TextView\n" + 161 " android:id=\"@+id/first\"\n" + 162 " android:layout_width=\"wrap_content\"\n" + 163 " android:layout_alignParentStart=\"true\"\n" + 164 " android:layout_alignParentLeft=\"true\"\n" + 165 " android:layout_height=\"wrap_content\"\n" + 166 " android:text=\"@{user.firstName,default=World}\" />\n" + 167 "\n" + 168 " <TextView\n" + 169 " android:id=\"@+id/last\"\n" + 170 " android:layout_width=\"wrap_content\"\n" + 171 " android:layout_height=\"wrap_content\"\n" + 172 " android:layout_toEndOf=\"@id/first\"\n" + 173 " android:layout_toRightOf=\"@id/first\"\n" + 174 " android:text=\"@{user.lastName,default=Hello}\" />\n" + 175 "\n" + 176 " <Button\n" + 177 " android:layout_width=\"wrap_content\"\n" + 178 " android:layout_height=\"wrap_content\"\n" + 179 " android:layout_below=\"@id/last\"\n" + 180 " android:text=\"Submit\"\n" + 181 " android:onClick=\"@{activity.onClick}\"/>\n" + 182 "</RelativeLayout>"; 183 } 184