1package com.xtremelabs.robolectric.shadows;
2
3import android.os.Looper;
4import android.view.View;
5import android.view.ViewGroup;
6import android.widget.AdapterView;
7import android.widget.TextView;
8import com.xtremelabs.robolectric.Robolectric;
9import com.xtremelabs.robolectric.util.Transcript;
10
11import static com.xtremelabs.robolectric.Robolectric.*;
12import static com.xtremelabs.robolectric.matchers.TextViewHasTextMatcher.hasText;
13import static org.hamcrest.CoreMatchers.equalTo;
14import static org.hamcrest.CoreMatchers.is;
15import static org.hamcrest.CoreMatchers.not;
16import static org.hamcrest.CoreMatchers.nullValue;
17import static org.hamcrest.CoreMatchers.sameInstance;
18import static org.hamcrest.core.CombinableMatcher.both;
19import static org.junit.Assert.assertThat;
20
21public class AdapterViewBehavior {
22    public static void shouldActAsAdapterView(AdapterView adapterView) throws Exception {
23        Robolectric.shadowOf(Looper.getMainLooper()).pause();
24
25        testSetAdapter_ShouldCauseViewsToBeRenderedAsynchronously(adapterView);
26        testSetAdapter_ShouldSelectFirstItemAsynchronously(adapterView);
27        testSetAdapter_ShouldFireOnNothingSelectedWhenAdapterCountIsReducedToZero(adapterView);
28
29        shouldIgnoreSetSelectionCallsWithInvalidPosition(adapterView);
30        shouldOnlyUpdateOnceIfInvalidatedMultipleTimes(adapterView);
31
32        testSetEmptyView_ShouldHideAdapterViewIfAdapterIsNull(adapterView);
33        testSetEmptyView_ShouldHideAdapterViewIfAdapterViewIsEmpty(adapterView);
34        testSetEmptyView_ShouldHideEmptyViewIfAdapterViewIsNotEmpty(adapterView);
35        testSetEmptyView_ShouldHideEmptyViewWhenAdapterGetsNewItem(adapterView);
36    }
37
38    private static void shouldIgnoreSetSelectionCallsWithInvalidPosition(AdapterView adapterView) {
39        final Transcript transcript = new Transcript();
40
41        adapterView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
42            @Override
43            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
44                transcript.add("onItemSelected fired");
45            }
46
47            @Override
48            public void onNothingSelected(AdapterView<?> parent) {
49            }
50        });
51
52        ShadowHandler.idleMainLooper();
53        transcript.assertNoEventsSoFar();
54        adapterView.setSelection(AdapterView.INVALID_POSITION);
55        ShadowHandler.idleMainLooper();
56        transcript.assertNoEventsSoFar();
57    }
58
59    private static void testSetAdapter_ShouldCauseViewsToBeRenderedAsynchronously(AdapterView adapterView) throws Exception {
60        adapterView.setAdapter(new CountingAdapter(2));
61
62        assertThat(adapterView.getCount(), equalTo(2));
63        assertThat(adapterView.getChildCount(), equalTo(0));
64
65        ShadowHandler.idleMainLooper();
66        assertThat(adapterView.getChildCount(), equalTo(2));
67        assertThat((TextView) adapterView.getChildAt(0), hasText("Item 0"));
68        assertThat((TextView) adapterView.getChildAt(1), hasText("Item 1"));
69    }
70
71    private static void testSetAdapter_ShouldSelectFirstItemAsynchronously(final AdapterView adapterView) throws Exception {
72        final Transcript transcript = new Transcript();
73
74        adapterView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
75            @Override
76            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
77                assertThat(parent, sameInstance(adapterView));
78                assertThat(view, both(sameInstance(adapterView.getChildAt(position))).and(not(nullValue())));
79                assertThat(id, equalTo(adapterView.getAdapter().getItemId(position)));
80                transcript.add("selected item " + position);
81            }
82
83            @Override
84            public void onNothingSelected(AdapterView<?> parent) {
85            }
86        });
87        adapterView.setAdapter(new CountingAdapter(2));
88        transcript.assertNoEventsSoFar();
89        ShadowHandler.idleMainLooper();
90        transcript.assertEventsSoFar("selected item 0");
91    }
92
93    private static void testSetAdapter_ShouldFireOnNothingSelectedWhenAdapterCountIsReducedToZero(final AdapterView adapterView) throws Exception {
94        final Transcript transcript = new Transcript();
95
96        adapterView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
97            @Override
98            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
99            }
100
101            @Override
102            public void onNothingSelected(AdapterView<?> parent) {
103                transcript.add("onNothingSelected fired");
104            }
105        });
106        CountingAdapter adapter = new CountingAdapter(2);
107        adapterView.setAdapter(adapter);
108        ShadowHandler.idleMainLooper();
109        transcript.assertNoEventsSoFar();
110        adapter.setCount(0);
111        ShadowHandler.idleMainLooper();
112        transcript.assertEventsSoFar("onNothingSelected fired");
113    }
114
115    private static void testSetEmptyView_ShouldHideAdapterViewIfAdapterIsNull(final AdapterView adapterView) throws Exception {
116    	adapterView.setAdapter(null);
117
118    	View emptyView = new View(adapterView.getContext());
119		adapterView.setEmptyView(emptyView);
120
121		assertThat(adapterView.getVisibility(), is(View.GONE));
122		assertThat(emptyView.getVisibility(), is(View.VISIBLE));
123    }
124
125    private static void testSetEmptyView_ShouldHideAdapterViewIfAdapterViewIsEmpty(final AdapterView adapterView) throws Exception {
126    	adapterView.setAdapter(new CountingAdapter(0));
127
128    	View emptyView = new View(adapterView.getContext());
129		adapterView.setEmptyView(emptyView);
130
131		assertThat(adapterView.getVisibility(), is(View.GONE));
132		assertThat(emptyView.getVisibility(), is(View.VISIBLE));
133    }
134
135    private static void testSetEmptyView_ShouldHideEmptyViewIfAdapterViewIsNotEmpty(final AdapterView adapterView) throws Exception {
136    	adapterView.setAdapter(new CountingAdapter(1));
137
138    	View emptyView = new View(adapterView.getContext());
139		adapterView.setEmptyView(emptyView);
140
141		assertThat(adapterView.getVisibility(), is(View.VISIBLE));
142		assertThat(emptyView.getVisibility(), is(View.GONE));
143    }
144
145    private static void testSetEmptyView_ShouldHideEmptyViewWhenAdapterGetsNewItem(final AdapterView adapterView) throws Exception {
146    	CountingAdapter adapter = new CountingAdapter(0);
147		adapterView.setAdapter(adapter);
148
149    	View emptyView = new View(adapterView.getContext());
150		adapterView.setEmptyView(emptyView);
151
152		assertThat(adapterView.getVisibility(), is(View.GONE));
153		assertThat(emptyView.getVisibility(), is(View.VISIBLE));
154
155		adapter.setCount(1);
156
157		ShadowHandler.idleMainLooper();
158
159		assertThat(adapterView.getVisibility(), is(View.VISIBLE));
160		assertThat(emptyView.getVisibility(), is(View.GONE));
161    }
162
163    private static void testSetEmptyView_ShouldHideAdapterViewWhenAdapterBecomesEmpty(final AdapterView adapterView) throws Exception {
164    	CountingAdapter adapter = new CountingAdapter(1);
165		adapterView.setAdapter(adapter);
166
167    	View emptyView = new View(adapterView.getContext());
168		adapterView.setEmptyView(emptyView);
169
170		assertThat(adapterView.getVisibility(), is(View.GONE));
171		assertThat(emptyView.getVisibility(), is(View.VISIBLE));
172
173		adapter.setCount(0);
174
175		ShadowHandler.idleMainLooper();
176
177		assertThat(adapterView.getVisibility(), is(View.VISIBLE));
178		assertThat(emptyView.getVisibility(), is(View.GONE));
179    }
180
181    private static void shouldOnlyUpdateOnceIfInvalidatedMultipleTimes(final AdapterView adapterView) {
182        final Transcript transcript = new Transcript();
183        CountingAdapter adapter = new CountingAdapter(2) {
184            @Override
185            public View getView(int position, View convertView, ViewGroup parent) {
186                transcript.add("getView for " + position);
187                return super.getView(position, convertView, parent);
188            }
189        };
190        adapterView.setAdapter(adapter);
191
192        transcript.assertNoEventsSoFar();
193
194        adapter.notifyDataSetChanged();
195        adapter.notifyDataSetChanged();
196
197        ShadowHandler.idleMainLooper();
198
199        transcript.assertEventsSoFar("getView for 0", "getView for 1");
200    }
201}
202