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.attachmentchooser;
18
19import android.app.Fragment;
20import android.test.suitebuilder.annotation.LargeTest;
21import android.widget.CheckBox;
22
23import com.android.messaging.FakeFactory;
24import com.android.messaging.R;
25import com.android.messaging.datamodel.DataModel;
26import com.android.messaging.datamodel.data.DraftMessageData;
27import com.android.messaging.datamodel.data.MessageData;
28import com.android.messaging.datamodel.data.MessagePartData;
29import com.android.messaging.datamodel.data.TestDataFactory;
30import com.android.messaging.ui.FragmentTestCase;
31import com.android.messaging.ui.TestActivity;
32import com.android.messaging.ui.TestActivity.FragmentEventListener;
33import com.android.messaging.ui.attachmentchooser.AttachmentChooserFragment;
34import com.android.messaging.ui.attachmentchooser.AttachmentGridItemView;
35import com.android.messaging.ui.attachmentchooser.AttachmentGridView;
36import com.android.messaging.ui.attachmentchooser.AttachmentChooserFragment.AttachmentChooserFragmentHost;
37import com.android.messaging.ui.conversationlist.ConversationListFragment;
38
39import org.mockito.Matchers;
40import org.mockito.Mock;
41import org.mockito.Mockito;
42import org.mockito.compat.ArgumentMatcher;
43
44import java.util.Arrays;
45import java.util.HashSet;
46import java.util.List;
47import java.util.Set;
48
49
50/**
51 * Unit tests for {@link ConversationListFragment}.
52 */
53@LargeTest
54public class AttachmentChooserFragmentTest extends FragmentTestCase<AttachmentChooserFragment> {
55
56    @Mock protected DataModel mockDataModel;
57    @Mock protected DraftMessageData mockDraftMessageData;
58    @Mock protected AttachmentChooserFragmentHost mockHost;
59
60    private static final String CONVERSATION_ID = "cid";
61
62    /** A custom argument matcher that checks whether the set argument passed in is a set
63     * with identical attachment data as the given set.
64     */
65    private class IsSetOfGivenAttachments extends ArgumentMatcher<Set<MessagePartData>> {
66        private final Set<MessagePartData> mGivenParts;
67        public IsSetOfGivenAttachments(final Set<MessagePartData> givenParts) {
68            mGivenParts = givenParts;
69        }
70
71        @Override
72        public boolean matchesObject(final Object set) {
73            @SuppressWarnings("unchecked")
74            final Set<MessagePartData> actualSet = (Set<MessagePartData>) set;
75            if (actualSet.size() != mGivenParts.size()) {
76                return false;
77            }
78            return mGivenParts.containsAll(actualSet) && actualSet.containsAll(mGivenParts);
79        }
80     }
81
82    public AttachmentChooserFragmentTest() {
83        super(AttachmentChooserFragment.class);
84    }
85
86    @Override
87    protected void setUp() throws Exception {
88        super.setUp();
89        FakeFactory.register(this.getInstrumentation().getTargetContext())
90            .withDataModel(mockDataModel);
91    }
92
93    private void loadWith(final List<MessagePartData> attachments) {
94        Mockito.when(mockDraftMessageData.isBound(Matchers.anyString()))
95            .thenReturn(true);
96        Mockito.doReturn(mockDraftMessageData)
97            .when(mockDataModel)
98            .createDraftMessageData(Mockito.anyString());
99        Mockito.doReturn(attachments)
100            .when(mockDraftMessageData)
101            .getReadOnlyAttachments();
102        Mockito.when(mockDataModel.createDraftMessageData(
103                Matchers.anyString()))
104            .thenReturn(mockDraftMessageData);
105
106        // Create fragment synchronously to avoid need for volatile, synchronization etc.
107        final AttachmentChooserFragment fragment = getFragment();
108        // Binding to model happens when attaching fragment to activity, so hook into test
109        // activity to do so.
110        getActivity().setFragmentEventListener(new FragmentEventListener() {
111            @Override
112            public void onAttachFragment(final Fragment attachedFragment) {
113                if (fragment == attachedFragment) {
114                    fragment.setConversationId(CONVERSATION_ID);
115                }
116            }
117        });
118
119        getActivity().runOnUiThread(new Runnable() {
120            @Override
121            public void run() {
122                fragment.setHost(mockHost);
123                getActivity().setFragment(fragment);
124                Mockito.verify(mockDataModel).createDraftMessageData(
125                        Mockito.matches(CONVERSATION_ID));
126                Mockito.verify(mockDraftMessageData).loadFromStorage(
127                        Matchers.eq(fragment.mBinding), Matchers.eq((MessageData) null),
128                        Matchers.eq(false));
129            }
130        });
131        // Now load the cursor
132        getActivity().runOnUiThread(new Runnable() {
133            @Override
134            public void run() {
135                fragment.onDraftChanged(mockDraftMessageData, DraftMessageData.ALL_CHANGED);
136            }
137        });
138        getInstrumentation().waitForIdleSync();
139    }
140
141    public void testUnselect() {
142        final List<MessagePartData> attachments = TestDataFactory.getTestDraftAttachments();
143        loadWith(attachments);
144        final AttachmentGridView attachmentGridView = (AttachmentGridView)
145                getFragment().getView().findViewById(R.id.grid);
146        assertEquals("bad view count", attachments.size(),
147                attachmentGridView.getAdapter().getCount());
148
149        final AttachmentGridItemView itemView = (AttachmentGridItemView)
150                attachmentGridView.getChildAt(0);
151        assertEquals(attachmentGridView, itemView.testGetHostInterface());
152        final CheckBox checkBox = (CheckBox) itemView.findViewById(R.id.checkbox);
153        assertEquals(true, checkBox.isChecked());
154        assertEquals(true, attachmentGridView.isItemSelected(itemView.mAttachmentData));
155        clickButton(checkBox);
156        assertEquals(false, checkBox.isChecked());
157        assertEquals(false, attachmentGridView.isItemSelected(itemView.mAttachmentData));
158
159        final AttachmentGridItemView itemView2 = (AttachmentGridItemView)
160                attachmentGridView.getChildAt(1);
161        final CheckBox checkBox2 = (CheckBox) itemView2.findViewById(R.id.checkbox);
162        clickButton(checkBox2);
163
164        getFragment().confirmSelection();
165        final MessagePartData[] attachmentsToRemove = new MessagePartData[] {
166                itemView.mAttachmentData, itemView2.mAttachmentData };
167        Mockito.verify(mockDraftMessageData).removeExistingAttachments(Matchers.argThat(
168                new IsSetOfGivenAttachments(new HashSet<>(Arrays.asList(attachmentsToRemove)))));
169        Mockito.verify(mockDraftMessageData).saveToStorage(Matchers.eq(getFragment().mBinding));
170        Mockito.verify(mockHost).onConfirmSelection();
171    }
172}
173