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 android.os;
18
19import static android.text.format.DateUtils.DAY_IN_MILLIS;
20import static android.text.format.DateUtils.HOUR_IN_MILLIS;
21import static android.text.format.DateUtils.WEEK_IN_MILLIS;
22
23import android.content.Context;
24import android.test.AndroidTestCase;
25import android.test.suitebuilder.annotation.MediumTest;
26
27import com.google.android.collect.Sets;
28
29import libcore.io.IoUtils;
30
31import java.io.ByteArrayInputStream;
32import java.io.File;
33import java.io.FileOutputStream;
34import java.io.FileWriter;
35import java.util.Arrays;
36import java.util.HashSet;
37
38@MediumTest
39public class FileUtilsTest extends AndroidTestCase {
40    private static final String TEST_DATA =
41            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
42
43    private File mDir;
44    private File mTestFile;
45    private File mCopyFile;
46
47    @Override
48    protected void setUp() throws Exception {
49        super.setUp();
50        mDir = getContext().getDir("testing", Context.MODE_PRIVATE);
51        mTestFile = new File(mDir, "test.file");
52        mCopyFile = new File(mDir, "copy.file");
53    }
54
55    @Override
56    protected void tearDown() throws Exception {
57        IoUtils.deleteContents(mDir);
58    }
59
60    // TODO: test setPermissions(), getPermissions()
61
62    public void testCopyFile() throws Exception {
63        stageFile(mTestFile, TEST_DATA);
64        assertFalse(mCopyFile.exists());
65        FileUtils.copyFile(mTestFile, mCopyFile);
66        assertTrue(mCopyFile.exists());
67        assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null));
68    }
69
70    public void testCopyToFile() throws Exception {
71        final String s = "Foo Bar";
72        assertFalse(mCopyFile.exists());
73        FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile);
74        assertTrue(mCopyFile.exists());
75        assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null));
76    }
77
78    public void testIsFilenameSafe() throws Exception {
79        assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
80        assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
81        assertFalse(FileUtils.isFilenameSafe(new File("foo*bar")));
82        assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar")));
83    }
84
85    public void testReadTextFile() throws Exception {
86        stageFile(mTestFile, TEST_DATA);
87
88        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null));
89
90        assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null));
91        assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>"));
92        assertEquals(TEST_DATA.substring(0, 51) + "<>",
93                FileUtils.readTextFile(mTestFile, 51, "<>"));
94        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>"));
95        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>"));
96
97        assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null));
98        assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>"));
99        assertEquals("<>" + TEST_DATA.substring(1, 52),
100                FileUtils.readTextFile(mTestFile, -51, "<>"));
101        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>"));
102        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>"));
103    }
104
105    public void testReadTextFileWithZeroLengthFile() throws Exception {
106        stageFile(mTestFile, TEST_DATA);
107        new FileOutputStream(mTestFile).close();  // Zero out the file
108        assertEquals("", FileUtils.readTextFile(mTestFile, 0, null));
109        assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>"));
110        assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>"));
111        assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>"));
112        assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>"));
113    }
114
115    public void testContains() throws Exception {
116        assertTrue(FileUtils.contains(new File("/"), new File("/moo.txt")));
117        assertTrue(FileUtils.contains(new File("/"), new File("/")));
118
119        assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard")));
120        assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/")));
121
122        assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard/moo.txt")));
123        assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/moo.txt")));
124
125        assertFalse(FileUtils.contains(new File("/sdcard"), new File("/moo.txt")));
126        assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/moo.txt")));
127
128        assertFalse(FileUtils.contains(new File("/sdcard"), new File("/sdcard.txt")));
129        assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/sdcard.txt")));
130    }
131
132    public void testDeleteOlderEmptyDir() throws Exception {
133        FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS);
134        assertDirContents();
135    }
136
137    public void testDeleteOlderTypical() throws Exception {
138        touch("file1", HOUR_IN_MILLIS);
139        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
140        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
141        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
142        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
143        assertTrue(FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS));
144        assertDirContents("file1", "file2", "file3");
145    }
146
147    public void testDeleteOlderInFuture() throws Exception {
148        touch("file1", -HOUR_IN_MILLIS);
149        touch("file2", HOUR_IN_MILLIS);
150        touch("file3", WEEK_IN_MILLIS);
151        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
152        assertDirContents("file1", "file2");
153
154        touch("file1", -HOUR_IN_MILLIS);
155        touch("file2", HOUR_IN_MILLIS);
156        touch("file3", WEEK_IN_MILLIS);
157        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
158        assertDirContents("file1", "file2");
159    }
160
161    public void testDeleteOlderOnlyAge() throws Exception {
162        touch("file1", HOUR_IN_MILLIS);
163        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
164        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
165        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
166        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
167        assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
168        assertFalse(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS));
169        assertDirContents("file1");
170    }
171
172    public void testDeleteOlderOnlyCount() throws Exception {
173        touch("file1", HOUR_IN_MILLIS);
174        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
175        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
176        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
177        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
178        assertTrue(FileUtils.deleteOlderFiles(mDir, 2, 0));
179        assertFalse(FileUtils.deleteOlderFiles(mDir, 2, 0));
180        assertDirContents("file1", "file2");
181    }
182
183    private void touch(String name, long age) throws Exception {
184        final File file = new File(mDir, name);
185        file.createNewFile();
186        file.setLastModified(System.currentTimeMillis() - age);
187    }
188
189    private void stageFile(File file, String data) throws Exception {
190        FileWriter writer = new FileWriter(file);
191        try {
192            writer.write(data, 0, data.length());
193        } finally {
194            writer.close();
195        }
196    }
197
198    private void assertDirContents(String... expected) {
199        final HashSet<String> expectedSet = Sets.newHashSet(expected);
200        String[] actual = mDir.list();
201        if (actual == null) actual = new String[0];
202
203        assertEquals(
204                "Expected " + Arrays.toString(expected) + " but actual " + Arrays.toString(actual),
205                expected.length, actual.length);
206        for (String actualFile : actual) {
207            assertTrue("Unexpected actual file " + actualFile, expectedSet.contains(actualFile));
208        }
209    }
210}
211