/*************************************************************************** * Copyright 2006-2016 by Christian Ihle * * contact@kouchat.net * * * * This file is part of KouChat. * * * * KouChat is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version. * * * * KouChat is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with KouChat. * * If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ package net.usikkert.kouchat.android.filetransfer; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.io.File; import java.io.IOException; import net.usikkert.kouchat.junit.ExpectedException; import net.usikkert.kouchat.util.ToolsTest; import org.fest.util.Lists; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowContentResolver; import org.robolectric.tester.android.database.SimpleTestCursor; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Environment; /** * Test of {@link AndroidFileUtils}. * * @author Christian Ihle */ @SuppressWarnings("HardCodedStringLiteral") @Config(manifest = Config.NONE) @RunWith(RobolectricTestRunner.class) public class AndroidFileUtilsTest { @Rule public ExpectedException expectedException = ExpectedException.none(); private AndroidFileUtils androidFileUtils; private ContentResolver contentResolver; private SimpleTestCursor cursor; private ShadowContentResolver shadowContentResolver; @Before public void setUp() { androidFileUtils = spy(new AndroidFileUtils()); contentResolver = Robolectric.application.getContentResolver(); shadowContentResolver = Robolectric.shadowOf(contentResolver); cursor = new SimpleTestCursor() { @Override public int getCount() { return results.length; // Not implemented in SimpleTestCursor } @Override public boolean moveToFirst() { return moveToNext(); // Not implemented in SimpleTestCursor } }; } @Test public void getFileFromUriShouldReturnNullIfUriIsNull() { assertNull(androidFileUtils.getFileFromUri(null, contentResolver)); } @Test public void getFileFromUriShouldReturnNullIfUriIsOfUnsupportedType() { assertNull(androidFileUtils.getFileFromUri(Uri.parse("ftp://ftp.google.com"), contentResolver)); } @Test public void getFileFromUriShouldReturnResultFromContentUriIfContentScheme() { final Uri uri = Uri.parse("content://contacts/photos/253"); final File tempFile = new File("tmp.txt"); when(androidFileUtils.getFileFromContentUri(uri, contentResolver)).thenReturn(tempFile); final File fileFromUri = androidFileUtils.getFileFromUri(uri, contentResolver); assertSame(tempFile, fileFromUri); verify(androidFileUtils).getFileFromContentUri(uri, contentResolver); } @Test public void getFileFromUriShouldReturnResultFromGetFromFileUriIfFileScheme() { final Uri uri = Uri.parse("file:///storage/emulated/0/kouchat-1600x1600.png"); final File tempFile = new File("tmp.txt"); when(androidFileUtils.getFileFromFileUri(uri)).thenReturn(tempFile); final File fileFromUri = androidFileUtils.getFileFromUri(uri, contentResolver); assertSame(tempFile, fileFromUri); verify(androidFileUtils).getFileFromFileUri(uri); } @Test public void getFileFromContentUriShouldThrowExceptionIfContentResolverIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("ContentResolver can not be null"); androidFileUtils.getFileFromContentUri(Uri.EMPTY, null); } @Test public void getFileFromContentUriShouldThrowExceptionIfUriIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Content uri can not be null"); assertNull(androidFileUtils.getFileFromContentUri(null, contentResolver)); } @Test public void getFileFromContentUriShouldReturnNullIfCursorIsNullAfterQuery() { shadowContentResolver.setCursor(null); assertNull(androidFileUtils.getFileFromContentUri(Uri.parse("content://contacts/photos/253"), contentResolver)); } @Test public void getFileFromContentUriShouldReturnNullIfNoResults() { shadowContentResolver.setCursor(cursor); assertNull(androidFileUtils.getFileFromContentUri(Uri.parse("content://contacts/photos/253"), contentResolver)); } @Test public void getFileFromContentUriShouldReturnFirstResult() { shadowContentResolver.setCursor(cursor); cursor.setColumnNames(Lists.newArrayList("_data")); cursor.setResults(new String[][] {{"/home/user/pictures/dsc0001.jpg", "/home/user/pictures/dsc0002.jpg"}}); final File fileFromUri = androidFileUtils.getFileFromContentUri(Uri.parse("content://contacts/photos/253"), contentResolver); assertNotNull(fileFromUri); assertEquals("dsc0001.jpg", fileFromUri.getName()); } @Test public void getFileFromFileUriShouldThrowExceptionIfUriIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("File uri can not be null"); androidFileUtils.getFileFromFileUri(null); } @Test public void getFileFromFileUriShouldReturnFileWithUriPathIfFileExists() throws IOException { final File tempFile = File.createTempFile("getFileFromFileUri", ".tmp"); assertTrue(tempFile.exists()); final Uri uri = Uri.fromFile(tempFile); assertTrue(uri.getScheme().equals("file")); final File file = androidFileUtils.getFileFromFileUri(uri); assertEquals(tempFile, file); } @Test public void getFileFromFileUriShouldReturnNullIfFileDoesNotExist() throws IOException { final Uri uri = Uri.parse("file:///storage/emulated/0/kouchat-1600x1600.png"); assertTrue(uri.getScheme().equals("file")); final File file = androidFileUtils.getFileFromFileUri(uri); assertNull(file); } @Test public void addFileToMediaDatabaseShouldThrowExceptionIfContextIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Context can not be null"); androidFileUtils.addFileToMediaDatabase(null, mock(File.class)); } @Test public void addFileToMediaDatabaseShouldThrowExceptionIfFileIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("File to add can not be null"); androidFileUtils.addFileToMediaDatabase(mock(Context.class), null); } @Test public void addFileToMediaDatabaseShouldSendBroadcast() { final Context context = Robolectric.application; final File file = new File("kouchat.png"); // Hack around the fact that this needs to final in order to be modified from an anonymous class final boolean[] broadcastReceived = {false}; final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { assertEquals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, intent.getAction()); assertEquals(Uri.fromFile(file), intent.getData()); broadcastReceived[0] = true; } }; final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); context.registerReceiver(broadcastReceiver, intentFilter); androidFileUtils.addFileToMediaDatabase(context, file); assertTrue(broadcastReceived[0]); } @Test public void createFileInDownloadsWithAvailableNameShouldThrowExceptionIfNameIsNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("File name can not be empty"); androidFileUtils.createFileInDownloadsWithAvailableName(null); } @Test public void createFileInDownloadsWithAvailableNameShouldThrowExceptionIfNameIsEmpty() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("File name can not be empty"); androidFileUtils.createFileInDownloadsWithAvailableName(" "); } @Test public void createFileInDownloadsWithAvailableNameShouldKeepFileNameAndUseDownloadDirectory() { final File file = androidFileUtils.createFileInDownloadsWithAvailableName("file.txt"); assertNotNull(file); assertFalse(file.exists()); assertEquals("file.txt", file.getName()); assertEquals(getDownloadsDirectory().getAbsolutePath(), file.getParent()); } @Test public void createFileInDownloadsWithAvailableNameShouldCreateMissingDirectoryStructure() { // Note: this test doesn't actually verify anything, because Robolectric creates the directory structure // before my code (unlike real Android). I don't know how to avoid that. Keeping the test anyway. final File downloadsDirectory = getDownloadsDirectory(); // Just trying to make sure this is an actual temporary directory before it's deleted. // Example: /tmp/android-external-files744975316838robolectric/e12c13f2-1135-4519/Download assertTrue(downloadsDirectory.getAbsolutePath().matches(".+android-external-files.+robolectric.+Download")); assertTrue(downloadsDirectory.delete()); assertFalse(downloadsDirectory.exists()); final File file = androidFileUtils.createFileInDownloadsWithAvailableName("file.txt"); assertNotNull(file); assertFalse(file.exists()); assertTrue(downloadsDirectory.exists()); } @Test public void createFileInDownloadsWithAvailableNameShouldIncrementFileNameIfFileAlreadyExists() throws IOException { final File existingFile = new File(getDownloadsDirectory(), "file.txt"); ToolsTest.createTemporaryFile(existingFile); final File file = androidFileUtils.createFileInDownloadsWithAvailableName("file.txt"); assertNotNull(file); assertFalse(file.exists()); assertEquals("file_1.txt", file.getName()); } private File getDownloadsDirectory() { return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); } }