1 /******************************************************************************* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 *******************************************************************************/ 17 18 package com.android.mail.browse; 19 20 import android.test.AndroidTestCase; 21 import android.test.suitebuilder.annotation.SmallTest; 22 import android.text.SpannableString; 23 24 import com.android.mail.providers.Account; 25 import com.android.mail.providers.ConversationInfo; 26 import com.android.mail.providers.ParticipantInfo; 27 import com.android.mail.providers.UIProvider; 28 import com.google.common.collect.Lists; 29 30 import org.json.JSONException; 31 import org.json.JSONObject; 32 33 import java.util.ArrayList; 34 import java.util.HashMap; 35 import java.util.Map; 36 37 @SmallTest 38 public class SendersFormattingTests extends AndroidTestCase { 39 40 private static ConversationInfo createConversationInfo() { 41 return new ConversationInfo(0, 5, "snippet", "snippet", "snippet"); 42 } 43 44 public void testMeFromNullName() { 45 final ConversationInfo conv = createConversationInfo(); 46 conv.addParticipant(new ParticipantInfo(null, "something (at) somewhere.com", 0, false)); 47 final ArrayList<SpannableString> strings = Lists.newArrayList(); 48 assertEquals(0, strings.size()); 49 50 final Account account = createAccount(); 51 SendersView.format(getContext(), conv, "", 100, strings, null, null, account, false, false); 52 assertEquals(1, strings.size()); 53 assertEquals("me", strings.get(0).toString()); 54 } 55 56 public void testMeFromEmptyName() { 57 final ConversationInfo conv = createConversationInfo(); 58 conv.addParticipant(new ParticipantInfo("", "something (at) somewhere.com", 0, false)); 59 final ArrayList<SpannableString> strings = Lists.newArrayList(); 60 assertEquals(0, strings.size()); 61 62 final Account account = createAccount(); 63 SendersView.format(getContext(), conv, "", 100, strings, null, null, account, false, false); 64 assertEquals(1, strings.size()); 65 assertEquals("me", strings.get(0).toString()); 66 } 67 68 public void testMeFromDuplicateEmptyNames() { 69 final ConversationInfo conv = createConversationInfo(); 70 conv.addParticipant(new ParticipantInfo("", "something (at) somewhere.com", 0, false)); 71 conv.addParticipant(new ParticipantInfo("", "something (at) somewhere.com", 0, false)); 72 final ArrayList<SpannableString> strings = Lists.newArrayList(); 73 assertEquals(0, strings.size()); 74 75 final Account account = createAccount(); 76 SendersView.format(getContext(), conv, "", 100, strings, null, null, account, false, false); 77 assertEquals(2, strings.size()); 78 assertNull(strings.get(0)); 79 assertEquals("me", strings.get(1).toString()); 80 } 81 82 public void testDuplicates() { 83 final ConversationInfo conv = createConversationInfo(); 84 conv.addParticipant(new ParticipantInfo("Something", "something (at) somewhere.com", 0, false)); 85 conv.addParticipant(new ParticipantInfo("Something", "something (at) somewhere.com", 0, false)); 86 87 final ArrayList<SpannableString> strings = Lists.newArrayList(); 88 assertEquals(0, strings.size()); 89 90 final Account account = createAccount(); 91 SendersView.format(getContext(), conv, "", 100, strings, null, null, account, false, false); 92 assertEquals(2, strings.size()); 93 assertNull(strings.get(0)); 94 assertEquals("Something", strings.get(1).toString()); 95 } 96 97 public void testSenderNameBadInput() { 98 final ConversationInfo before = createConversationInfo(); 99 before.addParticipant(new ParticipantInfo("****^****", null, 0, false)); 100 101 final byte[] serialized = before.toBlob(); 102 103 final ConversationInfo after = ConversationInfo.fromBlob(serialized); 104 assertEquals(1, after.participantInfos.size()); 105 assertEquals(before.participantInfos.get(0).name, after.participantInfos.get(0).name); 106 } 107 108 public void testConversationSnippetsBadInput() { 109 final String first = "*^*"; 110 final String firstUnread = "*^*^*"; 111 final String last = "*^*^*^*"; 112 113 final ConversationInfo before = new ConversationInfo(42, 49, first, firstUnread, last); 114 before.addParticipant(new ParticipantInfo("Foo Bar", "foo (at) bar.com", 0, false)); 115 assertEquals(first, before.firstSnippet); 116 assertEquals(firstUnread, before.firstUnreadSnippet); 117 assertEquals(last, before.lastSnippet); 118 119 final byte[] serialized = before.toBlob(); 120 121 final ConversationInfo after = ConversationInfo.fromBlob(serialized); 122 assertEquals(before.firstSnippet, after.firstSnippet); 123 assertEquals(before.firstUnreadSnippet, after.firstUnreadSnippet); 124 assertEquals(before.lastSnippet, after.lastSnippet); 125 } 126 127 public void testSenderAvatarIsSenderOfFirstUnreadMessage() { 128 final ConversationInfo conv = createConversationInfo(); 129 conv.addParticipant(new ParticipantInfo("a", "a (at) a.com", 0, true)); 130 conv.addParticipant(new ParticipantInfo("b", "b (at) b.com", 0, false)); 131 conv.addParticipant(new ParticipantInfo("c", "c (at) c.com", 0, false)); 132 133 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 134 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 135 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 136 new ConversationItemViewModel.SenderAvatarModel(); 137 138 final Account account = createAccount(); 139 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 140 senderAvatarModel, account, false, false); 141 142 // b is the first unread message with a valid email address 143 assertEquals("b (at) b.com", senderAvatarModel.getEmailAddress()); 144 assertEquals("b", senderAvatarModel.getName()); 145 } 146 147 public void testSenderAvatarDoesNotChooseEmptyEmailAddress() { 148 final ConversationInfo conv = createConversationInfo(); 149 conv.addParticipant(new ParticipantInfo("a", "a (at) a.com", 0, true)); 150 conv.addParticipant(new ParticipantInfo("b", "", 0, false)); 151 conv.addParticipant(new ParticipantInfo("c", "c (at) c.com", 0, false)); 152 153 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 154 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 155 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 156 new ConversationItemViewModel.SenderAvatarModel(); 157 158 final Account account = createAccount(); 159 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 160 senderAvatarModel, account, false, false); 161 162 // b is unread but has an invalid email address so email address is set to the name 163 assertEquals("b", senderAvatarModel.getEmailAddress()); 164 assertEquals("b", senderAvatarModel.getName()); 165 } 166 167 public void testSenderAvatarIsLastSenderIfAllMessagesAreRead() { 168 final ConversationInfo conv = createConversationInfo(); 169 conv.addParticipant(new ParticipantInfo("a", "a (at) a.com", 0, true)); 170 conv.addParticipant(new ParticipantInfo("b", "b (at) b.com", 0, true)); 171 conv.addParticipant(new ParticipantInfo("c", "c (at) c.com", 0, true)); 172 173 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 174 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 175 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 176 new ConversationItemViewModel.SenderAvatarModel(); 177 178 final Account account = createAccount(); 179 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 180 senderAvatarModel, account, false, false); 181 182 // all are read, so c is chosen because it is the last sender 183 assertEquals("c (at) c.com", senderAvatarModel.getEmailAddress()); 184 assertEquals("c", senderAvatarModel.getName()); 185 } 186 187 public void testSenderAvatarIsLastSenderWithValidEmailAddressIfAllMessagesAreRead() { 188 final ConversationInfo conv = createConversationInfo(); 189 conv.addParticipant(new ParticipantInfo("a", "a (at) a.com", 0, true)); 190 conv.addParticipant(new ParticipantInfo("b", "b (at) b.com", 0, true)); 191 conv.addParticipant(new ParticipantInfo("c", "", 0, true)); 192 193 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 194 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 195 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 196 new ConversationItemViewModel.SenderAvatarModel(); 197 198 final Account account = createAccount(); 199 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 200 senderAvatarModel, account, false, false); 201 202 // all are read, c has an invalid email address, so email address is set to the name 203 assertEquals("c", senderAvatarModel.getEmailAddress()); 204 assertEquals("c", senderAvatarModel.getName()); 205 } 206 207 public void testSenderAvatarIsLastSenderThatIsNotTheCurrentAccountIfAllMessagesAreRead() { 208 final ConversationInfo conv = createConversationInfo(); 209 conv.addParticipant(new ParticipantInfo("a", "a (at) a.com", 0, true)); 210 conv.addParticipant(new ParticipantInfo("b", "b (at) b.com", 0, true)); 211 // empty name indicates it is the current account 212 conv.addParticipant(new ParticipantInfo("", "c (at) c.com", 0, true)); 213 214 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 215 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 216 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 217 new ConversationItemViewModel.SenderAvatarModel(); 218 219 final Account account = createAccount(); 220 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 221 senderAvatarModel, account, false, false); 222 223 // c is the last sender, but it is the current account, so b is chosen instead 224 assertEquals("b (at) b.com", senderAvatarModel.getEmailAddress()); 225 assertEquals("b", senderAvatarModel.getName()); 226 } 227 228 public void testSenderAvatarIsCurrentAccountIfAllSendersAreCurrentAccount() { 229 final ConversationInfo conv = createConversationInfo(); 230 // empty name indicates it is the current account 231 conv.addParticipant(new ParticipantInfo("", "a (at) a.com", 0, true)); 232 233 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 234 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 235 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 236 new ConversationItemViewModel.SenderAvatarModel(); 237 238 final Account account = createAccount(); 239 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 240 senderAvatarModel, account, false, false); 241 242 // only one sender exists and it is the current account, so the current account is chosen 243 assertEquals("fflintstone (at) example.com", senderAvatarModel.getEmailAddress()); 244 assertEquals("Fred Flintstone", senderAvatarModel.getName()); 245 } 246 247 /** 248 * Two senders in a thread should be kept distinct if they have unique email addresses, even if 249 * they happen to share the same name. 250 */ 251 public void testSenderNamesWhenNamesMatchButEmailAddressesDiffer() { 252 final ConversationInfo conv = createConversationInfo(); 253 conv.addParticipant(new ParticipantInfo("Andrew", "aholmes (at) awesome.com", 0, true)); 254 conv.addParticipant(new ParticipantInfo("Andrew", "ajohnson (at) wicked.com", 0, true)); 255 256 final ArrayList<SpannableString> styledSenders = Lists.newArrayList(); 257 final ArrayList<String> displayableSenderNames = Lists.newArrayList(); 258 final ConversationItemViewModel.SenderAvatarModel senderAvatarModel = 259 new ConversationItemViewModel.SenderAvatarModel(); 260 261 final Account account = createAccount(); 262 SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames, 263 senderAvatarModel, account, false, false); 264 265 assertEquals(2, displayableSenderNames.size()); 266 assertEquals("Andrew", displayableSenderNames.get(0)); 267 assertEquals("Andrew", displayableSenderNames.get(1)); 268 } 269 270 private static Account createAccount() { 271 try { 272 final Map<String, Object> map = new HashMap<>(2); 273 map.put(UIProvider.AccountColumns.NAME, "Fred Flintstone"); 274 map.put(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME, "fflintstone (at) example.com"); 275 map.put(UIProvider.AccountColumns.TYPE, "IMAP"); 276 map.put(UIProvider.AccountColumns.PROVIDER_VERSION, 1); 277 map.put(UIProvider.AccountColumns.CAPABILITIES, 0); 278 279 final JSONObject json = new JSONObject(map); 280 281 return Account.builder().buildFrom(json); 282 } catch (JSONException je) { 283 throw new RuntimeException(je); 284 } 285 } 286 }