Home | History | Annotate | Download | only in browse
      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 }