1package com.xtremelabs.robolectric.shadows;
2
3import android.app.Application;
4import android.view.View;
5import android.view.ViewGroup;
6import android.view.animation.Animation;
7import android.view.animation.Animation.AnimationListener;
8import android.widget.FrameLayout;
9import android.widget.LinearLayout;
10import com.xtremelabs.robolectric.R;
11import com.xtremelabs.robolectric.Robolectric;
12import com.xtremelabs.robolectric.WithTestDefaultsRunner;
13import com.xtremelabs.robolectric.res.ResourceLoader;
14import org.junit.After;
15import org.junit.Before;
16import org.junit.Test;
17import org.junit.runner.RunWith;
18
19import java.io.ByteArrayOutputStream;
20import java.io.PrintStream;
21
22import static com.xtremelabs.robolectric.Robolectric.shadowOf;
23import static org.hamcrest.CoreMatchers.equalTo;
24import static org.hamcrest.CoreMatchers.sameInstance;
25import static org.hamcrest.MatcherAssert.assertThat;
26import static org.hamcrest.core.IsNull.nullValue;
27import static org.junit.Assert.*;
28
29@RunWith(WithTestDefaultsRunner.class)
30public class ViewGroupTest {
31    private String defaultLineSeparator;
32    private ViewGroup root;
33    private View child1;
34    private View child2;
35    private ViewGroup child3;
36    private View child3a;
37    private View child3b;
38    private Application context;
39
40    @Before
41    public void setUp() throws Exception {
42        context = new Application();
43        ShadowApplication.bind(context, new ResourceLoader(10, R.class, null, null));
44
45        root = new FrameLayout(context);
46
47        child1 = new View(context);
48        child2 = new View(context);
49        child3 = new FrameLayout(context);
50        child3a = new View(context);
51        child3b = new View(context);
52
53        root.addView(child1);
54        root.addView(child2);
55        root.addView(child3);
56
57        child3.addView(child3a);
58        child3.addView(child3b);
59
60        defaultLineSeparator = System.getProperty("line.separator");
61        System.setProperty("line.separator", "\n");
62    }
63
64    @After
65    public void tearDown() throws Exception {
66        System.setProperty("line.separator", defaultLineSeparator);
67    }
68
69    @Test
70    public void testLayoutAnimationListener() {
71        assertThat(root.getLayoutAnimationListener(), nullValue());
72
73        AnimationListener animationListener = new AnimationListener() {
74            @Override
75            public void onAnimationEnd(Animation a) { }
76
77            @Override
78            public void onAnimationRepeat(Animation a) { }
79
80            @Override
81            public void onAnimationStart(Animation a) { }
82        };
83        root.setLayoutAnimationListener(animationListener);
84
85        assertThat(root.getLayoutAnimationListener(), sameInstance(animationListener));
86    }
87
88    @Test
89    public void testRemoveChildAt() throws Exception {
90        root.removeViewAt(1);
91
92        assertThat(root.getChildCount(), equalTo(2));
93        assertThat(root.getChildAt(0), sameInstance(child1));
94        assertThat(root.getChildAt(1), sameInstance((View) child3));
95
96        assertThat(child2.getParent(), nullValue());
97    }
98
99    @Test
100    public void testAddViewAt() throws Exception {
101        root.removeAllViews();
102        root.addView(child1);
103        root.addView(child2);
104        root.addView(child3, 1);
105        assertThat(root.getChildAt(0), sameInstance(child1));
106        assertThat(root.getChildAt(1), sameInstance((View) child3));
107        assertThat(root.getChildAt(2), sameInstance(child2));
108    }
109
110    @Test
111    public void shouldfindViewWithTag() {
112        root.removeAllViews();
113        child1.setTag("tag1");
114        child2.setTag("tag2");
115        child3.setTag("tag3");
116        root.addView(child1);
117        root.addView(child2);
118        root.addView(child3, 1);
119        assertThat(root.findViewWithTag("tag1"), sameInstance(child1));
120        assertThat(root.findViewWithTag("tag2"), sameInstance(child2));
121        assertThat((ViewGroup) root.findViewWithTag("tag3"), sameInstance(child3));
122    }
123
124    @Test
125    public void shouldNotfindViewWithTagReturnNull() {
126        root.removeAllViews();
127        child1.setTag("tag1");
128        child2.setTag("tag2");
129        child3.setTag("tag3");
130        root.addView(child1);
131        root.addView(child2);
132        root.addView(child3, 1);
133        assertThat(root.findViewWithTag("tag21"), equalTo(null));
134        assertThat((ViewGroup) root.findViewWithTag("tag23"), equalTo(null));
135    }
136
137    @Test
138    public void shouldfindViewWithTagFromCorrectViewGroup() {
139        root.removeAllViews();
140        child1.setTag("tag1");
141        child2.setTag("tag2");
142        child3.setTag("tag3");
143        root.addView(child1);
144        root.addView(child2);
145        root.addView(child3);
146
147        child3a.setTag("tag1");
148        child3b.setTag("tag2");
149
150        //can find views by tag from root
151        assertThat(root.findViewWithTag("tag1"), sameInstance(child1));
152        assertThat(root.findViewWithTag("tag2"), sameInstance(child2));
153        assertThat((ViewGroup) root.findViewWithTag("tag3"), sameInstance(child3));
154
155        //can find views by tag from child3
156        assertThat(child3.findViewWithTag("tag1"), sameInstance(child3a));
157        assertThat(child3.findViewWithTag("tag2"), sameInstance(child3b));
158    }
159
160    @Test
161    public void shouldFindViewWithTag_whenViewGroupOverridesGetTag() throws Exception {
162        ViewGroup viewGroup = new LinearLayout(Robolectric.application) {
163            @Override
164            public Object getTag() {
165                return "blarg";
166            }
167        };
168        assertThat((ViewGroup) viewGroup.findViewWithTag("blarg"), sameInstance(viewGroup));
169    }
170
171    @Test
172    public void hasFocus_shouldReturnTrueIfAnyChildHasFocus() throws Exception {
173        assertFalse(root.hasFocus());
174
175        child1.requestFocus();
176        assertTrue(root.hasFocus());
177
178        child1.clearFocus();
179        assertFalse(root.hasFocus());
180
181        child3b.requestFocus();
182        assertTrue(root.hasFocus());
183
184        child3b.clearFocus();
185        assertFalse(root.hasFocus());
186
187        root.requestFocus();
188        assertTrue(root.hasFocus());
189    }
190
191    @Test
192    public void clearFocus_shouldRecursivelyClearTheFocusOfAllChildren() throws Exception {
193        child3a.requestFocus();
194
195        root.clearFocus();
196
197        assertFalse(child3a.hasFocus());
198        assertFalse(child3.hasFocus());
199        assertFalse(root.hasFocus());
200
201        root.requestFocus();
202        root.clearFocus();
203        assertFalse(root.hasFocus());
204    }
205
206    @Test
207    public void findFocus_shouldRecursivelyFindTheViewWithFocus() {
208        child3a.requestFocus();
209
210        assertSame(child3a, root.findFocus());
211    }
212
213    @Test
214    public void findFocus_shouldReturnThisBeforeChildrenWithFocus() {
215        child3a.requestFocus();
216        child3.requestFocus();
217
218        assertSame(child3, root.findFocus());
219    }
220
221    @Test
222    public void dump_shouldDumpStructure() throws Exception {
223        child3.setId(R.id.snippet_text);
224
225        ByteArrayOutputStream out = new ByteArrayOutputStream();
226        shadowOf(root).dump(new PrintStream(out), 0);
227        assertEquals("<FrameLayout>\n" +
228                "  <View/>\n" +
229                "  <View/>\n" +
230                "  <FrameLayout id=\"id/snippet_text\">\n" +
231                "    <View/>\n" +
232                "    <View/>\n" +
233                "  </FrameLayout>\n" +
234                "</FrameLayout>\n", out.toString());
235    }
236
237    @Test
238    public void testRemoveView() {
239        root.removeView(new View(context));
240        assertThat(root.getChildCount(), equalTo(3));
241
242        root.removeView(child2);
243        assertThat(root.getChildCount(), equalTo(2));
244        assertThat(root.getChildAt(0), sameInstance(child1));
245        assertThat(root.getChildAt(1), sameInstance((View) child3));
246
247        root.removeView(child2);
248        assertThat(root.getChildCount(), equalTo(2));
249        assertThat(root.getChildAt(0), sameInstance(child1));
250        assertThat(root.getChildAt(1), sameInstance((View) child3));
251
252        root.removeView(child1);
253        root.removeView(child3);
254        assertThat(root.getChildCount(), equalTo(0));
255    }
256
257    @Test
258    public void testRemoveViewInLayout() {
259        root.removeViewInLayout(new View(context));
260        assertThat(root.getChildCount(), equalTo(3));
261
262        root.removeViewInLayout(child2);
263        assertThat(root.getChildCount(), equalTo(2));
264        assertThat(root.getChildAt(0), sameInstance(child1));
265        assertThat(root.getChildAt(1), sameInstance((View) child3));
266
267        root.removeViewInLayout(child2);
268        assertThat(root.getChildCount(), equalTo(2));
269        assertThat(root.getChildAt(0), sameInstance(child1));
270        assertThat(root.getChildAt(1), sameInstance((View) child3));
271
272        root.removeViewInLayout(child1);
273        root.removeViewInLayout(child3);
274        assertThat(root.getChildCount(), equalTo(0));
275    }
276
277    @Test
278    public void testRemoveViews() {
279        root.removeViews(0, 0);
280        assertThat(root.getChildCount(), equalTo(3));
281
282        root.removeViews(2, 1);
283        assertThat(root.getChildCount(), equalTo(2));
284        assertThat(root.getChildAt(0), sameInstance(child1));
285        assertThat(root.getChildAt(1), sameInstance(child2));
286
287        root.removeViews(0, 1);
288        assertThat(root.getChildCount(), equalTo(1));
289        assertThat(root.getChildAt(0), sameInstance(child2));
290
291        root.removeViews(0, 1);
292        assertThat(root.getChildCount(), equalTo(0));
293
294        root.addView(child1);
295        root.addView(child2);
296        root.addView(child3);
297
298        root.removeViews(1, 1);
299        assertThat(root.getChildCount(), equalTo(2));
300        assertThat(root.getChildAt(0), sameInstance(child1));
301        assertThat(root.getChildAt(1), sameInstance((View) child3));
302
303        root.removeViews(0, 2);
304        assertThat(root.getChildCount(), equalTo(0));
305    }
306
307    @Test
308    public void testRemoveViewsInLayout() {
309        root.removeViewsInLayout(0, 0);
310        assertThat(root.getChildCount(), equalTo(3));
311
312        root.removeViewsInLayout(2, 1);
313        assertThat(root.getChildCount(), equalTo(2));
314        assertThat(root.getChildAt(0), sameInstance(child1));
315        assertThat(root.getChildAt(1), sameInstance(child2));
316
317        root.removeViewsInLayout(0, 1);
318        assertThat(root.getChildCount(), equalTo(1));
319        assertThat(root.getChildAt(0), sameInstance(child2));
320
321        root.removeViewsInLayout(0, 1);
322        assertThat(root.getChildCount(), equalTo(0));
323
324        root.addView(child1);
325        root.addView(child2);
326        root.addView(child3);
327
328        root.removeViewsInLayout(1, 1);
329        assertThat(root.getChildCount(), equalTo(2));
330        assertThat(root.getChildAt(0), sameInstance(child1));
331        assertThat(root.getChildAt(1), sameInstance((View) child3));
332
333        root.removeViewsInLayout(0, 2);
334        assertThat(root.getChildCount(), equalTo(0));
335    }
336}
337