1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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 */
16package com.android.ide.common.layout.relative;
17
18import static com.android.SdkConstants.ATTR_ID;
19import static com.android.SdkConstants.ANDROID_URI;
20
21import com.android.ide.common.api.INode;
22import com.android.ide.common.layout.BaseViewRule;
23import com.android.ide.common.layout.TestNode;
24
25import java.util.Arrays;
26import java.util.Collections;
27import java.util.List;
28
29import junit.framework.TestCase;
30
31@SuppressWarnings("javadoc")
32public class DeletionHandlerTest extends TestCase {
33    public void testSimple() {
34        String xml = "" +
35            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
36            "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
37            "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
38            "    android:layout_width=\"match_parent\"\n" +
39            "    android:layout_height=\"match_parent\"\n" +
40            "    tools:ignore=\"HardcodedText\" >\n" +
41            "\n" +
42            "    <Button\n" +
43            "        android:id=\"@+id/button1\"\n" +
44            "        android:layout_width=\"wrap_content\"\n" +
45            "        android:layout_height=\"wrap_content\"\n" +
46            "        android:layout_alignParentLeft=\"true\"\n" +
47            "        android:text=\"A\" />\n" +
48            "\n" +
49            "    <Button\n" +
50            "        android:id=\"@+id/button2\"\n" +
51            "        android:layout_width=\"wrap_content\"\n" +
52            "        android:layout_height=\"wrap_content\"\n" +
53            "        android:layout_alignBaseline=\"@+id/button1\"\n" +
54            "        android:layout_alignBottom=\"@+id/button1\"\n" +
55            "        android:layout_toRightOf=\"@+id/button1\"\n" +
56            "        android:text=\"B\" />\n" +
57            "\n" +
58            "    <Button\n" +
59            "        android:id=\"@+id/button3\"\n" +
60            "        android:layout_width=\"wrap_content\"\n" +
61            "        android:layout_height=\"wrap_content\"\n" +
62            "        android:layout_alignBottom=\"@+id/button2\"\n" +
63            "        android:layout_toRightOf=\"@+id/button2\"\n" +
64            "        android:text=\"C\" />\n" +
65            "\n" +
66            "</RelativeLayout>";
67        TestNode targetNode = TestNode.createFromXml(xml);
68        assertNotNull(targetNode);
69
70        TestNode button2 = TestNode.findById(targetNode, "@+id/button2");
71
72        INode layout = button2.getParent();
73        List<INode> deletedNodes = Collections.<INode>singletonList(button2);
74        List<INode> movedNodes = Collections.<INode>emptyList();
75        assertSame(layout, targetNode);
76        layout.removeChild(button2);
77
78        DeletionHandler handler = new DeletionHandler(deletedNodes, movedNodes, layout);
79        handler.updateConstraints();
80
81        String updated = TestNode.toXml(targetNode);
82        assertEquals(
83                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
84                "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
85                "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
86                "    android:layout_width=\"match_parent\"\n" +
87                "    android:layout_height=\"match_parent\"\n" +
88                "    tools:ignore=\"HardcodedText\">\n" +
89                "\n" +
90                "    <Button\n" +
91                "        android:id=\"@+id/button1\"\n" +
92                "        android:layout_width=\"wrap_content\"\n" +
93                "        android:layout_height=\"wrap_content\"\n" +
94                "        android:layout_alignParentLeft=\"true\"\n" +
95                "        android:text=\"A\">\n" +
96                "    </Button>\n" +
97                "\n" +
98                "    <Button\n" +
99                "        android:id=\"@+id/button3\"\n" +
100                "        android:layout_width=\"wrap_content\"\n" +
101                "        android:layout_height=\"wrap_content\"\n" +
102                "        android:layout_alignBaseline=\"@+id/button1\"\n" +
103                "        android:layout_alignBottom=\"@+id/button1\"\n" +
104                "        android:layout_toRightOf=\"@+id/button1\"\n" +
105                "        android:text=\"C\">\n" +
106                "    </Button>\n" +
107                "\n" +
108                "</RelativeLayout>",
109                updated);
110        assertFalse(updated.contains(BaseViewRule.stripIdPrefix(button2.getStringAttr(ANDROID_URI,
111                ATTR_ID))));
112    }
113
114    public void testTransitive() {
115        String xml = "" +
116            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
117            "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
118            "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
119            "    android:layout_width=\"match_parent\"\n" +
120            "    android:layout_height=\"match_parent\"\n" +
121            "    tools:ignore=\"HardcodedText\" >\n" +
122            "\n" +
123            "    <Button\n" +
124            "        android:id=\"@+id/button1\"\n" +
125            "        android:layout_width=\"wrap_content\"\n" +
126            "        android:layout_height=\"wrap_content\"\n" +
127            "        android:layout_alignParentLeft=\"true\"\n" +
128            "        android:layout_alignParentTop=\"true\"\n" +
129            "        android:text=\"Above\" />\n" +
130            "\n" +
131            "    <Button\n" +
132            "        android:id=\"@+id/button2\"\n" +
133            "        android:layout_width=\"wrap_content\"\n" +
134            "        android:layout_height=\"wrap_content\"\n" +
135            "        android:layout_alignParentLeft=\"true\"\n" +
136            "        android:layout_below=\"@+id/button1\"\n" +
137            "        android:text=\"A\" />\n" +
138            "\n" +
139            "    <Button\n" +
140            "        android:id=\"@+id/button3\"\n" +
141            "        android:layout_width=\"wrap_content\"\n" +
142            "        android:layout_height=\"wrap_content\"\n" +
143            "        android:layout_alignBaseline=\"@+id/button2\"\n" +
144            "        android:layout_alignBottom=\"@+id/button2\"\n" +
145            "        android:layout_toRightOf=\"@+id/button2\"\n" +
146            "        android:text=\"B\" />\n" +
147            "\n" +
148            "    <Button\n" +
149            "        android:id=\"@+id/button4\"\n" +
150            "        android:layout_width=\"wrap_content\"\n" +
151            "        android:layout_height=\"wrap_content\"\n" +
152            "        android:layout_alignBottom=\"@+id/button3\"\n" +
153            "        android:layout_toRightOf=\"@+id/button3\"\n" +
154            "        android:text=\"C\" />\n" +
155            "\n" +
156            "    <Button\n" +
157            "        android:id=\"@+id/button5\"\n" +
158            "        android:layout_width=\"wrap_content\"\n" +
159            "        android:layout_height=\"wrap_content\"\n" +
160            "        android:layout_alignBaseline=\"@+id/button4\"\n" +
161            "        android:layout_alignBottom=\"@+id/button4\"\n" +
162            "        android:layout_toRightOf=\"@+id/button4\"\n" +
163            "        android:text=\"D\" />\n" +
164            "\n" +
165            "    <Button\n" +
166            "        android:id=\"@+id/button6\"\n" +
167            "        android:layout_width=\"wrap_content\"\n" +
168            "        android:layout_height=\"wrap_content\"\n" +
169            "        android:layout_alignBottom=\"@+id/button5\"\n" +
170            "        android:layout_toRightOf=\"@+id/button5\"\n" +
171            "        android:text=\"E\" />\n" +
172            "\n" +
173            "    <Button\n" +
174            "        android:id=\"@+id/button7\"\n" +
175            "        android:layout_width=\"wrap_content\"\n" +
176            "        android:layout_height=\"wrap_content\"\n" +
177            "        android:layout_alignLeft=\"@+id/button3\"\n" +
178            "        android:layout_below=\"@+id/button3\"\n" +
179            "        android:text=\"Button\" />\n" +
180            "\n" +
181            "    <CheckBox\n" +
182            "        android:id=\"@+id/checkBox1\"\n" +
183            "        android:layout_width=\"wrap_content\"\n" +
184            "        android:layout_height=\"wrap_content\"\n" +
185            "        android:layout_alignBaseline=\"@+id/button7\"\n" +
186            "        android:layout_alignBottom=\"@+id/button7\"\n" +
187            "        android:layout_toRightOf=\"@+id/button7\"\n" +
188            "        android:text=\"CheckBox\" />\n" +
189            "\n" +
190            "    <Button\n" +
191            "        android:id=\"@+id/button8\"\n" +
192            "        android:layout_width=\"wrap_content\"\n" +
193            "        android:layout_height=\"wrap_content\"\n" +
194            "        android:layout_below=\"@+id/checkBox1\"\n" +
195            "        android:layout_toRightOf=\"@+id/checkBox1\"\n" +
196            "        android:text=\"Button\" />\n" +
197            "\n" +
198            "</RelativeLayout>";
199        TestNode targetNode = TestNode.createFromXml(xml);
200        assertNotNull(targetNode);
201        TestNode button7 = TestNode.findById(targetNode, "@+id/button7");
202        TestNode checkBox = TestNode.findById(targetNode, "@+id/checkBox1");
203
204        INode layout = button7.getParent();
205        List<INode> deletedNodes = Arrays.<INode>asList(button7, checkBox);
206        List<INode> movedNodes = Collections.<INode>emptyList();
207        assertSame(layout, targetNode);
208        layout.removeChild(button7);
209        layout.removeChild(checkBox);
210
211        DeletionHandler handler = new DeletionHandler(deletedNodes, movedNodes, layout);
212        handler.updateConstraints();
213
214        String updated = TestNode.toXml(targetNode);
215        assertEquals(
216                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
217                "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
218                "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
219                "    android:layout_width=\"match_parent\"\n" +
220                "    android:layout_height=\"match_parent\"\n" +
221                "    tools:ignore=\"HardcodedText\">\n" +
222                "\n" +
223                "    <Button\n" +
224                "        android:id=\"@+id/button1\"\n" +
225                "        android:layout_width=\"wrap_content\"\n" +
226                "        android:layout_height=\"wrap_content\"\n" +
227                "        android:layout_alignParentLeft=\"true\"\n" +
228                "        android:layout_alignParentTop=\"true\"\n" +
229                "        android:text=\"Above\">\n" +
230                "    </Button>\n" +
231                "\n" +
232                "    <Button\n" +
233                "        android:id=\"@+id/button2\"\n" +
234                "        android:layout_width=\"wrap_content\"\n" +
235                "        android:layout_height=\"wrap_content\"\n" +
236                "        android:layout_alignParentLeft=\"true\"\n" +
237                "        android:layout_below=\"@+id/button1\"\n" +
238                "        android:text=\"A\">\n" +
239                "    </Button>\n" +
240                "\n" +
241                "    <Button\n" +
242                "        android:id=\"@+id/button3\"\n" +
243                "        android:layout_width=\"wrap_content\"\n" +
244                "        android:layout_height=\"wrap_content\"\n" +
245                "        android:layout_alignBaseline=\"@+id/button2\"\n" +
246                "        android:layout_alignBottom=\"@+id/button2\"\n" +
247                "        android:layout_toRightOf=\"@+id/button2\"\n" +
248                "        android:text=\"B\">\n" +
249                "    </Button>\n" +
250                "\n" +
251                "    <Button\n" +
252                "        android:id=\"@+id/button4\"\n" +
253                "        android:layout_width=\"wrap_content\"\n" +
254                "        android:layout_height=\"wrap_content\"\n" +
255                "        android:layout_alignBottom=\"@+id/button3\"\n" +
256                "        android:layout_toRightOf=\"@+id/button3\"\n" +
257                "        android:text=\"C\">\n" +
258                "    </Button>\n" +
259                "\n" +
260                "    <Button\n" +
261                "        android:id=\"@+id/button5\"\n" +
262                "        android:layout_width=\"wrap_content\"\n" +
263                "        android:layout_height=\"wrap_content\"\n" +
264                "        android:layout_alignBaseline=\"@+id/button4\"\n" +
265                "        android:layout_alignBottom=\"@+id/button4\"\n" +
266                "        android:layout_toRightOf=\"@+id/button4\"\n" +
267                "        android:text=\"D\">\n" +
268                "    </Button>\n" +
269                "\n" +
270                "    <Button\n" +
271                "        android:id=\"@+id/button6\"\n" +
272                "        android:layout_width=\"wrap_content\"\n" +
273                "        android:layout_height=\"wrap_content\"\n" +
274                "        android:layout_alignBottom=\"@+id/button5\"\n" +
275                "        android:layout_toRightOf=\"@+id/button5\"\n" +
276                "        android:text=\"E\">\n" +
277                "    </Button>\n" +
278                "\n" +
279                "    <Button\n" +
280                "        android:id=\"@+id/button8\"\n" +
281                "        android:layout_width=\"wrap_content\"\n" +
282                "        android:layout_height=\"wrap_content\"\n" +
283                "        android:layout_alignLeft=\"@+id/button3\"\n" +
284                "        android:layout_below=\"@+id/button3\"\n" +
285                "        android:text=\"Button\">\n" +
286                "    </Button>\n" +
287                "\n" +
288                "</RelativeLayout>",
289                updated);
290        assertFalse(updated.contains(BaseViewRule.stripIdPrefix(button7.getStringAttr(ANDROID_URI,
291                ATTR_ID))));
292    }
293
294    public void testCenter() {
295        String xml =
296            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
297            "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
298            "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
299            "    android:layout_width=\"match_parent\"\n" +
300            "    android:layout_height=\"match_parent\"\n" +
301            "    tools:ignore=\"HardcodedText\" >\n" +
302            "\n" +
303            "    <Button\n" +
304            "        android:id=\"@+id/button1\"\n" +
305            "        android:layout_width=\"wrap_content\"\n" +
306            "        android:layout_height=\"wrap_content\"\n" +
307            "        android:layout_centerInParent=\"true\"\n" +
308            "        android:text=\"Button\" />\n" +
309            "\n" +
310            "    <CheckBox\n" +
311            "        android:id=\"@+id/checkBox1\"\n" +
312            "        android:layout_width=\"wrap_content\"\n" +
313            "        android:layout_height=\"wrap_content\"\n" +
314            "        android:layout_below=\"@+id/button1\"\n" +
315            "        android:layout_toRightOf=\"@+id/button1\"\n" +
316            "        android:text=\"CheckBox\" />\n" +
317            "\n" +
318            "</RelativeLayout>";
319
320        TestNode targetNode = TestNode.createFromXml(xml);
321        assertNotNull(targetNode);
322        TestNode button1 = TestNode.findById(targetNode, "@+id/button1");
323
324        INode layout = button1.getParent();
325        List<INode> deletedNodes = Collections.<INode>singletonList(button1);
326        List<INode> movedNodes = Collections.<INode>emptyList();
327        assertSame(layout, targetNode);
328        layout.removeChild(button1);
329
330        DeletionHandler handler = new DeletionHandler(deletedNodes, movedNodes, layout);
331        handler.updateConstraints();
332
333        String updated = TestNode.toXml(targetNode);
334        assertEquals(
335                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
336                "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
337                "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
338                "    android:layout_width=\"match_parent\"\n" +
339                "    android:layout_height=\"match_parent\"\n" +
340                "    tools:ignore=\"HardcodedText\">\n" +
341                "\n" +
342                "    <CheckBox\n" +
343                "        android:id=\"@+id/checkBox1\"\n" +
344                "        android:layout_width=\"wrap_content\"\n" +
345                "        android:layout_height=\"wrap_content\"\n" +
346                "        android:layout_centerInParent=\"true\"\n" +
347                "        android:text=\"CheckBox\">\n" +
348                "    </CheckBox>\n" +
349                "\n" +
350                "</RelativeLayout>",
351                updated);
352        assertFalse(updated.contains(BaseViewRule.stripIdPrefix(button1.getStringAttr(ANDROID_URI,
353                ATTR_ID))));
354
355    }
356
357    public void testMove() {
358        String xml = "" +
359            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
360            "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
361            "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
362            "    android:layout_width=\"match_parent\"\n" +
363            "    android:layout_height=\"match_parent\"\n" +
364            "    tools:ignore=\"HardcodedText\" >\n" +
365            "\n" +
366            "    <Button\n" +
367            "        android:id=\"@+id/button1\"\n" +
368            "        android:layout_width=\"wrap_content\"\n" +
369            "        android:layout_height=\"wrap_content\"\n" +
370            "        android:layout_alignParentLeft=\"true\"\n" +
371            "        android:text=\"A\" />\n" +
372            "\n" +
373            "    <Button\n" +
374            "        android:id=\"@+id/button2\"\n" +
375            "        android:layout_width=\"wrap_content\"\n" +
376            "        android:layout_height=\"wrap_content\"\n" +
377            "        android:layout_alignBaseline=\"@+id/button1\"\n" +
378            "        android:layout_alignBottom=\"@+id/button1\"\n" +
379            "        android:layout_toRightOf=\"@+id/button1\"\n" +
380            "        android:text=\"B\" />\n" +
381            "\n" +
382            "    <Button\n" +
383            "        android:id=\"@+id/button3\"\n" +
384            "        android:layout_width=\"wrap_content\"\n" +
385            "        android:layout_height=\"wrap_content\"\n" +
386            "        android:layout_alignBottom=\"@+id/button2\"\n" +
387            "        android:layout_toRightOf=\"@+id/button2\"\n" +
388            "        android:text=\"C\" />\n" +
389            "\n" +
390            "</RelativeLayout>";
391        TestNode targetNode = TestNode.createFromXml(xml);
392        assertNotNull(targetNode);
393
394        TestNode button2 = TestNode.findById(targetNode, "@+id/button2");
395
396        INode layout = button2.getParent();
397        List<INode> deletedNodes = Collections.<INode>singletonList(button2);
398        List<INode> movedNodes = Collections.<INode>singletonList(button2);
399        assertSame(layout, targetNode);
400
401        DeletionHandler handler = new DeletionHandler(deletedNodes, movedNodes, layout);
402        handler.updateConstraints();
403
404        String updated = TestNode.toXml(targetNode);
405        assertEquals(
406                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
407                "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
408                "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
409                "    android:layout_width=\"match_parent\"\n" +
410                "    android:layout_height=\"match_parent\"\n" +
411                "    tools:ignore=\"HardcodedText\">\n" +
412                "\n" +
413                "    <Button\n" +
414                "        android:id=\"@+id/button1\"\n" +
415                "        android:layout_width=\"wrap_content\"\n" +
416                "        android:layout_height=\"wrap_content\"\n" +
417                "        android:layout_alignParentLeft=\"true\"\n" +
418                "        android:text=\"A\">\n" +
419                "    </Button>\n" +
420                "\n" +
421                "    <Button\n" +
422                "        android:id=\"@+id/button2\"\n" +
423                "        android:layout_width=\"wrap_content\"\n" +
424                "        android:layout_height=\"wrap_content\"\n" +
425                "        android:layout_alignBaseline=\"@+id/button1\"\n" +
426                "        android:layout_alignBottom=\"@+id/button1\"\n" +
427                "        android:layout_toRightOf=\"@+id/button1\"\n" +
428                "        android:text=\"B\">\n" +
429                "    </Button>\n" +
430                "\n" +
431                "    <Button\n" +
432                "        android:id=\"@+id/button3\"\n" +
433                "        android:layout_width=\"wrap_content\"\n" +
434                "        android:layout_height=\"wrap_content\"\n" +
435                "        android:layout_alignBottom=\"@+id/button2\"\n" +
436                "        android:layout_toRightOf=\"@+id/button2\"\n" +
437                "        android:text=\"C\">\n" +
438                "    </Button>\n" +
439                "\n" +
440                "</RelativeLayout>",
441                updated);
442        assertTrue(updated.contains(BaseViewRule.stripIdPrefix(button2.getStringAttr(ANDROID_URI,
443                ATTR_ID))));
444    }
445}
446