• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.emailcommon.utility;
18 
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.database.CursorWrapper;
22 import android.net.Uri;
23 import android.os.Environment;
24 import android.test.AndroidTestCase;
25 import android.test.MoreAsserts;
26 import android.test.suitebuilder.annotation.SmallTest;
27 import android.test.suitebuilder.annotation.Suppress;
28 import android.text.SpannableStringBuilder;
29 import android.text.TextUtils;
30 import android.widget.TextView;
31 
32 import com.android.email.DBTestHelper;
33 import com.android.email.TestUtils;
34 import com.android.email.provider.ProviderTestUtils;
35 import com.android.emailcommon.provider.Account;
36 import com.android.emailcommon.provider.EmailContent.Attachment;
37 import com.android.emailcommon.provider.Mailbox;
38 import com.android.emailcommon.utility.Utility.NewFileCreator;
39 import com.android.mail.utils.MatrixCursorWithCachedColumns;
40 
41 import java.io.File;
42 import java.io.FileNotFoundException;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 import java.io.OutputStream;
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.HashSet;
49 import java.util.Set;
50 
51 /**
52  * This is a series of unit tests for the Utility class.  These tests must be locally
53  * complete - no server(s) required.
54  *
55  * You can run this entire test case with:
56  *   runtest -c com.android.email.UtilityUnitTests email
57  */
58 @Suppress
59 @SmallTest
60 public class UtilityUnitTests extends AndroidTestCase {
61 
b(int... array)62     private static byte[] b(int... array) {
63         return TestUtils.b(array);
64     }
65 
testToUtf8()66     public void testToUtf8() {
67         assertNull(Utility.toUtf8(null));
68         MoreAsserts.assertEquals(new byte[] {}, Utility.toUtf8(""));
69         MoreAsserts.assertEquals(b('a'), Utility.toUtf8("a"));
70         MoreAsserts.assertEquals(b('A', 'B', 'C'), Utility.toUtf8("ABC"));
71         MoreAsserts.assertEquals(b(0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E),
72                 Utility.toUtf8("\u65E5\u672C\u8A9E"));
73     }
74 
testFromUtf8()75     public void testFromUtf8() {
76         assertNull(Utility.fromUtf8(null));
77         assertEquals("", Utility.fromUtf8(new byte[] {}));
78         assertEquals("a", Utility.fromUtf8(b('a')));
79         assertEquals("ABC", Utility.fromUtf8(b('A', 'B', 'C')));
80         assertEquals("\u65E5\u672C\u8A9E",
81                 Utility.fromUtf8(b(0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E)));
82     }
83 
testIsFirstUtf8Byte()84     public void testIsFirstUtf8Byte() {
85         // 1 byte in UTF-8.
86         checkIsFirstUtf8Byte("0"); // First 2 bits: 00
87         checkIsFirstUtf8Byte("A"); // First 2 bits: 01
88 
89         checkIsFirstUtf8Byte("\u00A2"); // 2 bytes in UTF-8.
90         checkIsFirstUtf8Byte("\u20AC"); // 3 bytes in UTF-8.
91         checkIsFirstUtf8Byte("\uD852\uDF62"); // 4 bytes in UTF-8.  (surrogate pair)
92     }
93 
checkIsFirstUtf8Byte(String aChar)94     private void checkIsFirstUtf8Byte(String aChar) {
95         byte[] bytes = Utility.toUtf8(aChar);
96         assertTrue("0", Utility.isFirstUtf8Byte(bytes[0]));
97         for (int i = 1; i < bytes.length; i++) {
98             assertFalse(Integer.toString(i), Utility.isFirstUtf8Byte(bytes[i]));
99         }
100     }
101 
testByteToHex()102     public void testByteToHex() {
103         for (int i = 0; i <= 0xFF; i++) {
104             String hex = Utility.byteToHex((byte) i);
105             assertEquals("val=" + i, 2, hex.length());
106             assertEquals("val=" + i, i, Integer.parseInt(hex, 16));
107         }
108     }
109 
testReplaceBareLfWithCrlf()110     public void testReplaceBareLfWithCrlf() {
111         assertEquals("", Utility.replaceBareLfWithCrlf(""));
112         assertEquals("", Utility.replaceBareLfWithCrlf("\r"));
113         assertEquals("\r\n", Utility.replaceBareLfWithCrlf("\r\n"));
114         assertEquals("\r\n", Utility.replaceBareLfWithCrlf("\n"));
115         assertEquals("\r\n\r\n\r\n", Utility.replaceBareLfWithCrlf("\n\n\n"));
116         assertEquals("A\r\nB\r\nC\r\nD", Utility.replaceBareLfWithCrlf("A\nB\r\nC\nD"));
117     }
118 
testGetSmallHash()119     public void testGetSmallHash() {
120         assertEquals("1438642069", Utility.getSmallHash(""));
121         assertEquals("1354919068", Utility.getSmallHash("abc"));
122     }
123 
testGetSmallSha1()124     public void testGetSmallSha1() {
125         byte[] sha1 = new byte[20];
126 
127         // White box test.  Not so great, but to make sure it may detect careless mistakes...
128         assertEquals(0, Utility.getSmallHashFromSha1(sha1));
129 
130         for (int i = 0; i < sha1.length; i++) {
131             sha1[i] = (byte) 0xFF;
132         }
133         assertEquals(Integer.MAX_VALUE, Utility.getSmallHashFromSha1(sha1));
134 
135         // Boundary check
136         for (int i = 0; i < 16; i++) {
137             sha1[19] = (byte) i;
138             Utility.getSmallHashFromSha1(sha1);
139         }
140     }
141 
brokentestCleanUpMimeDate()142     public void brokentestCleanUpMimeDate() {
143         assertNull(Utility.cleanUpMimeDate(null));
144         assertEquals("", Utility.cleanUpMimeDate(""));
145         assertEquals("abc", Utility.cleanUpMimeDate("abc"));
146         assertEquals("GMT", Utility.cleanUpMimeDate("GMT"));
147         assertEquals("0000", Utility.cleanUpMimeDate("0000"));
148         assertEquals("-0000", Utility.cleanUpMimeDate("-0000"));
149         assertEquals("+1234", Utility.cleanUpMimeDate("GMT+1234"));
150         assertEquals("-1234", Utility.cleanUpMimeDate("GMT-1234"));
151         assertEquals("gmt-1234", Utility.cleanUpMimeDate("gmt-1234"));
152         assertEquals("GMT-123", Utility.cleanUpMimeDate("GMT-123"));
153 
154         assertEquals("Thu, 10 Dec 09 15:08:08 -0700",
155                 Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 GMT-0700"));
156         assertEquals("Thu, 10 Dec 09 15:08:08 -0700",
157                 Utility.cleanUpMimeDate("Thu, 10 Dec 09 15:08:08 -0700"));
158     }
159 
160     private static class MyNewFileCreator implements NewFileCreator {
161         private final HashSet<String> mExistingFileNames;
162 
MyNewFileCreator(String... fileNames)163         public MyNewFileCreator(String... fileNames) {
164             mExistingFileNames = new HashSet<String>();
165             for (String f : fileNames) {
166                 mExistingFileNames.add(f);
167             }
168         }
169 
createNewFile(File f)170         @Override public boolean createNewFile(File f) {
171             return !mExistingFileNames.contains(f.getAbsolutePath());
172         }
173     }
174 
testCreateUniqueFile()175     public void testCreateUniqueFile() throws Exception {
176         final MyNewFileCreator noFiles = new MyNewFileCreator();
177 
178         // Case 1: Files don't exist.
179         checkCreateUniqueFile("/a", noFiles, "/", "a");
180         checkCreateUniqueFile("/a.txt", noFiles, "/", "a.txt");
181 
182         checkCreateUniqueFile("/a/b/a", noFiles, "/a/b", "a");
183         checkCreateUniqueFile("/a/b/a.txt", noFiles, "/a/b", "a.txt");
184 
185         // Case 2: Files exist already.
186         final MyNewFileCreator files = new MyNewFileCreator(
187                 "/a", "/a.txt", "/a/b/a", "/a/b/a.txt",
188                 "/a-2.txt",
189                 "/a/b/a-2", "/a/b/a-3",
190                 "/a/b/a-2.txt", "/a/b/a-3.txt", "/a/b/a-4.txt"
191                 );
192 
193         checkCreateUniqueFile("/a-2", files, "/", "a");
194         checkCreateUniqueFile("/a-3.txt", files, "/", "a.txt");
195 
196         checkCreateUniqueFile("/a/b/a-4", files, "/a/b", "a");
197         checkCreateUniqueFile("/a/b/a-5.txt", files, "/a/b", "a.txt");
198     }
199 
checkCreateUniqueFile(String expectedFileName, NewFileCreator nfc, String dir, String fileName)200     private void checkCreateUniqueFile(String expectedFileName, NewFileCreator nfc,
201             String dir, String fileName) throws Exception {
202         assertEquals(expectedFileName,
203                 Utility.createUniqueFileInternal(nfc, new File(dir), fileName).toString());
204     }
205 
206     /**
207      * Test that we have the necessary permissions to write to external storage.
208      */
testExternalStoragePermissions()209     public void testExternalStoragePermissions() throws FileNotFoundException, IOException {
210         File file = null;
211         try {
212             // If there's no storage available, this test is moot
213             if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
214                 return;
215             }
216             file = Utility.createUniqueFile(Environment.getExternalStorageDirectory(),
217                     "write-test");
218             OutputStream out = new FileOutputStream(file);
219             out.write(1);
220             out.close();
221         } finally {
222             try {
223                 if (file != null) {
224                     if (file.exists()) {
225                         file.delete();
226                     }
227                 }
228             } catch (Exception e) {
229                 // ignore cleanup error - it still throws the original
230             }
231         }
232     }
233 
testIsPortFieldValid()234     public void testIsPortFieldValid() {
235         TextView view = new TextView(getContext());
236         // null, empty, negative, and non integer strings aren't valid
237         view.setText(null);
238         assertFalse(Utility.isPortFieldValid(view));
239         view.setText("");
240         assertFalse(Utility.isPortFieldValid(view));
241         view.setText("-1");
242         assertFalse(Utility.isPortFieldValid(view));
243         view.setText("1403.75");
244         assertFalse(Utility.isPortFieldValid(view));
245         view.setText("0");
246         assertFalse(Utility.isPortFieldValid(view));
247         view.setText("65536");
248         assertFalse(Utility.isPortFieldValid(view));
249         view.setText("i'm not valid");
250         assertFalse(Utility.isPortFieldValid(view));
251         // These next values are valid
252         view.setText("1");
253         assertTrue(Utility.isPortFieldValid(view));
254         view.setText("65535");
255         assertTrue(Utility.isPortFieldValid(view));
256     }
257 
testToPrimitiveLongArray()258     public void testToPrimitiveLongArray() {
259         assertEquals(0, Utility.toPrimitiveLongArray(createLongCollection()).length);
260 
261         final long[] one = Utility.toPrimitiveLongArray(createLongCollection(1));
262         assertEquals(1, one.length);
263         assertEquals(1, one[0]);
264 
265         final long[] two = Utility.toPrimitiveLongArray(createLongCollection(3, 4));
266         assertEquals(2, two.length);
267         assertEquals(3, two[0]);
268         assertEquals(4, two[1]);
269     }
270 
testToLongSet()271     public void testToLongSet() {
272         assertEquals(0, Utility.toLongSet(new long[] {}).size());
273 
274         final Set<Long> one = Utility.toLongSet(new long[] {1});
275         assertEquals(1, one.size());
276         assertTrue(one.contains(1L));
277 
278         final Set<Long> two = Utility.toLongSet(new long[] {1, 2});
279         assertEquals(2, two.size());
280         assertTrue(two.contains(1L));
281         assertTrue(two.contains(2L));
282     }
283 
testGetContentFileName()284     public void testGetContentFileName() throws Exception {
285         Context providerContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
286                 mContext);
287 
288         final long ACCOUNT_ID = 1;
289         final long MESSAGE_ID = 10;
290 
291         Account account = ProviderTestUtils.setupAccount("account", true, providerContext);
292         Mailbox mailbox = ProviderTestUtils.setupMailbox("box", account.mId, true, providerContext);
293 
294         // Set up an attachment.
295         Attachment att = ProviderTestUtils.setupAttachment(mailbox.mId, "name", 123, true,
296                 providerContext);
297         long attachmentId = att.mId;
298         Uri uri = AttachmentUtilities.getAttachmentUri(account.mId, attachmentId);
299 
300         // Case 1: exists in the provider.
301         assertEquals("name", Utility.getContentFileName(providerContext, uri));
302 
303         // Case 2: doesn't exist in the provider
304         Uri notExistUri = AttachmentUtilities.getAttachmentUri(account.mId, 123456789);
305         String lastPathSegment = notExistUri.getLastPathSegment();
306         assertEquals(lastPathSegment, Utility.getContentFileName(providerContext, notExistUri));
307     }
308 
309     // used by testToPrimitiveLongArray
createLongCollection(long... values)310     private static Collection<Long> createLongCollection(long... values) {
311         ArrayList<Long> ret = new ArrayList<Long>();
312         for (long value : values) {
313             ret.add(value);
314         }
315         return ret;
316     }
317 
testDumpCursor()318     public void testDumpCursor() {
319         // Just make sure the method won't crash and returns non-empty string.
320         final Cursor c1 = new MatrixCursorWithCachedColumns(new String[] {"col"});
321         final Cursor c2 = new CursorWrapper(c1);
322 
323         // Note it's a subclass of CursorWrapper.
324         final Cursor c3 = new CursorWrapper(c2) {
325         };
326 
327         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c1)));
328         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c2)));
329         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c3)));
330         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(null)));
331 
332         // Test again with closed cursor.
333         c1.close();
334         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c1)));
335         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c2)));
336         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(c3)));
337         assertFalse(TextUtils.isEmpty(Utility.dumpCursor(null)));
338     }
339 
testCloseTraceCursorWrapper()340     public void testCloseTraceCursorWrapper() {
341         final Cursor org = new MatrixCursorWithCachedColumns(new String[] {"col"});
342         final Utility.CloseTraceCursorWrapper c =
343                 Utility.CloseTraceCursorWrapper.alwaysCreateForTest(org);
344 
345         // Not closed -- no stack trace
346         assertNull(Utility.CloseTraceCursorWrapper.getTraceIfAvailable(c));
347         Utility.CloseTraceCursorWrapper.log(c); // shouldn't crash
348 
349         // Close, now stack trace should be available
350         c.close();
351         assertNotNull(Utility.CloseTraceCursorWrapper.getTraceIfAvailable(c));
352         Utility.CloseTraceCursorWrapper.log(c);
353 
354         // shouldn't crash
355         Utility.CloseTraceCursorWrapper.log(null);
356     }
357 
brokentestAppendBold()358     public void brokentestAppendBold() {
359         SpannableStringBuilder ssb = new SpannableStringBuilder();
360         ssb.append("no");
361 
362         assertEquals(ssb, Utility.appendBold(ssb, "BO"));
363 
364         assertEquals("noBO", ssb.toString());
365         // TODO check style -- but how?
366     }
367 
testAreStringsEqual()368     public void testAreStringsEqual() {
369         String s1;
370         String s2;
371 
372         s1 = new String("Foo");
373         s2 = s1;
374         assertTrue(Utility.areStringsEqual(s1, s2));
375 
376         s2 = new String("Foo");
377         assertTrue(Utility.areStringsEqual(s1, s2));
378 
379         s2 = "Bar";
380         assertFalse(Utility.areStringsEqual(s1, s2));
381 
382         s2 = null;
383         assertFalse(Utility.areStringsEqual(s1, s2));
384 
385         s1 = null;
386         s2 = "Bar";
387         assertFalse(Utility.areStringsEqual(s1, s2));
388 
389         s1 = null;
390         s2 = null;
391         assertTrue(Utility.areStringsEqual(s1, s2));
392     }
393 
testIsServerNameValid()394     public void testIsServerNameValid() {
395         assertTrue(Utility.isServerNameValid("a"));
396         assertTrue(Utility.isServerNameValid("gmail"));
397         assertTrue(Utility.isServerNameValid("gmail.com"));
398         assertTrue(Utility.isServerNameValid("gmail.com.x.y.z"));
399         assertTrue(Utility.isServerNameValid("  gmail.com.x.y.z  "));
400 
401         assertFalse(Utility.isServerNameValid(""));
402         assertFalse(Utility.isServerNameValid("$"));
403         assertFalse(Utility.isServerNameValid("  "));
404     }
405 
toColleciton(long... values)406     private static Collection<Long> toColleciton(long... values) {
407         ArrayList<Long> ret = new ArrayList<Long>();
408         for (long v : values) {
409             ret.add(v);
410         }
411         return ret;
412     }
413 
brokentestBuildInSelection()414     public void brokentestBuildInSelection() {
415         assertEquals("", Utility.buildInSelection("c", null));
416         assertEquals("", Utility.buildInSelection("c", toColleciton()));
417         assertEquals("c in (1)", Utility.buildInSelection("c", toColleciton(1)));
418         assertEquals("c in (1,2)", Utility.buildInSelection("c", toColleciton(1, 2)));
419         assertEquals("c in (1,2,-500)", Utility.buildInSelection("c", toColleciton(1, 2, -500)));
420     }
421 }
422