1/*
2 * Copyright (C) 2016 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
17package android.databinding.testapp;
18
19import static org.mockito.Matchers.eq;
20import static org.mockito.Mockito.any;
21import static org.mockito.Mockito.mock;
22import static org.mockito.Mockito.never;
23import static org.mockito.Mockito.times;
24import static org.mockito.Mockito.verify;
25import static org.mockito.Mockito.verifyZeroInteractions;
26import static org.mockito.Mockito.when;
27
28import android.annotation.TargetApi;
29import android.databinding.testapp.databinding.CallbacksBinding;
30import android.databinding.testapp.vo.CallbackBindingObject;
31import android.databinding.testapp.vo.NotBindableVo;
32import android.os.Build;
33import android.support.test.runner.AndroidJUnit4;
34import android.view.View;
35import android.widget.ArrayAdapter;
36
37import org.hamcrest.CoreMatchers;
38import org.hamcrest.MatcherAssert;
39import org.junit.Before;
40import org.junit.Rule;
41import org.junit.Test;
42import org.junit.runner.RunWith;
43
44import java.util.Arrays;
45import java.util.concurrent.atomic.AtomicInteger;
46
47@RunWith(AndroidJUnit4.class)
48public class CallbackTest {
49    @Rule
50    public DataBindingTestRule<CallbacksBinding> mBindingRule = new DataBindingTestRule<>(
51            R.layout.callbacks
52    );
53
54    CallbackBindingObject mObj;
55    NotBindableVo mOther;
56    CallbacksBinding mBinding;
57
58    @Before
59    public void setup() throws Throwable {
60        mBinding = mBindingRule.getBinding();
61        mObj = mock(CallbackBindingObject.class);
62        mOther = new NotBindableVo();
63        mBinding.setObj(mObj);
64        mBinding.setOtherObj(mOther);
65        mBindingRule.executePending();
66        mBindingRule.runOnUiThread(new Runnable() {
67            @Override
68            public void run() {
69                verifyZeroInteractions(mObj);
70            }
71        });
72
73    }
74
75    @Test
76    public void testRegularClick() throws Throwable {
77        mBindingRule.runOnUiThread(new Runnable() {
78            @Override
79            public void run() {
80                mBinding.view1.performClick();
81                verify(mObj, times(1)).onClick();
82                verify(mObj, never()).onClick(any(View.class));
83                verify(mObj, never()).onClickWithParam(any(NotBindableVo.class));
84                verify(mObj, never()).onClickWithParam(any(View.class), any(NotBindableVo.class));
85            }
86        });
87    }
88
89    @Test
90    public void testClickWithCallbackArg() throws Throwable {
91        mBindingRule.runOnUiThread(new Runnable() {
92            @Override
93            public void run() {
94                mBinding.view2.performClick();
95                verify(mObj, never()).onClick();
96                verify(mObj, times(1)).onClick(mBinding.view2);
97                verify(mObj, never()).onClickWithParam(any(NotBindableVo.class));
98                verify(mObj, never()).onClickWithParam(any(View.class), any(NotBindableVo.class));
99            }
100        });
101    }
102
103    @Test
104    public void testClickWithAnotherVariableAsArg() throws Throwable {
105        mBindingRule.runOnUiThread(new Runnable() {
106            @Override
107            public void run() {
108                mBinding.view3.performClick();
109                verify(mObj, never()).onClick();
110                verify(mObj, never()).onClick(any(View.class));
111                verify(mObj, times(1)).onClickWithParam(eq(mOther));
112                verify(mObj, never()).onClickWithParam(any(View.class), any(NotBindableVo.class));
113            }
114        });
115    }
116
117    @Test
118    public void testClickWithViewAndAnotherVariableAsArgs() throws Throwable {
119        mBindingRule.runOnUiThread(new Runnable() {
120            @Override
121            public void run() {
122                mBinding.view4.performClick();
123                verify(mObj, never()).onClick();
124                verify(mObj, never()).onClick(any(View.class));
125                verify(mObj, never()).onClickWithParam(any(NotBindableVo.class));
126                verify(mObj, times(1)).onClickWithParam(mBinding.view4, mOther);
127            }
128        });
129    }
130
131    @Test
132    public void nullObjectInCallback() throws Throwable {
133        mBinding.setObj(null);
134        mBindingRule.executePending();
135        mBindingRule.runOnUiThread(new Runnable() {
136            @Override
137            public void run() {
138                mBinding.view1.performClick();
139                mBinding.view2.performClick();
140                mBinding.view3.performClick();
141                mBinding.view4.performClick();
142
143                MatcherAssert.assertThat(mBinding.view1.performLongClick(), CoreMatchers.is(false));
144                MatcherAssert.assertThat(mBinding.view2.performLongClick(), CoreMatchers.is(false));
145                MatcherAssert.assertThat(mBinding.view3.performLongClick(), CoreMatchers.is(false));
146                MatcherAssert.assertThat(mBinding.view4.performLongClick(), CoreMatchers.is(false));
147
148            }
149        });
150        verifyZeroInteractions(mObj);
151    }
152
153    // long click
154    @Test
155    public void testRegularLongClick() throws Throwable {
156        mBindingRule.runOnUiThread(new Runnable() {
157            @Override
158            public void run() {
159                when(mObj.onLongClick()).thenReturn(true);
160                MatcherAssert.assertThat(mBinding.view1.performLongClick(), CoreMatchers.is(true));
161                verify(mObj, times(1)).onLongClick();
162                verify(mObj, never()).onLongClick(any(View.class));
163                verify(mObj, never()).onLongClickWithParam(any(NotBindableVo.class));
164                verify(mObj, never()).onLongClickWithParam(any(View.class), any(NotBindableVo
165                        .class));
166            }
167        });
168    }
169
170    @Test
171    public void testLongClickWithCallbackArg() throws Throwable {
172        mBindingRule.runOnUiThread(new Runnable() {
173            @Override
174            public void run() {
175                when(mObj.onLongClick(mBinding.view2)).thenReturn(true);
176                MatcherAssert.assertThat(mBinding.view2.performLongClick(), CoreMatchers.is(true));
177                verify(mObj, never()).onLongClick();
178                verify(mObj, times(1)).onLongClick(mBinding.view2);
179                verify(mObj, never()).onLongClickWithParam(any(NotBindableVo.class));
180                verify(mObj, never()).onLongClickWithParam(any(View.class), any(NotBindableVo
181                        .class));
182            }
183        });
184    }
185
186    @Test
187    public void testLongClickWithAnotherVariableAsArg() throws Throwable {
188        mBindingRule.runOnUiThread(new Runnable() {
189            @Override
190            public void run() {
191                when(mObj.onLongClickWithParam(mOther)).thenReturn(true);
192                MatcherAssert.assertThat(mBinding.view3.performLongClick(), CoreMatchers.is(true));
193                verify(mObj, never()).onLongClick();
194                verify(mObj, never()).onLongClick(any(View.class));
195                verify(mObj, times(1)).onLongClickWithParam(mOther);
196                verify(mObj, never()).onLongClickWithParam(any(View.class), any(NotBindableVo
197                        .class));
198            }
199        });
200    }
201
202    @Test
203    public void testLongClickWithViewAndAnotherVariableAsArgs() throws Throwable {
204        mBindingRule.runOnUiThread(new Runnable() {
205            @Override
206            public void run() {
207                when(mObj.onLongClickWithParam(mBinding.view4, mOther)).thenReturn(true);
208                MatcherAssert.assertThat(mBinding.view4.performLongClick(), CoreMatchers.is(true));
209                verify(mObj, never()).onLongClick();
210                verify(mObj, never()).onLongClick(any(View.class));
211                verify(mObj, never()).onLongClickWithParam(any(NotBindableVo.class));
212                verify(mObj, times(1)).onLongClickWithParam(mBinding.view4, mOther);
213            }
214        });
215    }
216
217    @Test
218    public void testListViewOnScroll() throws Throwable {
219        final CallbackBindingObject obj2 = mock(CallbackBindingObject.class);
220        mBinding.setObj2(obj2);
221        mBindingRule.executePending();
222        mBindingRule.runOnUiThread(new Runnable() {
223            @Override
224            public void run() {
225                // this is going to trigger scroll
226                mBinding.listView.setAdapter(new ArrayAdapter<>(mBinding.listView.getContext(),
227                        android.R.layout.simple_list_item_1, Arrays.asList("a", "b")));
228            }
229        });
230        mBindingRule.runOnUiThread(new Runnable() {
231            @TargetApi(Build.VERSION_CODES.KITKAT)
232            @Override
233            public void run() {
234                // setting listener also calls the callback
235                verify(obj2).onScrolled();
236            }
237        });
238    }
239
240    @Test
241    public void testProgressChange() throws Throwable {
242        mBindingRule.runOnUiThread(new Runnable() {
243            @Override
244            public void run() {
245                mBinding.seekBar.setProgress(20);
246                verify(mObj, times(1)).onProgressChanged(mBinding.seekBar, 20, false);
247            }
248        });
249    }
250
251    @Test
252    public void testStaticCallViaClass() throws Throwable {
253        staticCall(mBinding.view5);
254    }
255
256    @Test
257    public void testStaticCallViaInstance() throws Throwable {
258        staticCall(mBinding.view6);
259    }
260
261    @Test
262    public void testVariableOverride() throws Throwable {
263        mBindingRule.runOnUiThread(new Runnable() {
264            @Override
265            public void run() {
266                mBinding.view8.performClick();
267                verify(mObj).onClick(mBinding.view8);
268            }
269        });
270    }
271
272    @Test
273    public void testArrayAccess() throws Throwable {
274        final CallbackBindingObject[] objects = new CallbackBindingObject[] {
275                mock(CallbackBindingObject.class),
276                mock(CallbackBindingObject.class),
277                mock(CallbackBindingObject.class),
278        };
279        mBinding.setObjArr(objects);
280        mBindingRule.executePending();
281        mBindingRule.runOnUiThread(new Runnable() {
282            @Override
283            public void run() {
284                verifyZeroInteractions(objects);
285                mBinding.view7.performClick();
286                verify(objects[1]).onClick(mBinding.view7);
287                mBinding.view7.performLongClick();
288                verify(objects[2]).onLongClick(mBinding.view7);
289                verifyZeroInteractions(objects[0]);
290            }
291        });
292    }
293
294    @Test
295    public void testStaticVariableFullPackage() throws Throwable {
296        mBindingRule.runOnUiThread(new Runnable() {
297            @Override
298            public void run() {
299                mBinding.view9.performClick();
300                verify(mObj).setVisible(View.VISIBLE);
301            }
302        });
303    }
304
305    @Test
306    public void testStaticVariableImported() throws Throwable {
307        mBindingRule.runOnUiThread(new Runnable() {
308            @Override
309            public void run() {
310                mBinding.view10.performClick();
311                verify(mObj).setVisible(NotBindableVo.STATIC_VAL);
312            }
313        });
314    }
315
316    @Test
317    public void testTernary1() throws Throwable {
318        mBindingRule.runOnUiThread(new Runnable() {
319            @Override
320            public void run() {
321                mBinding.view11.setFocusable(false);
322                mBinding.view11.performClick();
323                verify(mObj).onNotFocusable();
324                verify(mObj, never()).onFocusable();
325            }
326        });
327    }
328
329    @Test
330    public void testTernary2() throws Throwable {
331        mBindingRule.runOnUiThread(new Runnable() {
332            @Override
333            public void run() {
334                mBinding.view11.setFocusable(true);
335                mBinding.view11.performClick();
336                verify(mObj).onFocusable();
337                verify(mObj, never()).onNotFocusable();
338            }
339        });
340    }
341
342    @Test
343    public void testTernary3() throws Throwable {
344        mBindingRule.runOnUiThread(new Runnable() {
345            @Override
346            public void run() {
347                mBinding.view11.setFocusable(false);
348                when(mObj.onFocusable()).thenReturn(true, false);
349                when(mObj.onNotFocusable()).thenReturn(false, true);
350                MatcherAssert.assertThat(mBinding.view11.performLongClick(), CoreMatchers.is(false));
351                MatcherAssert.assertThat(mBinding.view11.performLongClick(), CoreMatchers.is(true));
352                mBinding.view11.setFocusable(true);
353                MatcherAssert.assertThat(mBinding.view11.performLongClick(), CoreMatchers.is(true));
354                MatcherAssert.assertThat(mBinding.view11.performLongClick(), CoreMatchers.is(false));
355            }
356        });
357    }
358
359    @Test
360    public void testTernary4() throws Throwable {
361        mBindingRule.runOnUiThread(new Runnable() {
362            @Override
363            public void run() {
364                mBinding.view11.setFocusable(true);
365                mBinding.view11.performClick();
366                verify(mObj).onFocusable();
367                verify(mObj, never()).onNotFocusable();
368            }
369        });
370    }
371
372    private void staticCall(final View view) throws Throwable {
373        final AtomicInteger counter = NotBindableVo.sStaticCounter;
374        final int start = counter.get();
375        mBindingRule.runOnUiThread(new Runnable() {
376            @Override
377            public void run() {
378                view.performClick();
379                MatcherAssert.assertThat(counter.get(), CoreMatchers.is(start + 1));
380                MatcherAssert.assertThat(view.performLongClick(), CoreMatchers.is(true));
381                MatcherAssert.assertThat(counter.get(), CoreMatchers.is(start + 2));
382            }
383        });
384    }
385}
386