1/*
2 * Copyright (C) 2008 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.emailcommon.utility;
18
19import com.android.email.DBTestHelper;
20import com.android.email.R;
21import com.android.email.TestUtils;
22import com.android.email.provider.ProviderTestUtils;
23import com.android.emailcommon.provider.Account;
24import com.android.emailcommon.provider.EmailContent.Attachment;
25import com.android.emailcommon.provider.EmailContent.MailboxColumns;
26import com.android.emailcommon.provider.EmailContent.Message;
27import com.android.emailcommon.provider.Mailbox;
28import com.android.emailcommon.utility.Utility.NewFileCreator;
29
30import android.content.Context;
31import android.database.Cursor;
32import android.database.CursorWrapper;
33import android.database.MatrixCursor;
34import android.graphics.drawable.Drawable;
35import android.net.Uri;
36import android.os.Environment;
37import android.test.AndroidTestCase;
38import android.test.MoreAsserts;
39import android.test.suitebuilder.annotation.SmallTest;
40import android.text.SpannableStringBuilder;
41import android.text.TextUtils;
42import android.widget.TextView;
43
44import java.io.File;
45import java.io.FileNotFoundException;
46import java.io.FileOutputStream;
47import java.io.IOException;
48import java.io.OutputStream;
49import java.util.ArrayList;
50import java.util.Collection;
51import java.util.HashSet;
52import java.util.Set;
53
54/**
55 * This is a series of unit tests for the Utility class.  These tests must be locally
56 * complete - no server(s) required.
57 *
58 * You can run this entire test case with:
59 *   runtest -c com.android.email.UtilityUnitTests email
60 */
61@SmallTest
62public class UtilityUnitTests extends AndroidTestCase {
63
64    private static byte[] b(int... array) {
65        return TestUtils.b(array);
66    }
67
68    public void testToUtf8() {
69        assertNull(Utility.toUtf8(null));
70        MoreAsserts.assertEquals(new byte[] {}, Utility.toUtf8(""));
71        MoreAsserts.assertEquals(b('a'), Utility.toUtf8("a"));
72        MoreAsserts.assertEquals(b('A', 'B', 'C'), Utility.toUtf8("ABC"));
73        MoreAsserts.assertEquals(b(0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E),
74                Utility.toUtf8("\u65E5\u672C\u8A9E"));
75    }
76
77    public void testFromUtf8() {
78        assertNull(Utility.fromUtf8(null));
79        assertEquals("", Utility.fromUtf8(new byte[] {}));
80        assertEquals("a", Utility.fromUtf8(b('a')));
81        assertEquals("ABC", Utility.fromUtf8(b('A', 'B', 'C')));
82        assertEquals("\u65E5\u672C\u8A9E",
83                Utility.fromUtf8(b(0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E)));
84    }
85
86    public void testIsFirstUtf8Byte() {
87        // 1 byte in UTF-8.
88        checkIsFirstUtf8Byte("0"); // First 2 bits: 00
89        checkIsFirstUtf8Byte("A"); // First 2 bits: 01
90
91        checkIsFirstUtf8Byte("\u00A2"); // 2 bytes in UTF-8.
92        checkIsFirstUtf8Byte("\u20AC"); // 3 bytes in UTF-8.
93        checkIsFirstUtf8Byte("\uD852\uDF62"); // 4 bytes in UTF-8.  (surrogate pair)
94    }
95
96    private void checkIsFirstUtf8Byte(String aChar) {
97        byte[] bytes = Utility.toUtf8(aChar);
98        assertTrue("0", Utility.isFirstUtf8Byte(bytes[0]));
99        for (int i = 1; i < bytes.length; i++) {
100            assertFalse(Integer.toString(i), Utility.isFirstUtf8Byte(bytes[i]));
101        }
102    }
103
104    public void testByteToHex() {
105        for (int i = 0; i <= 0xFF; i++) {
106            String hex = Utility.byteToHex((byte) i);
107            assertEquals("val=" + i, 2, hex.length());
108            assertEquals("val=" + i, i, Integer.parseInt(hex, 16));
109        }
110    }
111
112    public void testReplaceBareLfWithCrlf() {
113        assertEquals("", Utility.replaceBareLfWithCrlf(""));
114        assertEquals("", Utility.replaceBareLfWithCrlf("\r"));
115        assertEquals("\r\n", Utility.replaceBareLfWithCrlf("\r\n"));
116        assertEquals("\r\n", Utility.replaceBareLfWithCrlf("\n"));
117        assertEquals("\r\n\r\n\r\n", Utility.replaceBareLfWithCrlf("\n\n\n"));
118        assertEquals("A\r\nB\r\nC\r\nD", Utility.replaceBareLfWithCrlf("A\nB\r\nC\nD"));
119    }
120
121    public void testGetSmallHash() {
122        assertEquals("1438642069", Utility.getSmallHash(""));
123        assertEquals("1354919068", Utility.getSmallHash("abc"));
124    }
125
126    public void testGetSmallSha1() {
127        byte[] sha1 = new byte[20];
128
129        // White box test.  Not so great, but to make sure it may detect careless mistakes...
130        assertEquals(0, Utility.getSmallHashFromSha1(sha1));
131
132        for (int i = 0; i < sha1.length; i++) {
133            sha1[i] = (byte) 0xFF;
134        }
135        assertEquals(Integer.MAX_VALUE, Utility.getSmallHashFromSha1(sha1));
136
137        // Boundary check
138        for (int i = 0; i < 16; i++) {
139            sha1[19] = (byte) i;
140            Utility.getSmallHashFromSha1(sha1);
141        }
142    }
143
144    public void testCleanUpMimeDate() {
145        assertNull(Utility.cleanUpMimeDate(null));
146        assertEquals("", Utility.cleanUpMimeDate(""));
147        assertEquals("abc", Utility.cleanUpMimeDate("abc"));
148        assertEquals("GMT", Utility.cleanUpMimeDate("GMT"));
149        assertEquals("0000", Utility.cleanUpMimeDate("0000"));
150        assertEquals("-0000", Utility.cleanUpMimeDate("-0000"));
151        assertEquals("+1234", Utility.cleanUpMimeDate("GMT+1234"));
152        assertEquals("-1234", Utility.cleanUpMimeDate("GMT-1234"));
153        assertEquals("gmt-1234", Utility.cleanUpMimeDate("gmt-1234"));
154        assertEquals("GMT-123", Utility.cleanUpMimeDate("GMT-123"));
155
156        assertEquals("Thu, 10 Dec 09 15:08:08 -0700",
157                Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 GMT-0700"));
158        assertEquals("Thu, 10 Dec 09 15:08:08 -0700",
159                Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 -0700"));
160    }
161
162    private static class MyNewFileCreator implements NewFileCreator {
163        private final HashSet<String> mExistingFileNames;
164
165        public MyNewFileCreator(String... fileNames) {
166            mExistingFileNames = new HashSet<String>();
167            for (String f : fileNames) {
168                mExistingFileNames.add(f);
169            }
170        }
171
172        @Override public boolean createNewFile(File f) {
173            return !mExistingFileNames.contains(f.getAbsolutePath());
174        }
175    }
176
177    public void testCreateUniqueFile() throws Exception {
178        final MyNewFileCreator noFiles = new MyNewFileCreator();
179
180        // Case 1: Files don't exist.
181        checkCreateUniqueFile("/a", noFiles, "/", "a");
182        checkCreateUniqueFile("/a.txt", noFiles, "/", "a.txt");
183
184        checkCreateUniqueFile("/a/b/a", noFiles, "/a/b", "a");
185        checkCreateUniqueFile("/a/b/a.txt", noFiles, "/a/b", "a.txt");
186
187        // Case 2: Files exist already.
188        final MyNewFileCreator files = new MyNewFileCreator(
189                "/a", "/a.txt", "/a/b/a", "/a/b/a.txt",
190                "/a-2.txt",
191                "/a/b/a-2", "/a/b/a-3",
192                "/a/b/a-2.txt", "/a/b/a-3.txt", "/a/b/a-4.txt"
193                );
194
195        checkCreateUniqueFile("/a-2", files, "/", "a");
196        checkCreateUniqueFile("/a-3.txt", files, "/", "a.txt");
197
198        checkCreateUniqueFile("/a/b/a-4", files, "/a/b", "a");
199        checkCreateUniqueFile("/a/b/a-5.txt", files, "/a/b", "a.txt");
200    }
201
202    private void checkCreateUniqueFile(String expectedFileName, NewFileCreator nfc,
203            String dir, String fileName) throws Exception {
204        assertEquals(expectedFileName,
205                Utility.createUniqueFileInternal(nfc, new File(dir), fileName).toString());
206    }
207
208    /**
209     * Test that we have the necessary permissions to write to external storage.
210     */
211    public void testExternalStoragePermissions() throws FileNotFoundException, IOException {
212        File file = null;
213        try {
214            // If there's no storage available, this test is moot
215            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
216                return;
217            }
218            file = Utility.createUniqueFile(Environment.getExternalStorageDirectory(),
219                    "write-test");
220            OutputStream out = new FileOutputStream(file);
221            out.write(1);
222            out.close();
223        } finally {
224            try {
225                if (file != null) {
226                    if (file.exists()) {
227                        file.delete();
228                    }
229                }
230            } catch (Exception e) {
231                // ignore cleanup error - it still throws the original
232            }
233        }
234    }
235
236    public void testIsPortFieldValid() {
237        TextView view = new TextView(getContext());
238        // null, empty, negative, and non integer strings aren't valid
239        view.setText(null);
240        assertFalse(Utility.isPortFieldValid(view));
241        view.setText("");
242        assertFalse(Utility.isPortFieldValid(view));
243        view.setText("-1");
244        assertFalse(Utility.isPortFieldValid(view));
245        view.setText("1403.75");
246        assertFalse(Utility.isPortFieldValid(view));
247        view.setText("0");
248        assertFalse(Utility.isPortFieldValid(view));
249        view.setText("65536");
250        assertFalse(Utility.isPortFieldValid(view));
251        view.setText("i'm not valid");
252        assertFalse(Utility.isPortFieldValid(view));
253        // These next values are valid
254        view.setText("1");
255        assertTrue(Utility.isPortFieldValid(view));
256        view.setText("65535");
257        assertTrue(Utility.isPortFieldValid(view));
258    }
259
260    public void testToPrimitiveLongArray() {
261        assertEquals(0, Utility.toPrimitiveLongArray(createLongCollection()).length);
262
263        final long[] one = Utility.toPrimitiveLongArray(createLongCollection(1));
264        assertEquals(1, one.length);
265        assertEquals(1, one[0]);
266
267        final long[] two = Utility.toPrimitiveLongArray(createLongCollection(3, 4));
268        assertEquals(2, two.length);
269        assertEquals(3, two[0]);
270        assertEquals(4, two[1]);
271    }
272
273    public void testToLongSet() {
274        assertEquals(0, Utility.toLongSet(new long[] {}).size());
275
276        final Set<Long> one = Utility.toLongSet(new long[] {1});
277        assertEquals(1, one.size());
278        assertTrue(one.contains(1L));
279
280        final Set<Long> two = Utility.toLongSet(new long[] {1, 2});
281        assertEquals(2, two.size());
282        assertTrue(two.contains(1L));
283        assertTrue(two.contains(2L));
284    }
285
286    public void testGetContentFileName() throws Exception {
287        Context providerContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
288                mContext);
289
290        final long ACCOUNT_ID = 1;
291        final long MESSAGE_ID = 10;
292
293        Account account = ProviderTestUtils.setupAccount("account", true, providerContext);
294        Mailbox mailbox = ProviderTestUtils.setupMailbox("box", account.mId, true, providerContext);
295
296        // Set up an attachment.
297        Attachment att = ProviderTestUtils.setupAttachment(mailbox.mId, "name", 123, true,
298                providerContext);
299        long attachmentId = att.mId;
300        Uri uri = AttachmentUtilities.getAttachmentUri(account.mId, attachmentId);
301
302        // Case 1: exists in the provider.
303        assertEquals("name", Utility.getContentFileName(providerContext, uri));
304
305        // Case 2: doesn't exist in the provider
306        Uri notExistUri = AttachmentUtilities.getAttachmentUri(account.mId, 123456789);
307        String lastPathSegment = notExistUri.getLastPathSegment();
308        assertEquals(lastPathSegment, Utility.getContentFileName(providerContext, notExistUri));
309    }
310
311    private long getLastUpdateKey(Context mockContext, long mailboxId) {
312        return Utility.getFirstRowLong(mockContext, Mailbox.CONTENT_URI,
313                new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY }, MailboxColumns.ID + "=?",
314                new String[] { Long.toString(mailboxId) }, null, 0, -1L);
315    }
316
317    public void testUpdateLastSeenMessageKey() throws Exception {
318        Context mockContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(mContext);
319
320        // Setup account & message stuff
321        Account account1 = ProviderTestUtils.setupAccount("account1", true, mockContext);
322        Account account2 = ProviderTestUtils.setupAccount("account2", true, mockContext);
323        Account account3 = ProviderTestUtils.setupAccount("account3", true, mockContext);
324        Account account4 = ProviderTestUtils.setupAccount("account4", true, mockContext);
325        Mailbox mailbox1_1 = ProviderTestUtils.setupMailbox("mbox1_1", account1.mId, true,
326                mockContext, Mailbox.TYPE_INBOX);
327        Mailbox mailbox1_2 = ProviderTestUtils.setupMailbox("mbox1_2", account1.mId, true,
328                mockContext, Mailbox.TYPE_MAIL);
329        Mailbox mailbox1_3 = ProviderTestUtils.setupMailbox("mbox1_3", account1.mId, true,
330                mockContext, Mailbox.TYPE_DRAFTS);
331        Mailbox mailbox1_4 = ProviderTestUtils.setupMailbox("mbox1_4", account1.mId, true,
332                mockContext, Mailbox.TYPE_OUTBOX);
333        Mailbox mailbox1_5 = ProviderTestUtils.setupMailbox("mbox1_5", account1.mId, true,
334                mockContext, Mailbox.TYPE_TRASH);
335        Mailbox mailbox2_1 = ProviderTestUtils.setupMailbox("mbox2_1", account2.mId, true,
336                mockContext, Mailbox.TYPE_MAIL);
337        Mailbox mailbox3_1 = ProviderTestUtils.setupMailbox("mbox3_1", account3.mId, true,
338                mockContext, Mailbox.TYPE_MAIL);
339        Mailbox mailbox3_2 = ProviderTestUtils.setupMailbox("mbox3_2", account3.mId, true,
340                mockContext, Mailbox.TYPE_INBOX);
341        Mailbox mailbox4_1 = ProviderTestUtils.setupMailbox("mbox4_1", account4.mId, true,
342                mockContext, Mailbox.TYPE_INBOX);
343        Message message1_1_1 = ProviderTestUtils.setupMessage("message_1_1_1", account1.mId,
344                mailbox1_1.mId, false, true, mockContext);
345        Message message1_1_2 = ProviderTestUtils.setupMessage("message_1_1_2", account1.mId,
346                mailbox1_1.mId, false, true, mockContext);
347        Message message1_1_3 = ProviderTestUtils.setupMessage("message_1_1_3", account1.mId,
348                mailbox1_1.mId, false, true, mockContext);
349        Message message1_2_1 = ProviderTestUtils.setupMessage("message_1_2_1", account1.mId,
350                mailbox1_2.mId, false, true, mockContext);
351        Message message1_3_1 = ProviderTestUtils.setupMessage("message_1_3_1", account1.mId,
352                mailbox1_3.mId, false, true, mockContext);
353        Message message1_4_1 = ProviderTestUtils.setupMessage("message_1_4_1", account1.mId,
354                mailbox1_4.mId, false, true, mockContext);
355        Message message1_5_1 = ProviderTestUtils.setupMessage("message_1_5_1", account1.mId,
356                mailbox1_5.mId, false, true, mockContext);
357        Message message2_1_1 = ProviderTestUtils.setupMessage("message_2_1_1", account2.mId,
358                mailbox2_1.mId, false, true, mockContext);
359        Message message2_1_2 = ProviderTestUtils.setupMessage("message_2_1_2", account2.mId,
360                mailbox2_1.mId, false, true, mockContext);
361        Message message3_1_1 = ProviderTestUtils.setupMessage("message_3_1_1", account3.mId,
362                mailbox3_1.mId, false, true, mockContext);
363        Message message4_1_1 = ProviderTestUtils.setupMessage("message_4_1_1", account4.mId,
364                mailbox4_1.mId, false, true, mockContext);
365        Message message4_1_2 = ProviderTestUtils.setupMessage("message_4_1_2", account4.mId,
366                mailbox4_1.mId, false, true, mockContext);
367        Message message4_1_3 = ProviderTestUtils.setupMessage("message_4_1_3", account4.mId,
368                mailbox4_1.mId, false, true, mockContext);
369        Message message4_1_4 = ProviderTestUtils.setupMessage("message_4_1_4", account4.mId,
370                mailbox4_1.mId, false, true, mockContext);
371
372        // Verify the default case
373        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_1.mId));
374        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId));
375        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId));
376        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_4.mId));
377        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_5.mId));
378        assertEquals(0L, getLastUpdateKey(mockContext, mailbox2_1.mId));
379        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_1.mId));
380        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_2.mId));
381        assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId));
382
383        // Test account; only INBOX is modified
384        Utility.updateLastSeenMessageKey(mockContext, account1.mId).get();
385        assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId));
386        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId));
387        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId));
388        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_4.mId));
389        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_5.mId));
390        assertEquals(0L, getLastUpdateKey(mockContext, mailbox2_1.mId));
391        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_1.mId));
392        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_2.mId));
393        assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId));
394
395        // Missing INBOX
396        Utility.updateLastSeenMessageKey(mockContext, account2.mId).get();
397        assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId));
398        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId));
399        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId));
400        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_4.mId));
401        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_5.mId));
402        assertEquals(0L, getLastUpdateKey(mockContext, mailbox2_1.mId));
403        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_1.mId));
404        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_2.mId));
405        assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId));
406
407        // No messages in mailbox
408        Utility.updateLastSeenMessageKey(mockContext, account3.mId).get();
409        assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId));
410        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId));
411        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId));
412        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_4.mId));
413        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_5.mId));
414        assertEquals(0L, getLastUpdateKey(mockContext, mailbox2_1.mId));
415        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_1.mId));
416        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_2.mId));
417        assertEquals(0L, getLastUpdateKey(mockContext, mailbox4_1.mId));
418
419        // Test combined accounts
420        Utility.updateLastSeenMessageKey(mockContext, 0x1000000000000000L).get();
421        assertEquals(message1_1_3.mId, getLastUpdateKey(mockContext, mailbox1_1.mId));
422        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_2.mId));
423        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_3.mId));
424        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_4.mId));
425        assertEquals(0L, getLastUpdateKey(mockContext, mailbox1_5.mId));
426        assertEquals(0L, getLastUpdateKey(mockContext, mailbox2_1.mId));
427        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_1.mId));
428        assertEquals(0L, getLastUpdateKey(mockContext, mailbox3_2.mId));
429        assertEquals(message4_1_4.mId, getLastUpdateKey(mockContext, mailbox4_1.mId));
430    }
431
432    // used by testToPrimitiveLongArray
433    private static Collection<Long> createLongCollection(long... values) {
434        ArrayList<Long> ret = new ArrayList<Long>();
435        for (long value : values) {
436            ret.add(value);
437        }
438        return ret;
439    }
440
441    public void testDumpCursor() {
442        // Just make sure the method won't crash and returns non-empty string.
443        final Cursor c1 = new MatrixCursor(new String[] {"col"});
444        final Cursor c2 = new CursorWrapper(c1);
445
446        // Note it's a subclass of CursorWrapper.
447        final Cursor c3 = new CursorWrapper(c2) {
448        };
449
450        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c1)));
451        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c2)));
452        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c3)));
453        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(null)));
454
455        // Test again with closed cursor.
456        c1.close();
457        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c1)));
458        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c2)));
459        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c3)));
460        assertFalse(TextUtils.isEmpty(Utility.dumpCursor(null)));
461    }
462
463    public void testCloseTraceCursorWrapper() {
464        final Cursor org = new MatrixCursor(new String[] {"col"});
465        final Utility.CloseTraceCursorWrapper c =
466                Utility.CloseTraceCursorWrapper.alwaysCreateForTest(org);
467
468        // Not closed -- no stack trace
469        assertNull(Utility.CloseTraceCursorWrapper.getTraceIfAvailable(c));
470        Utility.CloseTraceCursorWrapper.log(c); // shouldn't crash
471
472        // Close, now stack trace should be available
473        c.close();
474        assertNotNull(Utility.CloseTraceCursorWrapper.getTraceIfAvailable(c));
475        Utility.CloseTraceCursorWrapper.log(c);
476
477        // shouldn't crash
478        Utility.CloseTraceCursorWrapper.log(null);
479    }
480
481    public void testAppendBold() {
482        SpannableStringBuilder ssb = new SpannableStringBuilder();
483        ssb.append("no");
484
485        assertEquals(ssb, Utility.appendBold(ssb, "BO"));
486
487        assertEquals("noBO", ssb.toString());
488        // TODO check style -- but how?
489    }
490
491    public void testAreStringsEqual() {
492        String s1;
493        String s2;
494
495        s1 = new String("Foo");
496        s2 = s1;
497        assertTrue(Utility.areStringsEqual(s1, s2));
498
499        s2 = new String("Foo");
500        assertTrue(Utility.areStringsEqual(s1, s2));
501
502        s2 = "Bar";
503        assertFalse(Utility.areStringsEqual(s1, s2));
504
505        s2 = null;
506        assertFalse(Utility.areStringsEqual(s1, s2));
507
508        s1 = null;
509        s2 = "Bar";
510        assertFalse(Utility.areStringsEqual(s1, s2));
511
512        s1 = null;
513        s2 = null;
514        assertTrue(Utility.areStringsEqual(s1, s2));
515    }
516
517    public void testIsServerNameValid() {
518        assertTrue(Utility.isServerNameValid("a"));
519        assertTrue(Utility.isServerNameValid("gmail"));
520        assertTrue(Utility.isServerNameValid("gmail.com"));
521        assertTrue(Utility.isServerNameValid("gmail.com.x.y.z"));
522        assertTrue(Utility.isServerNameValid("  gmail.com.x.y.z  "));
523
524        assertFalse(Utility.isServerNameValid(""));
525        assertFalse(Utility.isServerNameValid("$"));
526        assertFalse(Utility.isServerNameValid("  "));
527    }
528
529    private static Collection<Long> toColleciton(long... values) {
530        ArrayList<Long> ret = new ArrayList<Long>();
531        for (long v : values) {
532            ret.add(v);
533        }
534        return ret;
535    }
536
537    public void testBuildInSelection() {
538        assertEquals("", Utility.buildInSelection("c", null));
539        assertEquals("", Utility.buildInSelection("c", toColleciton()));
540        assertEquals("c in (1)", Utility.buildInSelection("c", toColleciton(1)));
541        assertEquals("c in (1,2)", Utility.buildInSelection("c", toColleciton(1, 2)));
542        assertEquals("c in (1,2,-500)", Utility.buildInSelection("c", toColleciton(1, 2, -500)));
543    }
544}
545