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
17package com.android.messaging.ui.conversation;
18
19import android.app.Activity;
20import android.app.Fragment;
21import android.database.Cursor;
22import android.support.v7.widget.RecyclerView;
23import android.test.suitebuilder.annotation.LargeTest;
24
25import com.android.messaging.FakeFactory;
26import com.android.messaging.R;
27import com.android.messaging.datamodel.DataModel;
28import com.android.messaging.datamodel.MemoryCacheManager;
29import com.android.messaging.datamodel.data.ConversationData;
30import com.android.messaging.datamodel.data.ConversationData.ConversationDataListener;
31import com.android.messaging.datamodel.data.DraftMessageData;
32import com.android.messaging.datamodel.data.TestDataFactory;
33import com.android.messaging.datamodel.media.MediaResourceManager;
34import com.android.messaging.ui.FragmentTestCase;
35import com.android.messaging.ui.PlainTextEditText;
36import com.android.messaging.ui.TestActivity.FragmentEventListener;
37import com.android.messaging.ui.conversation.ConversationFragment.ConversationFragmentHost;
38import com.android.messaging.ui.conversationlist.ConversationListFragment;
39import com.android.messaging.util.BugleGservices;
40import com.android.messaging.util.ImeUtil;
41
42import org.mockito.Matchers;
43import org.mockito.Mock;
44import org.mockito.Mockito;
45
46
47/**
48 * Unit tests for {@link ConversationListFragment}.
49 */
50@LargeTest
51public class ConversationFragmentTest extends FragmentTestCase<ConversationFragment> {
52
53    @Mock protected DataModel mockDataModel;
54    @Mock protected ConversationData mockConversationData;
55    @Mock protected DraftMessageData mockDraftMessageData;
56    @Mock protected MediaResourceManager mockMediaResourceManager;
57    @Mock protected BugleGservices mockBugleGservices;
58    @Mock protected ConversationFragmentHost mockHost;
59    @Mock protected MemoryCacheManager mockMemoryCacheManager;
60
61    private ImeUtil mSpiedImeUtil;
62
63    private static final String CONVERSATION_ID = "cid";
64
65
66    public ConversationFragmentTest() {
67        super(ConversationFragment.class);
68    }
69
70    @Override
71    protected void setUp() throws Exception {
72      super.setUp();
73      ImeUtil.clearInstance();
74      mSpiedImeUtil = Mockito.spy(new ImeUtil());
75      FakeFactory.register(this.getInstrumentation().getTargetContext())
76          .withDataModel(mockDataModel)
77          .withBugleGservices(mockBugleGservices)
78          .withMemoryCacheManager(mockMemoryCacheManager);
79    }
80
81    /**
82     * Helper that will do the 'binding' of ConversationFragmentTest with ConversationData and
83     * leave fragment in 'ready' state.
84     * @param cursor
85     */
86    private void loadWith(final Cursor cursor) {
87        Mockito.when(mockDraftMessageData.isBound(Matchers.anyString()))
88            .thenReturn(true);
89        Mockito.when(mockConversationData.isBound(Matchers.anyString()))
90            .thenReturn(true);
91        Mockito.doReturn(mockDraftMessageData)
92            .when(mockDataModel)
93            .createDraftMessageData(Mockito.anyString());
94        Mockito.when(mockDataModel.createConversationData(
95                Matchers.any(Activity.class),
96                Matchers.any(ConversationDataListener.class),
97                Matchers.anyString()))
98            .thenReturn(mockConversationData);
99
100        // Create fragment synchronously to avoid need for volatile, synchronization etc.
101        final ConversationFragment fragment = getFragment();
102        // Binding to model happens when attaching fragment to activity, so hook into test
103        // activity to do so.
104        getActivity().setFragmentEventListener(new FragmentEventListener() {
105            @Override
106            public void onAttachFragment(final Fragment attachedFragment) {
107                if (fragment == attachedFragment) {
108                    fragment.setConversationInfo(getActivity(), CONVERSATION_ID, null);
109                }
110            }
111        });
112
113        getActivity().runOnUiThread(new Runnable() {
114            @Override
115            public void run() {
116                fragment.setHost(mockHost);
117                getActivity().setFragment(fragment);
118                Mockito.verify(mockDataModel).createConversationData(
119                        getActivity(), fragment, CONVERSATION_ID);
120                Mockito.verify(mockConversationData).init(fragment.getLoaderManager(),
121                        fragment.mBinding);
122            }
123        });
124        // Wait for initial layout pass to work around crash in recycler view
125        getInstrumentation().waitForIdleSync();
126        // Now load the cursor
127        getActivity().runOnUiThread(new Runnable() {
128            @Override
129            public void run() {
130                fragment.onConversationMessagesCursorUpdated(mockConversationData, cursor, null,
131                        false);
132            }
133        });
134        getInstrumentation().waitForIdleSync();
135    }
136
137    /**
138     * Verifies that list view gets correctly populated given a cursor.
139     */
140    public void testLoadListView() {
141        final Cursor cursor = TestDataFactory.getConversationMessageCursor();
142        loadWith(cursor);
143        final RecyclerView listView =
144                (RecyclerView) getFragment().getView().findViewById(android.R.id.list);
145        assertEquals("bad cursor", cursor.getCount(), listView.getAdapter().getItemCount());
146        assertEquals("bad cursor count", cursor.getCount(), listView.getChildCount());
147    }
148
149    public void testClickComposeMessageView() {
150        final Cursor cursor = TestDataFactory.getConversationMessageCursor();
151        loadWith(cursor);
152
153        final PlainTextEditText composeEditText = (PlainTextEditText) getFragment().getView()
154                .findViewById(R.id.compose_message_text);
155        setFocus(composeEditText, false);
156        Mockito.verify(mockHost, Mockito.never()).onStartComposeMessage();
157        setFocus(composeEditText, true);
158        Mockito.verify(mockHost).onStartComposeMessage();
159    }
160}
161