1 /*
2  * Copyright (C) 2011 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 
17 package com.android.dialer.calllog;
18 
19 import static com.google.common.collect.Lists.newArrayList;
20 
21 import android.database.MatrixCursor;
22 import android.provider.CallLog.Calls;
23 import android.test.AndroidTestCase;
24 import android.test.suitebuilder.annotation.SmallTest;
25 
26 import java.util.List;
27 
28 /**
29  * Unit tests for {@link CallLogGroupBuilder}
30  */
31 @SmallTest
32 public class CallLogGroupBuilderTest extends AndroidTestCase {
33     /** A phone number for testing. */
34     private static final String TEST_NUMBER1 = "14125551234";
35     /** A phone number for testing. */
36     private static final String TEST_NUMBER2 = "14125555555";
37 
38     /** The object under test. */
39     private CallLogGroupBuilder mBuilder;
40     /** Records the created groups. */
41     private FakeGroupCreator mFakeGroupCreator;
42     /** Cursor to store the values. */
43     private MatrixCursor mCursor;
44 
45     @Override
setUp()46     protected void setUp() throws Exception {
47         super.setUp();
48         mFakeGroupCreator = new FakeGroupCreator();
49         mBuilder = new CallLogGroupBuilder(mFakeGroupCreator);
50         createCursor();
51     }
52 
53     @Override
tearDown()54     protected void tearDown() throws Exception {
55         mCursor = null;
56         mBuilder = null;
57         mFakeGroupCreator = null;
58         super.tearDown();
59     }
60 
testAddGroups_NoCalls()61     public void testAddGroups_NoCalls() {
62         mBuilder.addGroups(mCursor);
63         assertEquals(0, mFakeGroupCreator.groups.size());
64     }
65 
testAddGroups_OneCall()66     public void testAddGroups_OneCall() {
67         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
68         mBuilder.addGroups(mCursor);
69         assertEquals(0, mFakeGroupCreator.groups.size());
70     }
71 
testAddGroups_TwoCallsNotMatching()72     public void testAddGroups_TwoCallsNotMatching() {
73         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
74         addCallLogEntry(TEST_NUMBER2, Calls.INCOMING_TYPE);
75         mBuilder.addGroups(mCursor);
76         assertEquals(0, mFakeGroupCreator.groups.size());
77     }
78 
testAddGroups_ThreeCallsMatching()79     public void testAddGroups_ThreeCallsMatching() {
80         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
81         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
82         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
83         mBuilder.addGroups(mCursor);
84         assertEquals(1, mFakeGroupCreator.groups.size());
85         assertGroupIs(0, 3, false, mFakeGroupCreator.groups.get(0));
86     }
87 
testAddGroups_MatchingIncomingAndOutgoing()88     public void testAddGroups_MatchingIncomingAndOutgoing() {
89         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
90         addCallLogEntry(TEST_NUMBER1, Calls.OUTGOING_TYPE);
91         addCallLogEntry(TEST_NUMBER1, Calls.INCOMING_TYPE);
92         mBuilder.addGroups(mCursor);
93         assertEquals(1, mFakeGroupCreator.groups.size());
94         assertGroupIs(0, 3, false, mFakeGroupCreator.groups.get(0));
95     }
96 
testAddGroups_Voicemail()97     public void testAddGroups_Voicemail() {
98         // Does not group with other types of calls, include voicemail themselves.
99         assertCallsAreNotGrouped(Calls.VOICEMAIL_TYPE, Calls.MISSED_TYPE);
100         //assertCallsAreNotGrouped(Calls.VOICEMAIL_TYPE, Calls.MISSED_TYPE, Calls.MISSED_TYPE);
101         assertCallsAreNotGrouped(Calls.VOICEMAIL_TYPE, Calls.VOICEMAIL_TYPE);
102         assertCallsAreNotGrouped(Calls.VOICEMAIL_TYPE, Calls.INCOMING_TYPE);
103         assertCallsAreNotGrouped(Calls.VOICEMAIL_TYPE, Calls.OUTGOING_TYPE);
104     }
105 
testAddGroups_Missed()106     public void testAddGroups_Missed() {
107         // Groups with one or more missed calls.
108         assertCallsAreGrouped(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
109         assertCallsAreGrouped(Calls.MISSED_TYPE, Calls.MISSED_TYPE, Calls.MISSED_TYPE);
110         // Does not group with other types of calls.
111         assertCallsAreNotGrouped(Calls.MISSED_TYPE, Calls.VOICEMAIL_TYPE);
112         assertCallsAreGrouped(Calls.MISSED_TYPE, Calls.INCOMING_TYPE);
113         assertCallsAreGrouped(Calls.MISSED_TYPE, Calls.OUTGOING_TYPE);
114     }
115 
testAddGroups_Incoming()116     public void testAddGroups_Incoming() {
117         // Groups with one or more incoming or outgoing.
118         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.INCOMING_TYPE);
119         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
120         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
121         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE, Calls.INCOMING_TYPE);
122         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.MISSED_TYPE);
123         // Does not group with voicemail and missed calls.
124         assertCallsAreNotGrouped(Calls.INCOMING_TYPE, Calls.VOICEMAIL_TYPE);
125     }
126 
testAddGroups_Outgoing()127     public void testAddGroups_Outgoing() {
128         // Groups with one or more incoming or outgoing.
129         assertCallsAreGrouped(Calls.OUTGOING_TYPE, Calls.INCOMING_TYPE);
130         assertCallsAreGrouped(Calls.OUTGOING_TYPE, Calls.OUTGOING_TYPE);
131         assertCallsAreGrouped(Calls.OUTGOING_TYPE, Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
132         assertCallsAreGrouped(Calls.OUTGOING_TYPE, Calls.OUTGOING_TYPE, Calls.INCOMING_TYPE);
133         assertCallsAreGrouped(Calls.INCOMING_TYPE, Calls.MISSED_TYPE);
134         // Does not group with voicemail and missed calls.
135         assertCallsAreNotGrouped(Calls.INCOMING_TYPE, Calls.VOICEMAIL_TYPE);
136     }
137 
testAddGroups_Mixed()138     public void testAddGroups_Mixed() {
139         addMultipleCallLogEntries(TEST_NUMBER1,
140                 Calls.VOICEMAIL_TYPE,  // Stand-alone
141                 Calls.INCOMING_TYPE,  // Group 1: 1-4
142                 Calls.OUTGOING_TYPE,
143                 Calls.MISSED_TYPE,
144                 Calls.MISSED_TYPE,
145                 Calls.VOICEMAIL_TYPE,  // Stand-alone
146                 Calls.INCOMING_TYPE,  // Stand-alone
147                 Calls.VOICEMAIL_TYPE,  // Stand-alone
148                 Calls.MISSED_TYPE, // Group 2: 8-10
149                 Calls.MISSED_TYPE,
150                 Calls.OUTGOING_TYPE);
151         mBuilder.addGroups(mCursor);
152         assertEquals(2, mFakeGroupCreator.groups.size());
153         assertGroupIs(1, 4, false, mFakeGroupCreator.groups.get(0));
154         assertGroupIs(8, 3, false, mFakeGroupCreator.groups.get(1));
155     }
156 
testEqualPhoneNumbers()157     public void testEqualPhoneNumbers() {
158         // Identical.
159         assertTrue(mBuilder.equalNumbers("6505555555", "6505555555"));
160         assertTrue(mBuilder.equalNumbers("650 555 5555", "650 555 5555"));
161         // Formatting.
162         assertTrue(mBuilder.equalNumbers("6505555555", "650 555 5555"));
163         assertTrue(mBuilder.equalNumbers("6505555555", "(650) 555-5555"));
164         assertTrue(mBuilder.equalNumbers("650 555 5555", "(650) 555-5555"));
165         // Short codes.
166         assertTrue(mBuilder.equalNumbers("55555", "55555"));
167         assertTrue(mBuilder.equalNumbers("55555", "555 55"));
168         // Different numbers.
169         assertFalse(mBuilder.equalNumbers("6505555555", "650555555"));
170         assertFalse(mBuilder.equalNumbers("6505555555", "6505555551"));
171         assertFalse(mBuilder.equalNumbers("650 555 5555", "650 555 555"));
172         assertFalse(mBuilder.equalNumbers("650 555 5555", "650 555 5551"));
173         assertFalse(mBuilder.equalNumbers("55555", "5555"));
174         assertFalse(mBuilder.equalNumbers("55555", "55551"));
175         // SIP addresses.
176         assertTrue(mBuilder.equalNumbers("6505555555@host.com", "6505555555@host.com"));
177         assertTrue(mBuilder.equalNumbers("6505555555@host.com", "6505555555@HOST.COM"));
178         assertTrue(mBuilder.equalNumbers("user@host.com", "user@host.com"));
179         assertTrue(mBuilder.equalNumbers("user@host.com", "user@HOST.COM"));
180         assertFalse(mBuilder.equalNumbers("USER@host.com", "user@host.com"));
181         assertFalse(mBuilder.equalNumbers("user@host.com", "user@host1.com"));
182         // SIP address vs phone number.
183         assertFalse(mBuilder.equalNumbers("6505555555@host.com", "6505555555"));
184         assertFalse(mBuilder.equalNumbers("6505555555", "6505555555@host.com"));
185         assertFalse(mBuilder.equalNumbers("user@host.com", "6505555555"));
186         assertFalse(mBuilder.equalNumbers("6505555555", "user@host.com"));
187         // Nulls.
188         assertTrue(mBuilder.equalNumbers(null, null));
189         assertFalse(mBuilder.equalNumbers(null, "6505555555"));
190         assertFalse(mBuilder.equalNumbers("6505555555", null));
191         assertFalse(mBuilder.equalNumbers(null, "6505555555@host.com"));
192         assertFalse(mBuilder.equalNumbers("6505555555@host.com", null));
193     }
194 
testCompareSipAddresses()195     public void testCompareSipAddresses() {
196         // Identical.
197         assertTrue(mBuilder.compareSipAddresses("6505555555@host.com", "6505555555@host.com"));
198         assertTrue(mBuilder.compareSipAddresses("user@host.com", "user@host.com"));
199         // Host is case insensitive.
200         assertTrue(mBuilder.compareSipAddresses("6505555555@host.com", "6505555555@HOST.COM"));
201         assertTrue(mBuilder.compareSipAddresses("user@host.com", "user@HOST.COM"));
202         // Userinfo is case sensitive.
203         assertFalse(mBuilder.compareSipAddresses("USER@host.com", "user@host.com"));
204         // Different hosts.
205         assertFalse(mBuilder.compareSipAddresses("user@host.com", "user@host1.com"));
206         // Different users.
207         assertFalse(mBuilder.compareSipAddresses("user1@host.com", "user@host.com"));
208         // Nulls.
209         assertTrue(mBuilder.compareSipAddresses(null, null));
210         assertFalse(mBuilder.compareSipAddresses(null, "6505555555@host.com"));
211         assertFalse(mBuilder.compareSipAddresses("6505555555@host.com", null));
212     }
213 
214     /** Creates (or recreates) the cursor used to store the call log content for the tests. */
createCursor()215     private void createCursor() {
216         mCursor = new MatrixCursor(CallLogQuery._PROJECTION);
217     }
218 
219     /** Clears the content of the {@link FakeGroupCreator} used in the tests. */
clearFakeGroupCreator()220     private void clearFakeGroupCreator() {
221         mFakeGroupCreator.groups.clear();
222     }
223 
224     /** Asserts that calls of the given types are grouped together into a single group. */
assertCallsAreGrouped(int... types)225     private void assertCallsAreGrouped(int... types) {
226         createCursor();
227         clearFakeGroupCreator();
228         addMultipleCallLogEntries(TEST_NUMBER1, types);
229         mBuilder.addGroups(mCursor);
230         assertEquals(1, mFakeGroupCreator.groups.size());
231         assertGroupIs(0, types.length, false, mFakeGroupCreator.groups.get(0));
232 
233     }
234 
235     /** Asserts that calls of the given types are not grouped together at all. */
assertCallsAreNotGrouped(int... types)236     private void assertCallsAreNotGrouped(int... types) {
237         createCursor();
238         clearFakeGroupCreator();
239         addMultipleCallLogEntries(TEST_NUMBER1, types);
240         mBuilder.addGroups(mCursor);
241         assertEquals(0, mFakeGroupCreator.groups.size());
242     }
243 
244     /** Adds a set of calls with the given types, all from the same number, in the old section. */
addMultipleCallLogEntries(String number, int... types)245     private void addMultipleCallLogEntries(String number, int... types) {
246         for (int type : types) {
247             addCallLogEntry(number, type);
248         }
249     }
250     /** Adds a call log entry with the given number and type to the cursor. */
addCallLogEntry(String number, int type)251     private void addCallLogEntry(String number, int type) {
252         mCursor.moveToNext();
253         Object[] values = CallLogQueryTestUtils.createTestValues();
254         values[CallLogQuery.ID] = mCursor.getPosition();
255         values[CallLogQuery.NUMBER] = number;
256         values[CallLogQuery.CALL_TYPE] = type;
257         mCursor.addRow(values);
258     }
259 
260     /** Adds a call log entry with a header to the cursor. */
addCallLogHeader(int section)261     private void addCallLogHeader(int section) {
262         mCursor.moveToNext();
263         Object[] values = CallLogQueryTestUtils.createTestValues();
264         values[CallLogQuery.ID] = mCursor.getPosition();
265         mCursor.addRow(values);
266     }
267 
268     /** Asserts that the group matches the given values. */
assertGroupIs(int cursorPosition, int size, boolean expanded, GroupSpec group)269     private void assertGroupIs(int cursorPosition, int size, boolean expanded, GroupSpec group) {
270         assertEquals(cursorPosition, group.cursorPosition);
271         assertEquals(size, group.size);
272         assertEquals(expanded, group.expanded);
273     }
274 
275     /** Defines an added group. Used by the {@link FakeGroupCreator}. */
276     private static class GroupSpec {
277         /** The starting position of the group. */
278         public final int cursorPosition;
279         /** The number of elements in the group. */
280         public final int size;
281         /** Whether the group should be initially expanded. */
282         public final boolean expanded;
283 
GroupSpec(int cursorPosition, int size, boolean expanded)284         public GroupSpec(int cursorPosition, int size, boolean expanded) {
285             this.cursorPosition = cursorPosition;
286             this.size = size;
287             this.expanded = expanded;
288         }
289     }
290 
291     /** Fake implementation of a GroupCreator which stores the created groups in a member field. */
292     private static class FakeGroupCreator implements CallLogGroupBuilder.GroupCreator {
293         /** The list of created groups. */
294         public final List<GroupSpec> groups = newArrayList();
295 
296         @Override
addGroup(int cursorPosition, int size, boolean expanded)297         public void addGroup(int cursorPosition, int size, boolean expanded) {
298             groups.add(new GroupSpec(cursorPosition, size, expanded));
299         }
300 
301         @Override
setDayGroup(long rowId, int dayGroup)302         public void setDayGroup(long rowId, int dayGroup) {
303             //No-op
304         }
305 
306         @Override
clearDayGroups()307         public void clearDayGroups() {
308             //No-op
309         }
310     }
311 }
312