diff --git a/app/build.gradle b/app/build.gradle index 072f82aefa..eac446cdba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -80,12 +80,13 @@ android { testOptions { unitTests { includeAndroidResources = true + returnDefaultValues = true } } } ext { - robolectricVersion = '3.8' + robolectricVersion = '4.3.1' glideVersion = '4.11.0' sshjVersion = '0.26.0' jcifsVersion = '2.1.3' @@ -93,6 +94,11 @@ ext { roomVersion = '2.2.5' bouncyCastleVersion = '1.65' awaitilityVersion = "3.1.6" + androidXTestVersion = "1.2.0" + junitVersion = "4.13" + slf4jVersion = "1.7.25" + mockitoVersion = "3.4.4" + androidBillingVersion = "2.1.0" } dependencies { @@ -106,23 +112,30 @@ dependencies { implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.cardview:cardview:1.0.0' implementation "androidx.room:room-runtime:$roomVersion" + implementation "com.android.billingclient:billing:$androidBillingVersion" annotationProcessor "androidx.room:room-compiler:$roomVersion" - implementation 'com.android.billingclient:billing:2.1.0' annotationProcessor 'androidx.annotation:annotation:1.1.0' //For tests - androidTestImplementation 'junit:junit:4.12'//tests the app logic - testImplementation 'junit:junit:4.12'//tests the app logic + testImplementation "junit:junit:$junitVersion"//tests the app logic testImplementation "org.robolectric:robolectric:$robolectricVersion"//tests android interaction testImplementation "org.robolectric:shadows-httpclient:$robolectricVersion"//tests android interaction - + testImplementation "androidx.test:core:$androidXTestVersion" + testImplementation "androidx.test:runner:$androidXTestVersion" + testImplementation "androidx.test:rules:$androidXTestVersion" + testImplementation 'androidx.test.ext:junit:1.1.1' + //testImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' + testImplementation "org.mockito:mockito-core:$mockitoVersion" testImplementation "org.apache.sshd:sshd-core:1.7.0" testImplementation "org.awaitility:awaitility:$awaitilityVersion" + testImplementation 'org.jsoup:jsoup:1.11.2' + testAnnotationProcessor "com.google.auto.service:auto-service:1.0-rc4" + androidTestImplementation "junit:junit:$junitVersion"//tests the app logic androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - debugImplementation 'androidx.test:runner:1.2.0' - androidTestImplementation 'androidx.test:rules:1.2.0' - androidTestImplementation 'androidx.annotation:annotation:1.1.0' + androidTestImplementation "androidx.test:core:$androidXTestVersion" + androidTestImplementation "androidx.test:runner:$androidXTestVersion" + androidTestImplementation "androidx.test:rules:$androidXTestVersion" androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'commons-net:commons-net:3.6' androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion" @@ -143,22 +156,15 @@ dependencies { implementation 'com.afollestad.material-dialogs:core:0.9.6.0' implementation 'com.afollestad.material-dialogs:commons:0.9.6.0' - //FTP Server - /* - implementation 'org.apache.mina:mina-core:2.0.13' - implementation 'org.apache.ftpserver:ftpserver-core:1.0.6' - implementation 'org.apache.ftpserver:ftplet-api:1.0.6' - */ - // https://mvnrepository.com/artifact/org.apache.mina/mina-core implementation group: 'org.apache.mina', name: 'mina-core', version: '2.0.16' // https://mvnrepository.com/artifact/org.slf4j/slf4j-api - implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25' + implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion // https://mvnrepository.com/artifact/org.slf4j/slf4j-simple - implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.25' + implementation group: 'org.slf4j', name: 'slf4j-android', version: slf4jVersion // https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j - implementation group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.25' + implementation group: 'org.slf4j', name: 'jcl-over-slf4j', version: slf4jVersion //implementation files('libs/ftplet-api-1.1.0-SNAPSHOT.jar') // https://mvnrepository.com/artifact/org.apache.ftpserver/ftplet-api @@ -183,13 +189,12 @@ dependencies { //SFTP implementation "com.hierynomus:sshj:$sshjVersion" + //smb implementation "eu.agno3.jcifs:jcifs-ng:$jcifsVersion" implementation "org.bouncycastle:bcpkix-jdk15on:$bouncyCastleVersion" implementation "org.bouncycastle:bcprov-jdk15on:$bouncyCastleVersion" - implementation "eu.agno3.jcifs:jcifs-ng:$jcifsVersion" - //Glide: loads icons seemlessly implementation "com.github.bumptech.glide:glide:$glideVersion" implementation ("com.github.bumptech.glide:recyclerview-integration:$glideVersion") { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d1923c7c71..d337a140fb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,7 +56,7 @@ android:label="@string/appbar_name" android:launchMode="singleInstance" android:name=".ui.activities.MainActivity" - android:theme="@style/appCompatLight"> + android:theme="@android:style/Theme.Translucent.NoTitleBar"> diff --git a/app/src/main/java/com/amaze/filemanager/adapters/data/StorageDirectoryParcelable.java b/app/src/main/java/com/amaze/filemanager/adapters/data/StorageDirectoryParcelable.java index 846ac22832..6cdd6e069b 100644 --- a/app/src/main/java/com/amaze/filemanager/adapters/data/StorageDirectoryParcelable.java +++ b/app/src/main/java/com/amaze/filemanager/adapters/data/StorageDirectoryParcelable.java @@ -28,17 +28,17 @@ /** Identifies a mounted volume */ public class StorageDirectoryParcelable implements Parcelable { - public final String path; - public final String name; + @NonNull public final String path; + @NonNull public final String name; public final @DrawableRes int iconRes; - public StorageDirectoryParcelable(String path, String name, int iconRes) { + public StorageDirectoryParcelable(@NonNull String path, @NonNull String name, int iconRes) { this.path = path; this.name = name; this.iconRes = iconRes; } - public StorageDirectoryParcelable(Parcel im) { + public StorageDirectoryParcelable(@NonNull Parcel im) { path = im.readString(); name = im.readString(); iconRes = im.readInt(); diff --git a/app/src/main/java/com/amaze/filemanager/application/AppConfig.java b/app/src/main/java/com/amaze/filemanager/application/AppConfig.java index da79e231e4..2ef2746d19 100644 --- a/app/src/main/java/com/amaze/filemanager/application/AppConfig.java +++ b/app/src/main/java/com/amaze/filemanager/application/AppConfig.java @@ -87,12 +87,11 @@ public void onCreate() { utilsProvider = new UtilitiesProvider(this); utilsHandler = new UtilsHandler(this, utilitiesDatabase); - // FIXME: in unit tests when AppConfig is rapidly created/destroyed this call will cause - // IllegalThreadStateException. - // Until this gets fixed only one test case can be run in a time. - Raymond, 24/4/2018 backgroundHandlerThread.start(); backgroundHandler = new Handler(backgroundHandlerThread.getLooper()); + runInBackground(jcifs.Config::registerSmbURLHandler); + // disabling file exposure method check for api n+ StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); @@ -179,11 +178,7 @@ public static void toast(Context context, @StringRes int message) { final Context c = context; final @StringRes int m = message; - ((AppConfig) context) - .runInApplicationThread( - () -> { - Toast.makeText(c, m, Toast.LENGTH_LONG).show(); - }); + getInstance().runInApplicationThread(() -> Toast.makeText(c, m, Toast.LENGTH_LONG).show()); } } @@ -207,11 +202,7 @@ public static void toast(Context context, String message) { final Context c = context; final String m = message; - ((AppConfig) context) - .runInApplicationThread( - () -> { - Toast.makeText(c, m, Toast.LENGTH_LONG).show(); - }); + getInstance().runInApplicationThread(() -> Toast.makeText(c, m, Toast.LENGTH_LONG).show()); } } diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTask.java index 943d125d5d..a4a3d79e6e 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTask.java @@ -52,7 +52,7 @@ public DbViewerTask( this.dbViewerFragment = dbViewerFragment; stringBuilder = new StringBuilder(); - webView.getSettings().setDefaultTextEncodingName("utf-8"); + this.webView.getSettings().setDefaultTextEncodingName("utf-8"); } @Override @@ -62,10 +62,10 @@ protected void onPreExecute() { if (dbViewerFragment.databaseViewerActivity.getAppTheme().equals(AppTheme.DARK) || dbViewerFragment.databaseViewerActivity.getAppTheme().equals(AppTheme.BLACK)) { - htmlInit = "" + ""; + htmlInit = "
"; } else { - htmlInit = "" + "
"; + htmlInit = "
"; } stringBuilder.append(htmlInit); dbViewerFragment.loadingText.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java index 60193fbcfc..a4c9fd736c 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/LoadFilesListTask.java @@ -55,6 +55,8 @@ import android.provider.MediaStore; import android.text.format.Formatter; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.util.Pair; import jcifs.smb.SmbAuthException; @@ -299,72 +301,42 @@ private LayoutElementParcelable createListParcelables(HybridFileParcelable baseF } private ArrayList listImages() { - ArrayList images = new ArrayList<>(); final String[] projection = {MediaStore.Images.Media.DATA}; - final Cursor cursor = - context - .getContentResolver() - .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null); - if (cursor == null) return images; - else if (cursor.getCount() > 0 && cursor.moveToFirst()) { - do { - String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); - HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles); - if (strings != null) { - LayoutElementParcelable parcelable = createListParcelables(strings); - if (parcelable != null) images.add(parcelable); - } - } while (cursor.moveToNext()); - } - cursor.close(); - return images; + return listMediaCommon(projection, null); } private ArrayList listVideos() { - ArrayList videos = new ArrayList<>(); - final String[] projection = {MediaStore.Images.Media.DATA}; - final Cursor cursor = - context - .getContentResolver() - .query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null); - if (cursor == null) return videos; - else if (cursor.getCount() > 0 && cursor.moveToFirst()) { - do { - String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); - HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles); - if (strings != null) { - LayoutElementParcelable parcelable = createListParcelables(strings); - if (parcelable != null) videos.add(parcelable); - } - } while (cursor.moveToNext()); - } - cursor.close(); - return videos; + final String[] projection = {MediaStore.Video.Media.DATA}; + return listMediaCommon(projection, null); } private ArrayList listaudio() { String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0"; String[] projection = {MediaStore.Audio.Media.DATA}; + return listMediaCommon(projection, selection); + } + private @NonNull ArrayList listMediaCommon( + @NonNull String[] projection, @Nullable String selection) { Cursor cursor = context .getContentResolver() .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null); - ArrayList songs = new ArrayList<>(); - if (cursor == null) return songs; + ArrayList retval = new ArrayList<>(); + if (cursor == null) return retval; else if (cursor.getCount() > 0 && cursor.moveToFirst()) { do { String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); HybridFileParcelable strings = RootHelper.generateBaseFile(new File(path), showHiddenFiles); if (strings != null) { LayoutElementParcelable parcelable = createListParcelables(strings); - if (parcelable != null) songs.add(parcelable); + if (parcelable != null) retval.add(parcelable); } } while (cursor.moveToNext()); } cursor.close(); - return songs; + return retval; } private ArrayList listDocs() { diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/PrepareCopyTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/PrepareCopyTask.java index fbab9b63cf..dbcf4a94cd 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/PrepareCopyTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/PrepareCopyTask.java @@ -239,7 +239,7 @@ private void showDialog( final MaterialDialog dialog = dialogBuilder.build(); dialog.show(); - if (filesToCopy.get(0).getParent().equals(path)) { + if (filesToCopy.get(0).getParent(context).equals(path)) { View negative = dialog.getActionButton(DialogAction.NEGATIVE); negative.setEnabled(false); } diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/ReadFileTask.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/ReadFileTask.java index 0e3967a46b..5831a82fc3 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/ReadFileTask.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/ReadFileTask.java @@ -74,13 +74,13 @@ protected ReturnedValues doInBackground(Void... params) { InputStream inputStream = null; switch (fileAbstraction.scheme) { - case EditableFileAbstraction.SCHEME_CONTENT: + case CONTENT: if (fileAbstraction.uri == null) throw new NullPointerException("Something went really wrong!"); inputStream = contentResolver.openInputStream(fileAbstraction.uri); break; - case EditableFileAbstraction.SCHEME_FILE: + case FILE: final HybridFileParcelable hybridFileParcelable = fileAbstraction.hybridFileParcelable; if (hybridFileParcelable == null) throw new NullPointerException("Something went really wrong!"); diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstraction.java b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstraction.java index ff72be125f..3470e6ffc1 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstraction.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstraction.java @@ -79,7 +79,7 @@ protected Integer doInBackground(Void... voids) { OutputStream outputStream; switch (fileAbstraction.scheme) { - case EditableFileAbstraction.SCHEME_CONTENT: + case CONTENT: if (fileAbstraction.uri == null) throw new NullPointerException("Something went really wrong!"); @@ -90,7 +90,7 @@ protected Integer doInBackground(Void... voids) { } break; - case EditableFileAbstraction.SCHEME_FILE: + case FILE: final HybridFileParcelable hybridFileParcelable = fileAbstraction.hybridFileParcelable; if (hybridFileParcelable == null) throw new NullPointerException("Something went really wrong!"); diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java b/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java index 0db9a59752..e71c626fa6 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/services/CopyService.java @@ -535,7 +535,7 @@ boolean checkFiles(HybridFile hFile1, HybridFile hFile2) throws ShellNotRunningE return RootHelper.fileExists(hFile2.getPath()); } else { ArrayList baseFiles = - RootHelper.getFilesList(hFile1.getParent(), true, true, null); + RootHelper.getFilesList(hFile1.getParent(c), true, true, null); int i = -1; int index = -1; for (HybridFileParcelable b : baseFiles) { @@ -546,7 +546,7 @@ boolean checkFiles(HybridFile hFile1, HybridFile hFile2) throws ShellNotRunningE } } ArrayList baseFiles1 = - RootHelper.getFilesList(hFile1.getParent(), true, true, null); + RootHelper.getFilesList(hFile1.getParent(c), true, true, null); int i1 = -1; int index1 = -1; for (HybridFileParcelable b : baseFiles1) { diff --git a/app/src/main/java/com/amaze/filemanager/database/UtilsHandler.java b/app/src/main/java/com/amaze/filemanager/database/UtilsHandler.java index b4785fd8db..cbfa7b3523 100644 --- a/app/src/main/java/com/amaze/filemanager/database/UtilsHandler.java +++ b/app/src/main/java/com/amaze/filemanager/database/UtilsHandler.java @@ -58,6 +58,8 @@ */ public class UtilsHandler { + private static final String TAG = UtilsHandler.class.getSimpleName(); + private final Context context; private final UtilitiesDatabase utilitiesDatabase; @@ -155,15 +157,15 @@ public void removeFromDatabase(OperationData operationData) { } public void addCommonBookmarks() { - String sd = Environment.getExternalStorageDirectory() + "/"; + File sd = Environment.getExternalStorageDirectory(); String[] dirs = new String[] { - sd + Environment.DIRECTORY_DCIM, - sd + Environment.DIRECTORY_DOWNLOADS, - sd + Environment.DIRECTORY_MOVIES, - sd + Environment.DIRECTORY_MUSIC, - sd + Environment.DIRECTORY_PICTURES + new File(sd, Environment.DIRECTORY_DCIM).getAbsolutePath(), + new File(sd, Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(), + new File(sd, Environment.DIRECTORY_MOVIES).getAbsolutePath(), + new File(sd, Environment.DIRECTORY_MUSIC).getAbsolutePath(), + new File(sd, Environment.DIRECTORY_PICTURES).getAbsolutePath() }; for (String dir : dirs) { @@ -313,6 +315,13 @@ public void renameBookmark(String oldName, String oldPath, String newName, Strin } public void renameSMB(String oldName, String oldPath, String newName, String newPath) { + try { + oldPath = SmbUtil.getSmbEncryptedPath(AppConfig.getInstance(), oldPath); + newPath = SmbUtil.getSmbEncryptedPath(AppConfig.getInstance(), newPath); + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Error encrypting SMB path", e); + } + SmbEntry smbEntry = utilitiesDatabase.smbEntryDao().findByNameAndPath(oldName, oldPath); smbEntry.name = newName; smbEntry.path = newPath; diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/EditableFileAbstraction.java b/app/src/main/java/com/amaze/filemanager/filesystem/EditableFileAbstraction.java index f411ca033c..62c8ac9c12 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/EditableFileAbstraction.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/EditableFileAbstraction.java @@ -20,6 +20,9 @@ package com.amaze.filemanager.filesystem; +import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.CONTENT; +import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.FILE; + import com.amaze.filemanager.utils.Utils; import android.content.Context; @@ -27,6 +30,8 @@ import android.net.Uri; import android.provider.OpenableColumns; +import androidx.annotation.NonNull; + /** * This is a special representation of a file that is to be used so that uris can be loaded as * editable files. @@ -35,19 +40,21 @@ */ public class EditableFileAbstraction { - public static final int SCHEME_CONTENT = 0; - public static final int SCHEME_FILE = 1; + public enum Scheme { + CONTENT, + FILE + } public final Uri uri; public final String name; - public final int scheme; + public final Scheme scheme; public final HybridFileParcelable hybridFileParcelable; - public EditableFileAbstraction(Context context, Uri uri) { + public EditableFileAbstraction(@NonNull Context context, @NonNull Uri uri) { switch (uri.getScheme()) { case "content": this.uri = uri; - this.scheme = SCHEME_CONTENT; + this.scheme = CONTENT; String tempName = null; Cursor c = @@ -79,7 +86,7 @@ public EditableFileAbstraction(Context context, Uri uri) { this.hybridFileParcelable = null; break; case "file": - this.scheme = SCHEME_FILE; + this.scheme = FILE; String path = uri.getPath(); if (path == null) diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/FileUtil.java b/app/src/main/java/com/amaze/filemanager/filesystem/FileUtil.java index 7428f8eaa7..542607f5d2 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/FileUtil.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/FileUtil.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -278,8 +279,7 @@ public List doInBackground() { } else { OutputStream outputStream = targetSmbFile.getOutputStream(); bufferedOutputStream = new BufferedOutputStream(outputStream); - retval.add( - mainActivity.mainActivityHelper.parseSmbPath(targetSmbFile.getPath())); + retval.add(HybridFile.parseSmbPath(targetSmbFile.getPath())); } break; case SFTP: @@ -619,6 +619,31 @@ public static boolean mkfile(final File file, Context context) { return false; } + public static boolean mktextfile(String data, String path, String fileName) { + + File f = new File(path + "/" + fileName + ".txt"); + FileOutputStream out = null; + OutputStreamWriter outputWriter = null; + try { + f.createNewFile(); + out = new FileOutputStream(f, false); + outputWriter = new OutputStreamWriter(out); + outputWriter.write(data); + return true; + } catch (IOException io) { + Log.e(FileUtil.LOG, io.getMessage()); + return false; + } finally { + try { + outputWriter.close(); + out.flush(); + out.close(); + } catch (IOException e) { + Log.e(FileUtil.LOG, e.getMessage()); + } + } + } + /** * Delete a folder. * @@ -1170,7 +1195,7 @@ private int getTemporaryAlbumId() { } private File installTemporaryTrack() throws IOException { - File externalFilesDir = getExternalFilesDir(context); + File externalFilesDir = context.getExternalFilesDir(null); if (externalFilesDir == null) { return null; } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java index 9f9ca90189..556c2b212a 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java @@ -57,19 +57,18 @@ import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.documentfile.provider.DocumentFile; import jcifs.smb.SmbException; import jcifs.smb.SmbFile; import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.common.Buffer; -import net.schmizz.sshj.sftp.FileAttributes; import net.schmizz.sshj.sftp.FileMode; import net.schmizz.sshj.sftp.RemoteFile; import net.schmizz.sshj.sftp.RemoteResourceInfo; import net.schmizz.sshj.sftp.SFTPClient; import net.schmizz.sshj.sftp.SFTPException; -import net.schmizz.sshj.xfer.FilePermission; /** Created by Arpit on 07-07-2015. */ // Hybrid file for handeling all types of files @@ -194,6 +193,7 @@ public boolean isGoogleDriveFile() { return mode == OpenMode.GDRIVE; } + @Nullable public File getFile() { return new File(path); } @@ -210,21 +210,19 @@ HybridFileParcelable generateBaseFileFromParent() { public long lastModified() throws SmbException { switch (mode) { case SFTP: - SshClientUtils.execute( + return SshClientUtils.execute( new SFtpClientTemplate(path) { @Override - public Long execute(SFTPClient client) throws IOException { + public Long execute(@NonNull SFTPClient client) throws IOException { return client.mtime(SshClientUtils.extractRemotePathFrom(path)); } }); - break; case SMB: SmbFile smbFile = getSmbFile(); if (smbFile != null) return smbFile.lastModified(); break; case FILE: - new File(path).lastModified(); - break; + return getFile().lastModified(); case ROOT: HybridFileParcelable baseFile = generateBaseFileFromParent(); if (baseFile != null) return baseFile.getDate(); @@ -232,40 +230,8 @@ public Long execute(SFTPClient client) throws IOException { return new File("/").lastModified(); } - /** @deprecated use {@link #length(Context)} to handle content resolvers */ - public long length() { - long s = 0L; - switch (mode) { - case SFTP: - return SshClientUtils.execute( - new SFtpClientTemplate(path) { - @Override - public Long execute(SFTPClient client) throws IOException { - return client.size(SshClientUtils.extractRemotePathFrom(path)); - } - }); - case SMB: - SmbFile smbFile = getSmbFile(); - if (smbFile != null) - try { - s = smbFile.length(); - } catch (SmbException e) { - } - return s; - case FILE: - s = new File(path).length(); - return s; - case ROOT: - HybridFileParcelable baseFile = generateBaseFileFromParent(); - if (baseFile != null) return baseFile.getSize(); - break; - } - return s; - } - /** Helper method to find length */ public long length(Context context) { - long s = 0l; switch (mode) { case SFTP: @@ -279,7 +245,7 @@ public long length(Context context) { } return s; case FILE: - s = new File(path).length(); + s = getFile().length(); return s; case ROOT: HybridFileParcelable baseFile = generateBaseFileFromParent(); @@ -335,9 +301,9 @@ public String getName() { if (smbFile != null) return smbFile.getName(); break; case FILE: - return new File(path).getName(); + return getFile().getName(); case ROOT: - return new File(path).getName(); + return getFile().getName(); default: StringBuilder builder = new StringBuilder(path); name = builder.substring(builder.lastIndexOf("/") + 1, builder.length()); @@ -353,14 +319,12 @@ public String getName(Context context) { if (smbFile != null) return smbFile.getName(); break; case FILE: - return new File(path).getName(); case ROOT: - return new File(path).getName(); + return getFile().getName(); case OTG: return OTGUtil.getDocumentFile(path, context, false).getName(); default: - StringBuilder builder = new StringBuilder(path); - name = builder.substring(builder.lastIndexOf("/") + 1, builder.length()); + name = path.substring(path.lastIndexOf('/')); } return name; } @@ -393,33 +357,6 @@ public boolean isCustomPath() { || path.equals("6"); } - /** - * Returns a path to parent for various {@link #mode} - * - * @deprecated use {@link #getParent(Context)} to handle content resolvers - */ - public String getParent() { - String parentPath = ""; - switch (mode) { - case SMB: - try { - parentPath = new SmbFile(path).getParent(); - } catch (MalformedURLException e) { - parentPath = ""; - e.printStackTrace(); - } - break; - case FILE: - case ROOT: - parentPath = new File(path).getParent(); - break; - default: - StringBuilder builder = new StringBuilder(path); - return builder.substring(0, builder.length() - (getName().length() + 1)); - } - return parentPath; - } - /** Helper method to get parent path */ public String getParent(Context context) { @@ -435,7 +372,7 @@ public String getParent(Context context) { break; case FILE: case ROOT: - parentPath = new File(path).getParent(); + parentPath = getFile().getParent(); break; case OTG: default: @@ -478,7 +415,7 @@ public boolean isDirectory() { } break; case FILE: - isDirectory = new File(path).isDirectory(); + isDirectory = getFile().isDirectory(); break; case ROOT: try { @@ -494,7 +431,7 @@ public boolean isDirectory() { isDirectory = false; break; default: - isDirectory = new File(path).isDirectory(); + isDirectory = getFile().isDirectory(); break; } return isDirectory; @@ -531,7 +468,7 @@ public Boolean execute(SFTPClient client) throws IOException { } break; case FILE: - isDirectory = new File(path).isDirectory(); + isDirectory = getFile().isDirectory(); break; case ROOT: try { @@ -573,7 +510,7 @@ public Boolean execute(SFTPClient client) throws IOException { .getFolder(); break; default: - isDirectory = new File(path).isDirectory(); + isDirectory = getFile().isDirectory(); break; } return isDirectory; @@ -595,7 +532,7 @@ public long folderSize() { } break; case FILE: - size = FileUtils.folderSize(new File(path), null); + size = FileUtils.folderSize(getFile(), null); break; case ROOT: HybridFileParcelable baseFile = generateBaseFileFromParent(); @@ -630,7 +567,7 @@ public Long execute(SFTPClient client) throws IOException { } break; case FILE: - size = FileUtils.folderSize(new File(path), null); + size = FileUtils.folderSize(getFile(), null); break; case ROOT: HybridFileParcelable baseFile = generateBaseFileFromParent(); @@ -670,7 +607,7 @@ public long getUsableSpace() { break; case FILE: case ROOT: - size = new File(path).getUsableSpace(); + size = getFile().getUsableSpace(); break; case DROPBOX: case BOX: @@ -729,7 +666,7 @@ public long getTotal(Context context) { break; case FILE: case ROOT: - size = new File(path).getTotalSpace(); + size = getFile().getTotalSpace(); break; case DROPBOX: case BOX: @@ -786,21 +723,14 @@ public Void execute(SFTPClient client) { try { for (RemoteResourceInfo info : client.ls(SshClientUtils.extractRemotePathFrom(path))) { - boolean isDirectory = info.isDirectory(); - if (info.getAttributes().getType().equals(FileMode.Type.SYMLINK)) { - FileAttributes symlinkAttrs = client.stat(info.getPath()); - isDirectory = symlinkAttrs.getType().equals(FileMode.Type.DIRECTORY); + boolean isDirectory = false; + try { + isDirectory = SshClientUtils.isDirectory(client, info); + } catch (IOException ifBrokenSymlink) { + Log.w(TAG, "IOException checking isDirectory(): " + info.getPath()); + continue; } - HybridFileParcelable f = - new HybridFileParcelable(String.format("%s/%s", path, info.getName())); - f.setName(info.getName()); - f.setMode(OpenMode.SFTP); - f.setDirectory(isDirectory); - f.setDate(info.getAttributes().getMtime() * 1000); - f.setSize(isDirectory ? 0 : info.getAttributes().getSize()); - f.setPermission( - Integer.toString( - FilePermission.toMask(info.getAttributes().getPermissions()), 8)); + HybridFileParcelable f = new HybridFileParcelable(path, isDirectory, info); onFileFound.onFileFound(f); } } catch (IOException e) { @@ -817,12 +747,7 @@ public Void execute(SFTPClient client) { try { SmbFile smbFile = new SmbFile(path); for (SmbFile smbFile1 : smbFile.listFiles()) { - HybridFileParcelable baseFile = new HybridFileParcelable(smbFile1.getPath()); - baseFile.setName(smbFile1.getName()); - baseFile.setMode(OpenMode.SMB); - baseFile.setDirectory(smbFile1.isDirectory()); - baseFile.setDate(smbFile1.lastModified()); - baseFile.setSize(baseFile.isDirectory() ? 0 : smbFile1.length()); + HybridFileParcelable baseFile = new HybridFileParcelable(smbFile1); onFileFound.onFileFound(baseFile); } } catch (MalformedURLException | SmbException e) { @@ -867,17 +792,15 @@ public ArrayList execute(SFTPClient client) { try { for (RemoteResourceInfo info : client.ls(SshClientUtils.extractRemotePathFrom(path))) { + boolean isDirectory = false; + try { + isDirectory = SshClientUtils.isDirectory(client, info); + } catch (IOException ifBrokenSymlink) { + Log.w(TAG, "IOException checking isDirectory(): " + info.getPath()); + continue; + } HybridFileParcelable f = - new HybridFileParcelable( - String.format("%s/%s", path, info.getName())); - f.setName(info.getName()); - f.setMode(OpenMode.SFTP); - f.setDirectory(info.isDirectory()); - f.setDate(info.getAttributes().getMtime() * 1000); - f.setSize(f.isDirectory() ? 0 : info.getAttributes().getSize()); - f.setPermission( - Integer.toString( - FilePermission.toMask(info.getAttributes().getPermissions()), 8)); + new HybridFileParcelable(path, isDirectory, info); retval.add(f); } } catch (IOException e) { @@ -895,19 +818,14 @@ public ArrayList execute(SFTPClient client) { try { SmbFile smbFile = new SmbFile(path); for (SmbFile smbFile1 : smbFile.listFiles()) { - HybridFileParcelable baseFile = new HybridFileParcelable(smbFile1.getPath()); - baseFile.setName(smbFile1.getName()); - baseFile.setMode(OpenMode.SMB); - baseFile.setDirectory(smbFile1.isDirectory()); - baseFile.setDate(smbFile1.lastModified()); - baseFile.setSize(baseFile.isDirectory() ? 0 : smbFile1.length()); + HybridFileParcelable baseFile = new HybridFileParcelable(smbFile1); arrayList.add(baseFile); } } catch (MalformedURLException e) { - if (arrayList != null) arrayList.clear(); + arrayList.clear(); e.printStackTrace(); } catch (SmbException e) { - if (arrayList != null) arrayList.clear(); + arrayList.clear(); e.printStackTrace(); } break; @@ -938,12 +856,12 @@ public String getReadablePath(String path) { return path; } - String parseSftpPath(String a) { + public static String parseSftpPath(String a) { if (a.contains("@")) return "ssh://" + a.substring(a.indexOf("@") + 1, a.length()); else return a; } - String parseSmbPath(String a) { + public static String parseSmbPath(String a) { if (a.contains("@")) return "smb://" + a.substring(a.indexOf("@") + 1, a.length()); else return a; } @@ -1111,7 +1029,7 @@ public void close() throws IOException { break; default: try { - outputStream = FileUtil.getOutputStream(new File(path), context); + outputStream = FileUtil.getOutputStream(getFile(), context); } catch (Exception e) { outputStream = null; e.printStackTrace(); @@ -1155,7 +1073,7 @@ public Boolean execute(SFTPClient client) throws IOException { CloudStorage cloudStorageOneDrive = dataUtils.getAccount(OpenMode.ONEDRIVE); exists = cloudStorageOneDrive.exists(CloudUtil.stripPath(OpenMode.ONEDRIVE, path)); } else if (isLocal()) { - exists = new File(path).exists(); + exists = getFile().exists(); } else if (isRoot()) { return RootHelper.fileExists(path); } @@ -1181,7 +1099,7 @@ public boolean isSimpleFile() { && !isOtgFile() && !isCustomPath() && !android.util.Patterns.EMAIL_ADDRESS.matcher(path).matches() - && !new File(path).isDirectory() + && (getFile() != null && !getFile().isDirectory()) && !isOneDriveFile() && !isGoogleDriveFile() && !isDropBoxFile() @@ -1200,7 +1118,7 @@ public boolean setLastModified(final long date) { return false; } } - File f = new File(path); + File f = getFile(); return f.setLastModified(date); } @@ -1259,7 +1177,7 @@ public Void execute(SFTPClient client) { } catch (Exception e) { e.printStackTrace(); } - } else FileUtil.mkdir(new File(path), context); + } else FileUtil.mkdir(getFile(), context); } public boolean delete(Context context, boolean rootmode) throws ShellNotRunningException { @@ -1286,7 +1204,7 @@ public Void execute(SFTPClient client) throws IOException { setMode(OpenMode.ROOT); RootUtils.delete(getPath()); } else { - FileUtil.deleteFile(new File(path), context); + FileUtil.deleteFile(getFile(), context); } } return !exists(); @@ -1312,7 +1230,7 @@ public LayoutElementParcelable generateLayoutElement(@NonNull Context c, boolean switch (mode) { case FILE: case ROOT: - File file = new File(path); + File file = getFile(); LayoutElementParcelable layoutElement; if (isDirectory()) { diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFileParcelable.java b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFileParcelable.java index f6d2fe1f40..0c0f337627 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/HybridFileParcelable.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/HybridFileParcelable.java @@ -21,10 +21,17 @@ package com.amaze.filemanager.filesystem; import com.amaze.filemanager.utils.OpenMode; +import com.amaze.filemanager.utils.Utils; +import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import jcifs.smb.SmbException; +import jcifs.smb.SmbFile; +import net.schmizz.sshj.sftp.RemoteResourceInfo; +import net.schmizz.sshj.xfer.FilePermission; + /** Created by arpitkh996 on 11-01-2016. */ public class HybridFileParcelable extends HybridFile implements Parcelable { @@ -49,12 +56,49 @@ public HybridFileParcelable( this.permission = permission; } + /** + * Constructor for jcifs {@link SmbFile}. + * + * @param smbFile + * @throws SmbException + */ + public HybridFileParcelable(SmbFile smbFile) throws SmbException { + super(OpenMode.SMB, smbFile.getPath()); + setName(smbFile.getName()); + setDirectory(smbFile.isDirectory()); + setDate(smbFile.lastModified()); + setSize(smbFile.isDirectory() ? 0 : smbFile.length()); + } + + /** + * Constructor for sshj {@link RemoteResourceInfo}. + * + * @param path + * @param isDirectory + * @param sshFile + */ + public HybridFileParcelable(String path, boolean isDirectory, RemoteResourceInfo sshFile) { + super(OpenMode.SFTP, String.format("%s/%s", path, sshFile.getName())); + setName(sshFile.getName()); + setDirectory(isDirectory); + setDate(sshFile.getAttributes().getMtime() * 1000); + setSize(isDirectory ? 0 : sshFile.getAttributes().getSize()); + setPermission( + Integer.toString(FilePermission.toMask(sshFile.getAttributes().getPermissions()), 8)); + } + @Override public String getName() { - if (name != null && name.length() > 0) return name; + if (!Utils.isNullOrEmpty(name)) return name; else return super.getName(); } + @Override + public String getName(Context context) { + if (!Utils.isNullOrEmpty(name)) return name; + else return super.getName(context); + } + public void setName(String name) { this.name = name; } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java b/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java index b5c5e45e76..b613ebd93b 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/MediaStoreHack.java @@ -154,7 +154,7 @@ private static int getTemporaryAlbumId(final Context context) { try { temporaryTrack = installTemporaryTrack(context); } catch (final IOException ex) { - Log.w("MediaFile", "Error installing tempory track.", ex); + Log.w("MediaFile", "Error installing temporary track.", ex); return 0; } final Uri filesUri = MediaStore.Files.getContentUri("external"); diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java b/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java index 225b754b9b..647280795c 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/Operations.java @@ -133,7 +133,8 @@ protected Void doInBackground(Void... params) { DocumentFile directoryToCreate = OTGUtil.getDocumentFile(file.getPath(), context, false); if (directoryToCreate != null) errorCallBack.exists(file); - DocumentFile parentDirectory = OTGUtil.getDocumentFile(file.getParent(), context, false); + DocumentFile parentDirectory = + OTGUtil.getDocumentFile(file.getParent(context), context, false); if (parentDirectory.isDirectory()) { parentDirectory.createDirectory(file.getName(context)); errorCallBack.done(file, true); @@ -178,7 +179,7 @@ protected Void doInBackground(Void... params) { } } else { if (file.isLocal() || file.isRoot()) { - int mode = checkFolder(new File(file.getParent()), context); + int mode = checkFolder(new File(file.getParent(context)), context); if (mode == 2) { errorCallBack.launchSAF(file); return null; @@ -317,7 +318,8 @@ protected Void doInBackground(Void... params) { DocumentFile fileToCreate = OTGUtil.getDocumentFile(file.getPath(), context, false); if (fileToCreate != null) errorCallBack.exists(file); - DocumentFile parentDirectory = OTGUtil.getDocumentFile(file.getParent(), context, false); + DocumentFile parentDirectory = + OTGUtil.getDocumentFile(file.getParent(context), context, false); if (parentDirectory.isDirectory()) { parentDirectory.createFile( file.getName(context).substring(file.getName(context).lastIndexOf(".")), @@ -327,7 +329,7 @@ protected Void doInBackground(Void... params) { return null; } else { if (file.isLocal() || file.isRoot()) { - int mode = checkFolder(new File(file.getParent()), context); + int mode = checkFolder(new File(file.getParent(context)), context); if (mode == 2) { errorCallBack.launchSAF(file); return null; diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/files/FileUtils.java b/app/src/main/java/com/amaze/filemanager/filesystem/files/FileUtils.java index cd13cf4954..1c340e724b 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/files/FileUtils.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/files/FileUtils.java @@ -800,7 +800,9 @@ public static boolean isPathAccessible(String dir, SharedPreferences pref) { public static boolean isRoot( String dir) { // TODO: 5/5/2017 hardcoding root might lead to problems down the line - return !dir.contains(OTGUtil.PREFIX_OTG) && !dir.startsWith("/storage"); + return !dir.contains(OTGUtil.PREFIX_OTG) + && !dir.startsWith(OTGUtil.PREFIX_MEDIA_REMOVABLE) + && !dir.startsWith("/storage"); } /** Converts ArrayList of HybridFileParcelable to ArrayList of File */ diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/ssh/CustomSshJConfig.java b/app/src/main/java/com/amaze/filemanager/filesystem/ssh/CustomSshJConfig.java index 86e95412c6..2b7297bbce 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/ssh/CustomSshJConfig.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/ssh/CustomSshJConfig.java @@ -23,10 +23,6 @@ import java.security.Security; import net.schmizz.sshj.DefaultConfig; -import net.schmizz.sshj.signature.SignatureDSA; -import net.schmizz.sshj.signature.SignatureRSA; -import net.schmizz.sshj.transport.random.JCERandom; -import net.schmizz.sshj.transport.random.SingletonRandomFactory; /** * sshj {@link net.schmizz.sshj.Config} for our own use. @@ -44,14 +40,4 @@ public static void init() { Security.removeProvider("BC"); Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 0); } - - // don't add ECDSA - protected void initSignatureFactories() { - setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory()); - } - - @Override - protected void initRandomFactory(boolean ignored) { - setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory())); - } } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/ssh/SshClientUtils.java b/app/src/main/java/com/amaze/filemanager/filesystem/ssh/SshClientUtils.java index 55291b4898..b8f3d8c470 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/ssh/SshClientUtils.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/ssh/SshClientUtils.java @@ -49,6 +49,9 @@ import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.connection.channel.direct.Session; +import net.schmizz.sshj.sftp.FileAttributes; +import net.schmizz.sshj.sftp.FileMode; +import net.schmizz.sshj.sftp.RemoteResourceInfo; import net.schmizz.sshj.sftp.SFTPClient; public abstract class SshClientUtils { @@ -283,4 +286,19 @@ public static String deriveSftpPathFrom( ? String.format("ssh://%s@%s:%d", username, hostname, port) : String.format("ssh://%s:%s@%s:%d", username, password, hostname, port); } + + public static boolean isDirectory(@NonNull SFTPClient client, @NonNull RemoteResourceInfo info) + throws IOException { + boolean isDirectory = info.isDirectory(); + if (info.getAttributes().getType().equals(FileMode.Type.SYMLINK)) { + try { + FileAttributes symlinkAttrs = client.stat(info.getPath()); + isDirectory = symlinkAttrs.getType().equals(FileMode.Type.DIRECTORY); + } catch (IOException ifSymlinkIsBroken) { + Log.w(TAG, String.format("Symbolic link %s is broken, skipping", info.getPath())); + throw ifSymlinkIsBroken; + } + } + return isDirectory; + } } diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java index 2359410cc4..bf6d4ffea0 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java @@ -519,16 +519,20 @@ private void checkForExternalIntent(Intent intent) { zippath = Utils.sanitizeInput(uri.toString()); } - } else if (actionIntent.equals(Intent.ACTION_SEND) && type != null) { - // save a single file to filesystem - Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - ArrayList uris = new ArrayList<>(); - uris.add(uri); - initFabToSave(uris); - + } else if (actionIntent.equals(Intent.ACTION_SEND)) { + if (type.equals("text/plain")) { + initFabToSave(null); + } else { + // save a single file to filesystem + Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + ArrayList uris = new ArrayList<>(); + uris.add(uri); + initFabToSave(uris); + } // disable screen rotation just for convenience purpose // TODO: Support screen rotation when saving a file Utils.disableScreenRotation(this); + } else if (actionIntent.equals(Intent.ACTION_SEND_MULTIPLE) && type != null) { // save multiple files to filesystem @@ -580,6 +584,26 @@ private void initFabToSave(final ArrayList uris) { .show(); finish(); } + } else { + Bundle extras = intent.getExtras(); + String data = + extras.getString(Intent.EXTRA_SUBJECT) + + "\nURL: " + + extras.getString(Intent.EXTRA_TEXT); + String fileName = Long.toString(System.currentTimeMillis()); + AppConfig.runInBackground( + () -> + FileUtil.mktextfile( + data, getCurrentMainFragment().getCurrentPath(), fileName)); + + Toast.makeText( + MainActivity.this, + getResources().getString(R.string.saving) + + " to " + + getCurrentMainFragment().getCurrentPath(), + Toast.LENGTH_LONG) + .show(); + finish(); } }); // Ensure the FAB menu is visible @@ -1213,7 +1237,7 @@ public void onResume() { registerReceiver(mainActivityHelper.mNotificationReceiver, newFilter); registerReceiver(receiver2, new IntentFilter(TAG_INTENT_FILTER_GENERAL)); - if (SDK_INT >= Build.VERSION_CODES.KITKAT && SDK_INT < Build.VERSION_CODES.N) { + if (SDK_INT >= Build.VERSION_CODES.KITKAT) { updateUsbInformation(); } } @@ -1484,10 +1508,9 @@ protected void onActivityResult(int requestCode, int responseCode, Intent intent } else if (requestCode == REQUEST_CODE_SAF) { if (responseCode == Activity.RESULT_OK && intent.getData() != null) { // otg access - Uri usbOtgRoot = Uri.parse(intent.getData().toString()); + Uri usbOtgRoot = intent.getData(); SingletonUsbOtg.getInstance().setUsbOtgRoot(usbOtgRoot); getCurrentMainFragment().loadlist(OTGUtil.PREFIX_OTG, false, OpenMode.OTG); - drawer.closeIfNotLocked(); if (drawer.isLocked()) drawer.onDrawerClosed(); } else { @@ -2053,7 +2076,9 @@ public void onLoadFinished(Loader loader, final Cursor data) { } @Override - public void onLoaderReset(Loader loader) {} + public void onLoaderReset(Loader loader) { + // For passing code check + } private static final class FabActionListener implements SpeedDialView.OnActionSelectedListener { diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/TextEditorActivity.java b/app/src/main/java/com/amaze/filemanager/ui/activities/TextEditorActivity.java index e41f68f6c3..51f15ff510 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/TextEditorActivity.java +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/TextEditorActivity.java @@ -20,6 +20,7 @@ package com.amaze.filemanager.ui.activities; +import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.FILE; import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_COLORED_NAVIGATION; import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_TEXTEDITOR_NEWSTACK; @@ -322,7 +323,7 @@ private void load() { try { mInput.setText(data.fileContents); - if (mFile.scheme == EditableFileAbstraction.SCHEME_FILE + if (mFile.scheme.equals(FILE) && getExternalCacheDir() != null && mFile .hybridFileParcelable @@ -403,8 +404,7 @@ public boolean onOptionsItemSelected(MenuItem item) { saveFile(mInput.getText().toString()); break; case R.id.details: - if (mFile.scheme == EditableFileAbstraction.SCHEME_FILE - && mFile.hybridFileParcelable.getFile().exists()) { + if (mFile.scheme.equals(FILE) && mFile.hybridFileParcelable.getFile().exists()) { GeneralDialogCreation.showPropertiesDialogWithoutPermissions( mFile.hybridFileParcelable, this, getAppTheme()); } else { @@ -412,7 +412,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } break; case R.id.openwith: - if (mFile.scheme == EditableFileAbstraction.SCHEME_FILE) { + if (mFile.scheme.equals(FILE)) { File currentFile = mFile.hybridFileParcelable.getFile(); if (currentFile.exists()) { boolean useNewStack = getBoolean(PREFERENCE_TEXTEDITOR_NEWSTACK); diff --git a/app/src/main/java/com/amaze/filemanager/ui/colors/ColorUtils.java b/app/src/main/java/com/amaze/filemanager/ui/colors/ColorUtils.java index a310b64654..2583c2d41e 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/colors/ColorUtils.java +++ b/app/src/main/java/com/amaze/filemanager/ui/colors/ColorUtils.java @@ -59,6 +59,7 @@ public static void colorizeIcons( break; case Icons.NOT_KNOWN: background.setColor(Utils.getColor(context, R.color.generic_item)); + break; default: background.setColor(defaultColor); break; diff --git a/app/src/main/java/com/amaze/filemanager/ui/dialogs/SmbConnectDialog.java b/app/src/main/java/com/amaze/filemanager/ui/dialogs/SmbConnectDialog.java index 94196cb28c..1f2f45a8d3 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/dialogs/SmbConnectDialog.java +++ b/app/src/main/java/com/amaze/filemanager/ui/dialogs/SmbConnectDialog.java @@ -207,7 +207,6 @@ public void afterTextChanged(Editable s) { String userp = "", passp = "", ipp = "", domainp = ""; conName.setText(name); try { - jcifs.Config.registerSmbURLHandler(); URL a = new URL(path); String userinfo = a.getUserInfo(); if (userinfo != null) { diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/preference_fragments/PrefFrag.java b/app/src/main/java/com/amaze/filemanager/ui/fragments/preference_fragments/PrefFrag.java index 018c72c345..9c4db6e745 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/preference_fragments/PrefFrag.java +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/preference_fragments/PrefFrag.java @@ -164,7 +164,7 @@ public void onCreate(Bundle savedInstanceState) { masterPasswordPreference.setEnabled(false); return true; }); - } catch (NoClassDefFoundError error) { + } catch (NoClassDefFoundError | ClassCastException error) { error.printStackTrace(); // fingerprint manager class not defined in the framework diff --git a/app/src/main/java/com/amaze/filemanager/ui/notifications/NotificationConstants.java b/app/src/main/java/com/amaze/filemanager/ui/notifications/NotificationConstants.java index b723ddebb8..6a1581871f 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/notifications/NotificationConstants.java +++ b/app/src/main/java/com/amaze/filemanager/ui/notifications/NotificationConstants.java @@ -77,7 +77,7 @@ public static void setMetadata( case TYPE_FTP: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { notification.setCategory(Notification.CATEGORY_SERVICE); - notification.setVisibility(Notification.VISIBILITY_PUBLIC); + notification.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { notification.setPriority(Notification.PRIORITY_MAX); diff --git a/app/src/main/java/com/amaze/filemanager/ui/views/WarnableTextInputValidator.java b/app/src/main/java/com/amaze/filemanager/ui/views/WarnableTextInputValidator.java index cb95407130..71125c98ad 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/views/WarnableTextInputValidator.java +++ b/app/src/main/java/com/amaze/filemanager/ui/views/WarnableTextInputValidator.java @@ -34,11 +34,11 @@ public final class WarnableTextInputValidator extends SimpleTextWatcher implements View.OnFocusChangeListener, View.OnTouchListener { - private final Context mContext; - private final EditText mEditText; - private final View mButton; - private final WarnableTextInputLayout mTextInputLayout; - private final OnTextValidate mValidator; + private final Context context; + private final EditText editText; + private final View button; + private final WarnableTextInputLayout textInputLayout; + private final OnTextValidate validator; private @DrawableRes int warningDrawable, errorDrawable; public WarnableTextInputValidator( @@ -47,15 +47,15 @@ public WarnableTextInputValidator( WarnableTextInputLayout textInputLayout, View positiveButton, OnTextValidate validator) { - mContext = context; - mEditText = editText; - mEditText.setOnFocusChangeListener(this); - mEditText.addTextChangedListener(this); - mTextInputLayout = textInputLayout; - mButton = positiveButton; - mButton.setOnTouchListener(this); - mButton.setEnabled(false); - mValidator = validator; + this.context = context; + this.editText = editText; + this.editText.setOnFocusChangeListener(this); + this.editText.addTextChangedListener(this); + this.textInputLayout = textInputLayout; + button = positiveButton; + button.setOnTouchListener(this); + button.setEnabled(false); + this.validator = validator; warningDrawable = R.drawable.ic_warning_24dp; errorDrawable = R.drawable.ic_error_24dp; @@ -65,7 +65,7 @@ public WarnableTextInputValidator( public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { int state = doValidate(false); - mButton.setEnabled(state != ReturnState.STATE_ERROR); + button.setEnabled(state != ReturnState.STATE_ERROR); } } @@ -86,24 +86,24 @@ public void afterTextChanged(Editable s) { /** @return ReturnState.state */ private int doValidate(boolean onlySetWarning) { - ReturnState state = mValidator.isTextValid(mEditText.getText().toString()); + ReturnState state = validator.isTextValid(editText.getText().toString()); switch (state.state) { case ReturnState.STATE_NORMAL: - mTextInputLayout.removeError(); + textInputLayout.removeError(); setEditTextIcon(null); - mButton.setEnabled(true); + button.setEnabled(true); break; case ReturnState.STATE_ERROR: if (!onlySetWarning) { - mTextInputLayout.setError(mContext.getString(state.text)); + textInputLayout.setError(context.getString(state.text)); setEditTextIcon(errorDrawable); } - mButton.setEnabled(false); + button.setEnabled(false); break; case ReturnState.STATE_WARNING: - mTextInputLayout.setWarning(state.text); + textInputLayout.setWarning(state.text); setEditTextIcon(warningDrawable); - mButton.setEnabled(true); + button.setEnabled(true); break; } @@ -112,7 +112,7 @@ private int doValidate(boolean onlySetWarning) { private void setEditTextIcon(@DrawableRes Integer drawable) { @DrawableRes int drawableInt = drawable != null ? drawable : 0; - mEditText.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawableInt, 0); + editText.setCompoundDrawablesWithIntrinsicBounds(0, 0, drawableInt, 0); } public interface OnTextValidate { diff --git a/app/src/main/java/com/amaze/filemanager/ui/views/appbar/BottomBar.java b/app/src/main/java/com/amaze/filemanager/ui/views/appbar/BottomBar.java index ecde625110..8808cb81d0 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/views/appbar/BottomBar.java +++ b/app/src/main/java/com/amaze/filemanager/ui/views/appbar/BottomBar.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import com.amaze.filemanager.R; +import com.amaze.filemanager.filesystem.HybridFile; import com.amaze.filemanager.filesystem.files.FileUtils; import com.amaze.filemanager.ui.activities.MainActivity; import com.amaze.filemanager.ui.dialogs.GeneralDialogCreation; @@ -341,10 +342,10 @@ public void updatePath( switch (openmode) { case SFTP: - newPath = mainActivityHelper.parseSftpPath(news); + newPath = HybridFile.parseSftpPath(news); break; case SMB: - newPath = mainActivityHelper.parseSmbPath(news); + newPath = HybridFile.parseSmbPath(news); break; case OTG: newPath = mainActivityHelper.parseOTGPath(news); diff --git a/app/src/main/java/com/amaze/filemanager/ui/views/drawer/Drawer.java b/app/src/main/java/com/amaze/filemanager/ui/views/drawer/Drawer.java index e7dc335abf..33ae923492 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/views/drawer/Drawer.java +++ b/app/src/main/java/com/amaze/filemanager/ui/views/drawer/Drawer.java @@ -263,7 +263,7 @@ public void refreshDrawer() { storageDirectoryPaths.add(file); - if (file.contains(OTGUtil.PREFIX_OTG)) { + if (file.contains(OTGUtil.PREFIX_OTG) || file.startsWith(OTGUtil.PREFIX_MEDIA_REMOVABLE)) { addNewItem( menu, STORAGES_GROUP, @@ -694,7 +694,8 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) { } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && meta.path.contains(OTGUtil.PREFIX_OTG) + && (meta.path.contains(OTGUtil.PREFIX_OTG) + || meta.path.startsWith(OTGUtil.PREFIX_MEDIA_REMOVABLE)) && SingletonUsbOtg.getInstance().getUsbOtgRoot() == null) { MaterialDialog dialog = GeneralDialogCreation.showOtgSafExplanationDialog(mainActivity); dialog @@ -705,6 +706,7 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) { mainActivity.startActivityForResult(safIntent, MainActivity.REQUEST_CODE_SAF); dialog.dismiss(); }); + dialog.show(); } else { pendingPath = meta.path; closeIfNotLocked(); diff --git a/app/src/main/java/com/amaze/filemanager/utils/MainActivityHelper.java b/app/src/main/java/com/amaze/filemanager/utils/MainActivityHelper.java index 072deae523..c3cc6e70ee 100644 --- a/app/src/main/java/com/amaze/filemanager/utils/MainActivityHelper.java +++ b/app/src/main/java/com/amaze/filemanager/utils/MainActivityHelper.java @@ -453,7 +453,10 @@ public void exists(final HybridFile file) { .show(); if (ma != null && ma.getActivity() != null) { // retry with dialog prompted again - mkfile(file.getMode(), file.getParent(), ma); + mkfile( + file.getMode(), + file.getParent(mainActivity.getApplicationContext()), + ma); } }); } @@ -531,7 +534,10 @@ public void exists(final HybridFile file) { .show(); if (ma != null && ma.getActivity() != null) { // retry with dialog prompted again - mkdir(file.getMode(), file.getParent(), ma); + mkdir( + file.getMode(), + file.getParent(mainActivity.getApplicationContext()), + ma); } }); } @@ -611,20 +617,10 @@ public void extractFile(File file) { } else Toast.makeText(mainActivity, R.string.not_allowed, Toast.LENGTH_SHORT).show(); } - public String parseSftpPath(String a) { - if (a.contains("@")) return "ssh://" + a.substring(a.lastIndexOf("@") + 1, a.length()); - else return a; - } - - public String parseSmbPath(String a) { - if (a.contains("@")) return "smb://" + a.substring(a.indexOf("@") + 1, a.length()); - else return a; - } - /** Retrieve a path with {@link OTGUtil#PREFIX_OTG} as prefix */ public String parseOTGPath(String path) { if (path.contains(OTGUtil.PREFIX_OTG)) return path; - else return OTGUtil.PREFIX_OTG + path.substring(path.indexOf(":") + 1, path.length()); + else return OTGUtil.PREFIX_OTG + path.substring(path.indexOf(":") + 1); } public String parseCloudPath(OpenMode serviceType, String path) { diff --git a/app/src/main/java/com/amaze/filemanager/utils/OTGUtil.java b/app/src/main/java/com/amaze/filemanager/utils/OTGUtil.java index e3b7ae00bb..3f54730421 100644 --- a/app/src/main/java/com/amaze/filemanager/utils/OTGUtil.java +++ b/app/src/main/java/com/amaze/filemanager/utils/OTGUtil.java @@ -51,6 +51,8 @@ public class OTGUtil { public static final String PREFIX_OTG = "otg:/"; + public static final String PREFIX_MEDIA_REMOVABLE = "/mnt/media_rw"; + /** * Returns an array of list of files at a specific path in OTG * diff --git a/app/src/main/java/com/amaze/filemanager/utils/Utils.java b/app/src/main/java/com/amaze/filemanager/utils/Utils.java index fb100dd187..f83a0df6b7 100644 --- a/app/src/main/java/com/amaze/filemanager/utils/Utils.java +++ b/app/src/main/java/com/amaze/filemanager/utils/Utils.java @@ -52,6 +52,7 @@ import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.core.graphics.drawable.DrawableCompat; @@ -221,12 +222,12 @@ private static String sanitizeInputOnce(String input) { } /** Returns uri associated to specific basefile */ - public static Uri getUriForBaseFile(Context context, HybridFileParcelable baseFile) { + public static Uri getUriForBaseFile( + @NonNull Context context, @NonNull HybridFileParcelable baseFile) { switch (baseFile.getMode()) { case FILE: case ROOT: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - return FileProvider.getUriForFile( context, context.getPackageName(), new File(baseFile.getPath())); } else { @@ -340,7 +341,7 @@ public static Snackbar showThemedSnackbar( MainActivity mainActivity, CharSequence text, int length, - int actionTextId, + @StringRes int actionTextId, Runnable actionCallback) { Snackbar snackbar = Snackbar.make(mainActivity.findViewById(R.id.content_frame), text, length) diff --git a/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java b/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java new file mode 100644 index 0000000000..183375750c --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.application; + +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Field; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.shadows.ShadowToast; + +import com.amaze.filemanager.R; +import com.amaze.filemanager.ui.activities.MainActivity; +import com.bumptech.glide.Glide; +import com.bumptech.glide.MemoryCategory; + +import android.os.StrictMode; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +public class AppConfigTest { + + @After + public void tearDown() { + ShadowToast.reset(); + } + + @Test + public void testSetVmPolicyOnAppCreateHasNoFlags() throws Exception { + Field maskField = StrictMode.VmPolicy.class.getDeclaredField("mask"); + maskField.setAccessible(true); + assertEquals(0, maskField.get(StrictMode.getVmPolicy())); + } + + @Test + public void testToastWithNullContext() { + AppConfig.toast(null, R.string.ok); + assertNull(ShadowToast.getLatestToast()); + } + + @Test + public void testToastWithStringRes() { + AppConfig.toast(ApplicationProvider.getApplicationContext(), R.string.ok); + await().atMost(5, TimeUnit.SECONDS).until(() -> ShadowToast.getLatestToast() != null); + assertEquals( + ApplicationProvider.getApplicationContext().getString(R.string.ok), + ShadowToast.getTextOfLatestToast()); + } + + @Test + public void testToastWithString() { + AppConfig.toast(ApplicationProvider.getApplicationContext(), "Hello world"); + await().atMost(5, TimeUnit.SECONDS).until(() -> ShadowToast.getLatestToast() != null); + assertEquals("Hello world", ShadowToast.getTextOfLatestToast()); + } + + @Test + public void testGetImageLoader() throws Exception { + Field requestQueue = AppConfig.class.getDeclaredField("requestQueue"); + Field imageLoader = AppConfig.class.getDeclaredField("imageLoader"); + requestQueue.setAccessible(true); + imageLoader.setAccessible(true); + + assertNull(requestQueue.get(AppConfig.getInstance())); + assertNull(imageLoader.get(AppConfig.getInstance())); + + assertNotNull(AppConfig.getInstance().getImageLoader()); + } + + @Test + public void testGlideMemoryCategorySetToHigh() throws Exception { + Field memoryCategory = Glide.class.getDeclaredField("memoryCategory"); + memoryCategory.setAccessible(true); + assertEquals( + MemoryCategory.HIGH, + memoryCategory.get(Glide.get(ApplicationProvider.getApplicationContext()))); + } + + @Test + public void testGetScreenUtils() { + assertNull(AppConfig.getInstance().getScreenUtils()); + + MainActivity mock = mock(MainActivity.class); + AppConfig.getInstance().setMainActivityContext(mock); + assertNotNull(AppConfig.getInstance().getScreenUtils()); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java new file mode 100644 index 0000000000..c9c042f968 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.asynchronous.asynctasks; + +import static android.view.View.VISIBLE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.shadows.ShadowMultiDex; +import com.amaze.filemanager.ui.activities.DatabaseViewerActivity; +import com.amaze.filemanager.ui.fragments.DbViewerFragment; +import com.amaze.filemanager.ui.theme.AppTheme; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.view.View; +import android.webkit.WebView; +import android.widget.TextView; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) +public class DbViewerTaskTest { + + private WebView webView; + + @Before + public void setUp() { + webView = new WebView(ApplicationProvider.getApplicationContext()); + } + + @After + public void tearDown() { + webView.destroy(); + } + + @Test + public void testOnPreExecute() { + DbViewerFragment mock = mock(DbViewerFragment.class); + TextView loadingText = new TextView(ApplicationProvider.getApplicationContext()); + mock.loadingText = loadingText; + mock.databaseViewerActivity = mock(DatabaseViewerActivity.class); + mock.loadingText.setVisibility(View.GONE); + when(mock.databaseViewerActivity.getAppTheme()).thenReturn(AppTheme.DARK); + + DbViewerTask task = new DbViewerTask(null, null, webView, mock); + task.onPreExecute(); + assertEquals(VISIBLE, mock.loadingText.getVisibility()); + assertTrue(task.htmlInit.contains("color:#ffffff")); + assertEquals("utf-8", webView.getSettings().getDefaultTextEncodingName()); + + when(mock.databaseViewerActivity.getAppTheme()).thenReturn(AppTheme.BLACK); + task = new DbViewerTask(null, null, webView, mock); + task.onPreExecute(); + assertEquals(VISIBLE, mock.loadingText.getVisibility()); + assertTrue(task.htmlInit.contains("color:#ffffff")); + assertEquals("utf-8", webView.getSettings().getDefaultTextEncodingName()); + + when(mock.databaseViewerActivity.getAppTheme()).thenReturn(AppTheme.LIGHT); + task = new DbViewerTask(null, null, webView, mock); + task.onPreExecute(); + assertEquals(VISIBLE, mock.loadingText.getVisibility()); + assertTrue(task.htmlInit.contains("color:#000000")); + assertEquals("utf-8", webView.getSettings().getDefaultTextEncodingName()); + } + + @Test + public void testExecute() { + SQLiteDatabase sqLiteDatabase = + SQLiteDatabase.openDatabase( + "src/test/resources/test.db", null, SQLiteDatabase.OPEN_READONLY); + assertNotNull(sqLiteDatabase); + + DbViewerFragment mock = mock(DbViewerFragment.class); + TextView loadingText = new TextView(ApplicationProvider.getApplicationContext()); + mock.loadingText = loadingText; + Cursor schemaCursor = sqLiteDatabase.rawQuery("PRAGMA table_info('users');", null); + Cursor contentCursor = sqLiteDatabase.rawQuery("SELECT * FROM users", null); + + DbViewerTask task = new DbViewerTask(schemaCursor, contentCursor, webView, mock); + task.doInBackground(); + + assertNotNull(task.schemaList); + assertNotNull(task.contentList); + + // 3 columns + assertEquals(3, task.schemaList.size()); + // 4 records + assertEquals(4, task.contentList.size()); + assertEquals("4 records loaded", loadingText.getText().toString()); + + sqLiteDatabase.close(); + } + + @Test + public void testCompleteTask() { + SQLiteDatabase sqLiteDatabase = + SQLiteDatabase.openDatabase( + "src/test/resources/test.db", null, SQLiteDatabase.OPEN_READONLY); + assertNotNull(sqLiteDatabase); + + DbViewerFragment mock = mock(DbViewerFragment.class); + TextView loadingText = new TextView(ApplicationProvider.getApplicationContext()); + mock.loadingText = loadingText; + mock.databaseViewerActivity = mock(DatabaseViewerActivity.class); + mock.loadingText.setVisibility(View.GONE); + when(mock.databaseViewerActivity.getAppTheme()).thenReturn(AppTheme.DARK); + Cursor schemaCursor = sqLiteDatabase.rawQuery("PRAGMA table_info('users');", null); + Cursor contentCursor = sqLiteDatabase.rawQuery("SELECT * FROM users", null); + + DbViewerTask task = new DbViewerTask(schemaCursor, contentCursor, webView, mock); + task.onPreExecute(); + task.doInBackground(); + task.onPostExecute(null); + + assertNotNull(task.stringBuilder.toString()); + + Document html = Jsoup.parse(task.stringBuilder.toString()); + assertNotNull(html); + Elements elements = html.getElementsByTag("table"); + assertEquals(1, elements.size()); + elements = elements.get(0).getElementsByTag("tr"); + assertEquals(5, elements.size()); + Elements headerRow = elements.get(0).getElementsByTag("th"); + assertEquals(3, headerRow.size()); + + sqLiteDatabase.close(); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstractionTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstractionTest.java new file mode 100644 index 0000000000..c7093e9a64 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/WriteFileAbstractionTest.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.asynchronous.asynctasks; + +import static com.amaze.filemanager.asynchronous.asynctasks.WriteFileAbstraction.EXCEPTION_SHELL_NOT_RUNNING; +import static com.amaze.filemanager.asynchronous.asynctasks.WriteFileAbstraction.EXCEPTION_STREAM_NOT_FOUND; +import static com.amaze.filemanager.asynchronous.asynctasks.WriteFileAbstraction.NORMAL; +import static org.junit.Assert.assertEquals; +import static org.robolectric.Shadows.shadowOf; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; + +import org.apache.ftpserver.util.IoUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import com.amaze.filemanager.exceptions.ShellNotRunningException; +import com.amaze.filemanager.filesystem.EditableFileAbstraction; +import com.amaze.filemanager.filesystem.FileUtil; +import com.amaze.filemanager.shadows.ShadowMultiDex; +import com.amaze.filemanager.utils.RootUtils; + +import android.content.ContentResolver; +import android.content.Context; +import android.net.Uri; +import android.os.Environment; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) +public class WriteFileAbstractionTest { + + private static final String contents = "This is modified data"; + + @Test + public void testWriteContentUri() { + Uri uri = Uri.parse("content://com.amaze.filemanager.test/foobar.txt"); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + shadowOf(cr).registerOutputStream(uri, bout); + + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, null, false, null); + int result = task.doInBackground(); + assertEquals(NORMAL, result); + assertEquals(contents, new String(bout.toByteArray(), StandardCharsets.UTF_8)); + } + + @Test + public void testWriteFileNonRoot() throws IOException { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + Uri uri = Uri.fromFile(file); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, null, false, null); + int result = task.doInBackground(); + assertEquals(NORMAL, result); + + String verify = IoUtils.readFully(new FileInputStream(file)); + assertEquals(contents, verify); + } + + @Test + public void testWriteFileOverwriting() throws IOException { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + IoUtils.copy(new StringReader("Dummy test content"), new FileWriter(file), 1024); + Uri uri = Uri.fromFile(file); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, null, false, null); + int result = task.doInBackground(); + assertEquals(NORMAL, result); + + String verify = IoUtils.readFully(new FileInputStream(file)); + assertEquals(contents, verify); + } + + @Test + @Config(shadows = {BlockAllOutputStreamsFileUtil.class, BypassMountPartitionRootUtils.class}) + public void testWriteFileRoot() throws IOException { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + File cacheFile = File.createTempFile("test.txt", "cache"); + cacheFile.deleteOnExit(); + Uri uri = Uri.fromFile(file); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, cacheFile, true, null); + int result = task.doInBackground(); + assertEquals(NORMAL, result); + + String verify = IoUtils.readFully(new FileInputStream(file)); + assertEquals(contents, verify); + } + + @Test + @Config(shadows = {BlockAllOutputStreamsFileUtil.class}) + public void testWriteFileRootNoCacheFile() { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + Uri uri = Uri.fromFile(file); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, null, true, null); + int result = task.doInBackground(); + assertEquals(EXCEPTION_STREAM_NOT_FOUND, result); + } + + @Test + @Config(shadows = {BlockAllOutputStreamsFileUtil.class}) + public void testWriteFileRootCacheFileNotFound() { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + Uri uri = Uri.fromFile(file); + File cacheFile = new File(Environment.getExternalStorageDirectory(), "test.txt.cache"); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, cacheFile, true, null); + int result = task.doInBackground(); + assertEquals(EXCEPTION_STREAM_NOT_FOUND, result); + } + + @Test + @Config(shadows = {ShellNotRunningRootUtils.class}) + public void testWriteFileRootShellNotRunning() throws IOException { + File file = new File(Environment.getExternalStorageDirectory(), "test.txt"); + Uri uri = Uri.fromFile(file); + File cacheFile = File.createTempFile("test.txt", "cache"); + cacheFile.deleteOnExit(); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, cacheFile, true, null); + int result = task.doInBackground(); + assertEquals(EXCEPTION_SHELL_NOT_RUNNING, result); + } + + @Test(expected = IllegalArgumentException.class) + public void testWriteBogeyUri() { + Uri uri = Uri.parse("ftp://bogey.ftp/test.txt"); + Context ctx = ApplicationProvider.getApplicationContext(); + ContentResolver cr = ctx.getContentResolver(); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + shadowOf(cr).registerOutputStream(uri, bout); + + WriteFileAbstraction task = + new WriteFileAbstraction( + ctx, cr, new EditableFileAbstraction(ctx, uri), contents, null, false, null); + + task.doInBackground(); + } + + @Implements(FileUtil.class) + static class BlockAllOutputStreamsFileUtil { + + @Implementation + public static OutputStream getOutputStream(final File target, Context context) + throws FileNotFoundException { + return null; + } + } + + @Implements(RootUtils.class) + static class BypassMountPartitionRootUtils { + + @Implementation + public static void cat(String sourcePath, String destinationPath) + throws ShellNotRunningException { + try { + IoUtils.copy(new FileInputStream(sourcePath), new FileOutputStream(destinationPath), 512); + } catch (IOException e) { + throw new ShellNotRunningException(); + } + } + } + + @Implements(RootUtils.class) + static class ShellNotRunningRootUtils { + @Implementation + public static void cat(String sourcePath, String destinationPath) + throws ShellNotRunningException { + throw new ShellNotRunningException(); + } + } +} diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperTaskTest.java index e292fdc8a1..618d244e04 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperTaskTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperTaskTest.java @@ -32,23 +32,19 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowEnvironment; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.adapters.data.CompressedObjectParcelable; import com.amaze.filemanager.asynchronous.asynctasks.AsyncTaskResult; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.os.Environment; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - minSdk = 27, - maxSdk = 27) +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public abstract class AbstractCompressedHelperTaskTest { @Before diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/EncryptedZipHelperTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/EncryptedZipHelperTaskTest.java index d78bc07d2b..79efc9b532 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/EncryptedZipHelperTaskTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/EncryptedZipHelperTaskTest.java @@ -22,15 +22,15 @@ import java.io.File; -import org.robolectric.RuntimeEnvironment; - import android.os.Environment; +import androidx.test.core.app.ApplicationProvider; + public class EncryptedZipHelperTaskTest extends AbstractCompressedHelperTaskTest { protected CompressedHelperTask createTask(String relativePath) { return new ZipHelperTask( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new File(Environment.getExternalStorageDirectory(), "test-archive-encrypted.zip") .getAbsolutePath(), relativePath, diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarGzHelperTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarGzHelperTaskTest.java index 9004d6366c..f82673002a 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarGzHelperTaskTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarGzHelperTaskTest.java @@ -22,16 +22,16 @@ import java.io.File; -import org.robolectric.RuntimeEnvironment; - import android.os.Environment; +import androidx.test.core.app.ApplicationProvider; + public class TarGzHelperTaskTest extends AbstractCompressedHelperTaskTest { @Override protected CompressedHelperTask createTask(String relativePath) { return new GzipHelperTask( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new File(Environment.getExternalStorageDirectory(), "test-archive.tar.gz") .getAbsolutePath(), relativePath, diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperTaskTest.java index b78c23fa74..0914d91266 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperTaskTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperTaskTest.java @@ -22,15 +22,15 @@ import java.io.File; -import org.robolectric.RuntimeEnvironment; - import android.os.Environment; +import androidx.test.core.app.ApplicationProvider; + public class ZipHelperTaskTest extends AbstractCompressedHelperTaskTest { protected CompressedHelperTask createTask(String relativePath) { return new ZipHelperTask( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new File(Environment.getExternalStorageDirectory(), "test-archive.zip").getAbsolutePath(), relativePath, false, diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.java index d2fae6f272..d608c463d0 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.java @@ -36,13 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowEnvironment; import org.robolectric.shadows.ShadowToast; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.R; import com.amaze.filemanager.shadows.ShadowMultiDex; @@ -50,12 +47,11 @@ import android.os.Environment; import androidx.annotation.NonNull; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class ExtractServiceTest { private File zipfile1 = new File(Environment.getExternalStorageDirectory(), "zip-slip.zip"); @@ -142,7 +138,8 @@ public void tearDown() throws Exception { public void testExtractZipSlip() { performTest(zipfile1); assertEquals( - RuntimeEnvironment.application.getString(R.string.multiple_invalid_archive_entries), + ApplicationProvider.getApplicationContext() + .getString(R.string.multiple_invalid_archive_entries), ShadowToast.getTextOfLatestToast()); } @@ -150,7 +147,8 @@ public void testExtractZipSlip() { public void testExtractZipSlipWin() { performTest(zipfile2); assertEquals( - RuntimeEnvironment.application.getString(R.string.multiple_invalid_archive_entries), + ApplicationProvider.getApplicationContext() + .getString(R.string.multiple_invalid_archive_entries), ShadowToast.getTextOfLatestToast()); } @@ -236,7 +234,7 @@ public void testExtractListPasswordProtected7Zip() { private void performTest(@NonNull File archiveFile) { Intent intent = - new Intent(RuntimeEnvironment.application, ExtractService.class) + new Intent(ApplicationProvider.getApplicationContext(), ExtractService.class) .putExtra(ExtractService.KEY_PATH_ZIP, archiveFile.getAbsolutePath()) .putExtra(ExtractService.KEY_ENTRIES_ZIP, new String[0]) .putExtra( diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java new file mode 100644 index 0000000000..d216223244 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.filesystem; + +import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.CONTENT; +import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.FILE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.File; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.shadows.ShadowMultiDex; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.net.Uri; +import android.os.Environment; +import android.provider.OpenableColumns; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) +public class EditableFileAbstractionTest { + + @Test(expected = IllegalArgumentException.class) + public void testBogeyUri() { + new EditableFileAbstraction( + ApplicationProvider.getApplicationContext(), Uri.parse("https://github.com/TeamAmaze")); + } + + @Test + public void testContentUri() { + Uri uri = Uri.parse("content://com.amaze.filemanager.test/foobar/foobar.txt"); + String displayName = "foobar.txt"; + ContentResolver cr = ApplicationProvider.getApplicationContext().getContentResolver(); + ContentValues content = new ContentValues(); + content.put(OpenableColumns.DISPLAY_NAME, displayName); + cr.insert(uri, content); + + EditableFileAbstraction verify = + new EditableFileAbstraction(ApplicationProvider.getApplicationContext(), uri); + assertEquals(CONTENT, verify.scheme); + assertEquals(displayName, verify.name); + assertNull(verify.hybridFileParcelable); + assertEquals(uri, verify.uri); + } + + @Test + public void testNonExistentContentUri() { + Uri uri = Uri.parse("content://foo.bar.bogey.uri/test.txt"); + EditableFileAbstraction verify = + new EditableFileAbstraction(ApplicationProvider.getApplicationContext(), uri); + assertEquals("test.txt", verify.name); + assertNull(verify.hybridFileParcelable); + assertEquals(CONTENT, verify.scheme); + assertEquals(uri, verify.uri); + } + + @Test + public void testFileUri() { + File file = new File(Environment.getExternalStorageDirectory(), "test.odt"); + Uri uri = Uri.fromFile(file); + EditableFileAbstraction verify = + new EditableFileAbstraction(ApplicationProvider.getApplicationContext(), uri); + assertEquals("test.odt", verify.name); + assertNotNull(verify.hybridFileParcelable); + assertEquals(FILE, verify.scheme); + assertNull(verify.uri); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java index 0e9c0dc33b..871628a289 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java @@ -29,21 +29,18 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.utils.OpenMode; import android.os.Environment; -@RunWith(RobolectricTestRunner.class) -@Config( - maxSdk = 27, - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}) +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class OperationsTest { private File storageRoot = Environment.getExternalStorageDirectory(); @@ -69,7 +66,7 @@ public void testMkdir() throws InterruptedException { CountDownLatch waiter = new CountDownLatch(1); Operations.mkdir( newFolderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -89,7 +86,7 @@ public void testMkdirDuplicate() throws InterruptedException { CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( newFolderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -104,7 +101,7 @@ public void done(HybridFile hFile, boolean b) { AtomicBoolean assertFlag = new AtomicBoolean(false); Operations.mkdir( newFolderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -125,7 +122,7 @@ public void testMkdirNewFolderSameNameAsCurrentFolder() throws InterruptedExcept CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( newFolderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -141,7 +138,7 @@ public void done(HybridFile hFile, boolean b) { CountDownLatch waiter2 = new CountDownLatch(1); Operations.mkdir( newFolder2HF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -156,7 +153,7 @@ public void done(HybridFile hFile, boolean b) { AtomicBoolean assertFlag = new AtomicBoolean(false); Operations.mkdir( newFolder2HF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -179,7 +176,7 @@ public void testRename() throws InterruptedException { CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( oldFolderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -195,7 +192,7 @@ public void done(HybridFile hFile, boolean b) { oldFolderHF, newFolderHF, false, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new AbstractErrorCallback() { @Override public void done(HybridFile hFile, boolean b) { @@ -215,7 +212,7 @@ public void testRenameSameName() throws InterruptedException { CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( folderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -232,7 +229,7 @@ public void done(HybridFile hFile, boolean b) { folderHF, folderHF, false, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new AbstractErrorCallback() { @Override public void exists(HybridFile file) { @@ -253,7 +250,7 @@ public void testRenameSameName2() throws InterruptedException { CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( folderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -270,7 +267,7 @@ public void done(HybridFile hFile, boolean b) { CountDownLatch waiter2 = new CountDownLatch(1); Operations.mkdir( folder2HF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -287,7 +284,7 @@ public void done(HybridFile hFile, boolean b) { folderHF, folder2HF, false, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new AbstractErrorCallback() { @Override public void exists(HybridFile file) { @@ -308,7 +305,7 @@ public void testRenameSameName3() throws InterruptedException { CountDownLatch waiter1 = new CountDownLatch(1); Operations.mkdir( folderHF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -325,7 +322,7 @@ public void done(HybridFile hFile, boolean b) { CountDownLatch waiter2 = new CountDownLatch(1); Operations.mkdir( folder2HF, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, new AbstractErrorCallback() { @Override @@ -345,7 +342,7 @@ public void done(HybridFile hFile, boolean b) { folder2HF, folder3HF, false, - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), new AbstractErrorCallback() { @Override public void done(HybridFile file, boolean b) { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java index 7a2f1a1725..39e02c25fb 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java @@ -35,23 +35,20 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.test.ShadowShellInteractive; import com.amaze.filemanager.ui.activities.MainActivity; import android.os.Environment; +import androidx.test.ext.junit.runners.AndroidJUnit4; + import eu.chainfire.libsuperuser.Shell; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class, ShadowShellInteractive.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class, ShadowShellInteractive.class}) public class RootHelperTest { private static final File sysroot = diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/cloud/CloudStreamSourceTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/cloud/CloudStreamSourceTest.java index c5a10ee96f..abe76c114f 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/cloud/CloudStreamSourceTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/cloud/CloudStreamSourceTest.java @@ -36,20 +36,17 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.os.Environment; +import androidx.test.ext.junit.runners.AndroidJUnit4; + /** Created by Rustam Khadipash on 31/3/2018. */ -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class CloudStreamSourceTest { private CloudStreamSource cs; private String testFilePath; diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java index d0ffef1965..53f874c3ec 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java @@ -31,12 +31,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowToast; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.R; import com.amaze.filemanager.adapters.data.CompressedObjectParcelable; import com.amaze.filemanager.asynchronous.asynctasks.compress.ZipHelperTask; @@ -46,11 +43,11 @@ import android.os.Environment; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class B0rkenZipTest { private File zipfile1 = new File(Environment.getExternalStorageDirectory(), "zip-slip.zip"); @@ -93,7 +90,7 @@ public void setUp() throws Exception { public void testExtractZipWithWrongPathUnix() throws Exception { Extractor extractor = new ZipExtractor( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), zipfile1.getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath(), emptyListener); @@ -106,7 +103,7 @@ public void testExtractZipWithWrongPathUnix() throws Exception { public void testExtractZipWithWrongPathWindows() throws Exception { Extractor extractor = new ZipExtractor( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), zipfile2.getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath(), emptyListener); @@ -119,7 +116,7 @@ public void testExtractZipWithWrongPathWindows() throws Exception { public void testExtractZipWithSlashPrefixEntry() throws Exception { Extractor extractor = new ZipExtractor( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), zipfile3.getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath(), emptyListener); @@ -132,12 +129,17 @@ public void testExtractZipWithSlashPrefixEntry() throws Exception { public void testZipHelperTaskShouldOmitInvalidEntries() throws Exception { ZipHelperTask task = new ZipHelperTask( - RuntimeEnvironment.application, zipfile1.getAbsolutePath(), null, false, (data) -> {}); + ApplicationProvider.getApplicationContext(), + zipfile1.getAbsolutePath(), + null, + false, + (data) -> {}); List result = task.execute().get().result; assertEquals(1, result.size()); assertEquals("good.txt", result.get(0).path); assertEquals( - RuntimeEnvironment.application.getString(R.string.multiple_invalid_archive_entries), + ApplicationProvider.getApplicationContext() + .getString(R.string.multiple_invalid_archive_entries), ShadowToast.getTextOfLatestToast()); } @@ -145,12 +147,17 @@ public void testZipHelperTaskShouldOmitInvalidEntries() throws Exception { public void testZipHelperTaskShouldOmitInvalidEntriesWithBackslash() throws Exception { ZipHelperTask task = new ZipHelperTask( - RuntimeEnvironment.application, zipfile2.getAbsolutePath(), null, false, (data) -> {}); + ApplicationProvider.getApplicationContext(), + zipfile2.getAbsolutePath(), + null, + false, + (data) -> {}); List result = task.execute().get().result; assertEquals(1, result.size()); assertEquals("good.txt", result.get(0).path); assertEquals( - RuntimeEnvironment.application.getString(R.string.multiple_invalid_archive_entries), + ApplicationProvider.getApplicationContext() + .getString(R.string.multiple_invalid_archive_entries), ShadowToast.getTextOfLatestToast()); } } diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java index 51f99a5bfe..134e433f17 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java @@ -29,11 +29,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor; import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.Bzip2Extractor; import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.GzipExtractor; @@ -56,11 +53,11 @@ import android.content.Context; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class CompressedHelperTest { private Context context; @@ -68,7 +65,7 @@ public class CompressedHelperTest { @Before public void setUp() { - context = RuntimeEnvironment.application; + context = ApplicationProvider.getApplicationContext(); emptyUpdateListener = new Extractor.OnUpdate() { @Override diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.java index 6fe6f01a27..b51fd6eebd 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.java @@ -38,24 +38,22 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowEnvironment; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.filesystem.compressed.ArchivePasswordCache; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.content.Context; import android.os.Environment; -@RunWith(RobolectricTestRunner.class) +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) @Config( - constants = BuildConfig.class, shadows = {ShadowMultiDex.class}, - minSdk = 14, - maxSdk = 27) + minSdk = 14) public abstract class AbstractExtractorTest { protected abstract Class extractorClass(); @@ -85,7 +83,7 @@ public void testFixEntryName() throws Exception { extractorClass() .getConstructor(Context.class, String.class, String.class, Extractor.OnUpdate.class) .newInstance( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), getArchiveFile().getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath(), null); @@ -119,7 +117,7 @@ protected void doTestExtractFiles() throws Exception { extractorClass() .getConstructor(Context.class, String.class, String.class, Extractor.OnUpdate.class) .newInstance( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), getArchiveFile().getAbsolutePath(), Environment.getExternalStorageDirectory().getAbsolutePath(), new Extractor.OnUpdate() { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.java index 8cf0efa219..57490dcab9 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.java @@ -27,25 +27,22 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowDateFormat; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.adapters.data.LayoutElementParcelable; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.utils.OpenMode; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + /** * because of test based on mock-up, extension testing isn't tested so, assume all extension is * "*{slash}*" */ -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class, ShadowDateFormat.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class, ShadowDateFormat.class}) public class FileListSorterTest { /** * Purpose: when dirsOnTop is 0, if file1 is directory && file2 is not directory, result is -1 @@ -57,7 +54,7 @@ public void testDir0File1DirAndFile2NoDir() { FileListSorter fileListSorter = new FileListSorter(0, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1", "C:\\AmazeFileManager\\abc1", "user", @@ -71,7 +68,7 @@ public void testDir0File1DirAndFile2NoDir() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -103,7 +100,7 @@ public void testDir0File1NoDirAndFile2Dir() { FileListSorter fileListSorter = new FileListSorter(0, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1.txt", "C:\\AmazeFileManager\\abc1", "user", @@ -117,7 +114,7 @@ public void testDir0File1NoDirAndFile2Dir() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2", "C:\\AmazeFileManager\\abc2", "user", @@ -143,7 +140,7 @@ public void testDir1File1DirAndFile2NoDir() { FileListSorter fileListSorter = new FileListSorter(1, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1", "C:\\AmazeFileManager\\abc1", "user", @@ -157,7 +154,7 @@ public void testDir1File1DirAndFile2NoDir() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -183,7 +180,7 @@ public void testDir1File1NoDirAndFile2Dir() { FileListSorter fileListSorter = new FileListSorter(1, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1.txt", "C:\\AmazeFileManager\\abc1", "user", @@ -197,7 +194,7 @@ public void testDir1File1NoDirAndFile2Dir() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2", "C:\\AmazeFileManager\\abc2", "user", @@ -225,7 +222,7 @@ public void testSort0File1TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1.txt", "C:\\AmazeFileManager\\abc1", "user", @@ -239,7 +236,7 @@ public void testSort0File1TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -265,7 +262,7 @@ public void testSort0File2TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -279,7 +276,7 @@ public void testSort0File2TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -305,7 +302,7 @@ public void testSort0TitleSame() { FileListSorter fileListSorter = new FileListSorter(-1, 0, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -319,7 +316,7 @@ public void testSort0TitleSame() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "ABC.txt", "C:\\AmazeFileManager\\ABC", "user", @@ -345,7 +342,7 @@ public void testSort1File1DateLastest() { FileListSorter fileListSorter = new FileListSorter(-1, 1, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -359,7 +356,7 @@ public void testSort1File1DateLastest() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -385,7 +382,7 @@ public void testSort1File2DateLastest() { FileListSorter fileListSorter = new FileListSorter(-1, 1, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -399,7 +396,7 @@ public void testSort1File2DateLastest() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -425,7 +422,7 @@ public void testSort1FileDateSame() { FileListSorter fileListSorter = new FileListSorter(-1, 1, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -439,7 +436,7 @@ public void testSort1FileDateSame() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -465,7 +462,7 @@ public void testSort2NoDirAndFile1SizeBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -479,7 +476,7 @@ public void testSort2NoDirAndFile1SizeBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -505,7 +502,7 @@ public void testSort2NoDirAndFile2SizeBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -519,7 +516,7 @@ public void testSort2NoDirAndFile2SizeBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -545,7 +542,7 @@ public void testSort2NoDirAndFileSizeSame() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -559,7 +556,7 @@ public void testSort2NoDirAndFileSizeSame() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -586,7 +583,7 @@ public void testSort2File1DirAndFile1TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1", "C:\\AmazeFileManager\\abc1", "user", @@ -600,7 +597,7 @@ public void testSort2File1DirAndFile1TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -627,7 +624,7 @@ public void testSort2File1DirAndFile2TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc", "C:\\AmazeFileManager\\abc", "user", @@ -641,7 +638,7 @@ public void testSort2File1DirAndFile2TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -668,7 +665,7 @@ public void testSort2File2DirAndFile1TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1.txt", "C:\\AmazeFileManager\\abc1", "user", @@ -682,7 +679,7 @@ public void testSort2File2DirAndFile1TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc", "C:\\AmazeFileManager\\abc", "user", @@ -709,7 +706,7 @@ public void testSort2File2DirAndFile2TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -723,7 +720,7 @@ public void testSort2File2DirAndFile2TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2", "C:\\AmazeFileManager\\abc2", "user", @@ -749,7 +746,7 @@ public void testSort2File2DirAndFileTitleSame() { FileListSorter fileListSorter = new FileListSorter(-1, 2, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc", "C:\\AmazeFileManager\\abc", "user", @@ -763,7 +760,7 @@ public void testSort2File2DirAndFileTitleSame() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc", "C:\\AmazeFileManager\\abc", "user", @@ -791,7 +788,7 @@ public void testSort3FileExtensionSameAndFile1TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 3, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc1.txt", "C:\\AmazeFileManager\\abc1", "user", @@ -805,7 +802,7 @@ public void testSort3FileExtensionSameAndFile1TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -833,7 +830,7 @@ public void testSort3FileExtensionSameAndFile2TitleBigger() { FileListSorter fileListSorter = new FileListSorter(-1, 3, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -847,7 +844,7 @@ public void testSort3FileExtensionSameAndFile2TitleBigger() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc2.txt", "C:\\AmazeFileManager\\abc2", "user", @@ -874,7 +871,7 @@ public void testSort3FileExtensionSameAndFileTitleSame() { FileListSorter fileListSorter = new FileListSorter(-1, 3, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -888,7 +885,7 @@ public void testSort3FileExtensionSameAndFileTitleSame() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "ABC.txt", "C:\\AmazeFileManager\\ABC", "user", @@ -913,7 +910,7 @@ public void testSortAnotherNumber() { FileListSorter fileListSorter = new FileListSorter(-1, 4, 1); LayoutElementParcelable file1 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "abc.txt", "C:\\AmazeFileManager\\abc", "user", @@ -927,7 +924,7 @@ public void testSortAnotherNumber() { OpenMode.UNKNOWN); LayoutElementParcelable file2 = new LayoutElementParcelable( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "ABC.txt", "C:\\AmazeFileManager\\ABC", "user", diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/smbstreamer/StreamSourceTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/smbstreamer/StreamSourceTest.java index ddbcfc71c2..5ac87031a1 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/smbstreamer/StreamSourceTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/smbstreamer/StreamSourceTest.java @@ -33,24 +33,21 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.shadows.jcifs.smb.ShadowSmbFile; import android.os.Environment; +import androidx.test.ext.junit.runners.AndroidJUnit4; + import jcifs.smb.SmbFile; /** Created by Rustam Khadipash on 30/3/2018. */ -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class, ShadowSmbFile.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class, ShadowSmbFile.class}) public class StreamSourceTest { private SmbFile file; private StreamSource ss; diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.java index 06a62d0a86..5d08b196dc 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.java @@ -36,20 +36,17 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.filesystem.ssh.test.TestKeyProvider; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.os.Environment; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public abstract class AbstractSftpServerTest { protected SshServer server; diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/ListFilesOnSshdTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/ListFilesOnSshdTest.java index e8c71008fb..c7fd6b02ba 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/ListFilesOnSshdTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/ListFilesOnSshdTest.java @@ -20,6 +20,7 @@ package com.amaze.filemanager.filesystem.ssh; +import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.hasItems; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -28,6 +29,7 @@ import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; @@ -35,13 +37,14 @@ import java.util.concurrent.CountDownLatch; import org.junit.Test; -import org.robolectric.RuntimeEnvironment; import com.amaze.filemanager.filesystem.HybridFile; import com.amaze.filemanager.utils.OpenMode; import android.os.Environment; +import androidx.test.core.app.ApplicationProvider; + public class ListFilesOnSshdTest extends AbstractSftpServerTest { @Test @@ -49,11 +52,16 @@ public void testNormalListDirs() throws InterruptedException { for (String s : new String[] {"sysroot", "srv", "var", "tmp", "bin", "lib", "usr"}) { new File(Environment.getExternalStorageDirectory(), s).mkdir(); } - performVerify(); + assertTrue(performVerify()); } @Test public void testListDirsAndSymlinks() throws Exception { + createNecessaryDirsForSymlinkRelatedTests(); + assertTrue(performVerify()); + } + + private void createNecessaryDirsForSymlinkRelatedTests() throws IOException { File sysroot = new File(Environment.getExternalStorageDirectory(), "sysroot"); sysroot.mkdir(); for (String s : new String[] {"srv", "var", "tmp"}) { @@ -66,41 +74,27 @@ public void testListDirsAndSymlinks() throws Exception { for (String s : new String[] {"bin", "lib", "usr"}) { new File(Environment.getExternalStorageDirectory(), s).mkdir(); } - performVerify(); } - private void performVerify() throws InterruptedException { + private boolean performVerify() { List result = new ArrayList<>(); HybridFile file = new HybridFile(OpenMode.SFTP, "ssh://testuser:testpassword@127.0.0.1:" + serverPort); - CountDownLatch waiter = new CountDownLatch(7); file.forEachChildrenFile( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, (fileFound) -> { assertTrue(fileFound.getPath() + " not seen as directory", fileFound.isDirectory()); result.add(fileFound.getName()); - waiter.countDown(); }); - waiter.await(); - assertEquals(7, result.size()); + await().until(() -> result.size() == 7); assertThat(result, hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr")); + return true; } @Test public void testListDirsAndFilesAndSymlinks() throws Exception { - File sysroot = new File(Environment.getExternalStorageDirectory(), "sysroot"); - sysroot.mkdir(); - for (String s : new String[] {"srv", "var", "tmp"}) { - File subdir = new File(sysroot, s); - subdir.mkdir(); - Files.createSymbolicLink( - Paths.get(new File(Environment.getExternalStorageDirectory(), s).getAbsolutePath()), - Paths.get(subdir.getAbsolutePath())); - } - for (String s : new String[] {"bin", "lib", "usr"}) { - new File(Environment.getExternalStorageDirectory(), s).mkdir(); - } + createNecessaryDirsForSymlinkRelatedTests(); for (int i = 1; i <= 4; i++) { File f = new File(Environment.getExternalStorageDirectory(), i + ".txt"); FileOutputStream out = new FileOutputStream(f); @@ -117,7 +111,7 @@ public void testListDirsAndFilesAndSymlinks() throws Exception { new HybridFile(OpenMode.SFTP, "ssh://testuser:testpassword@127.0.0.1:" + serverPort); CountDownLatch waiter = new CountDownLatch(15); file.forEachChildrenFile( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), false, (fileFound) -> { if (!fileFound.getName().endsWith(".txt")) { @@ -144,4 +138,15 @@ public void testListDirsAndFilesAndSymlinks() throws Exception { "symlink3.txt", "symlink4.txt")); } + + @Test + public void testListDirsAndBrokenSymlinks() throws Exception { + createNecessaryDirsForSymlinkRelatedTests(); + Files.createSymbolicLink( + Paths.get( + new File(Environment.getExternalStorageDirectory(), "b0rken.symlink") + .getAbsolutePath()), + Paths.get(new File("/tmp/notfound.file").getAbsolutePath())); + assertTrue(performVerify()); + } } diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshClientUtilTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshClientUtilTest.java new file mode 100644 index 0000000000..162d2f80a1 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshClientUtilTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.filesystem.ssh; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import org.junit.Test; + +import net.schmizz.sshj.sftp.FileAttributes; +import net.schmizz.sshj.sftp.FileMode; +import net.schmizz.sshj.sftp.RemoteResourceInfo; +import net.schmizz.sshj.sftp.SFTPClient; + +public class SshClientUtilTest { + + @Test + public void testIsDirectoryNormal() throws IOException { + RemoteResourceInfo mock = mock(RemoteResourceInfo.class); + when(mock.isDirectory()).thenReturn(true); + FileAttributes mockAttributes = + new FileAttributes.Builder().withType(FileMode.Type.DIRECTORY).build(); + when(mock.getAttributes()).thenReturn(mockAttributes); + SFTPClient mockClient = mock(SFTPClient.class); + assertTrue(SshClientUtils.isDirectory(mockClient, mock)); + } + + @Test + public void testIsDirectoryWithFile() throws IOException { + RemoteResourceInfo mock = mock(RemoteResourceInfo.class); + when(mock.isDirectory()).thenReturn(false); + FileAttributes mockAttributes = + new FileAttributes.Builder().withType(FileMode.Type.REGULAR).build(); + when(mock.getAttributes()).thenReturn(mockAttributes); + SFTPClient mockClient = mock(SFTPClient.class); + assertFalse(SshClientUtils.isDirectory(mockClient, mock)); + } + + @Test + public void testIsDirectorySymlinkNormal() throws IOException { + RemoteResourceInfo mock = mock(RemoteResourceInfo.class); + when(mock.getPath()).thenReturn("/sysroot/etc"); + when(mock.isDirectory()).thenReturn(true); + FileAttributes mockAttributes = + new FileAttributes.Builder().withType(FileMode.Type.SYMLINK).build(); + when(mock.getAttributes()).thenReturn(mockAttributes); + + SFTPClient mockClient = mock(SFTPClient.class); + mockAttributes = new FileAttributes.Builder().withType(FileMode.Type.DIRECTORY).build(); + when(mockClient.stat("/sysroot/etc")).thenReturn(mockAttributes); + + assertTrue(SshClientUtils.isDirectory(mockClient, mock)); + } + + @Test + public void testIsDirectorySymlinkBrokenDirectory() throws IOException { + RemoteResourceInfo mock = mock(RemoteResourceInfo.class); + when(mock.getPath()).thenReturn("/sysroot/etc"); + when(mock.isDirectory()).thenReturn(true); + FileAttributes mockAttributes = + new FileAttributes.Builder().withType(FileMode.Type.SYMLINK).build(); + when(mock.getAttributes()).thenReturn(mockAttributes); + + SFTPClient mockClient = mock(SFTPClient.class); + mockAttributes = new FileAttributes.Builder().withType(FileMode.Type.DIRECTORY).build(); + when(mockClient.stat("/sysroot/etc")).thenThrow(new IOException()); + + assertThrows(IOException.class, () -> SshClientUtils.isDirectory(mockClient, mock)); + } + + @Test + public void testIsDirectorySymlinkBrokenFile() throws IOException { + RemoteResourceInfo mock = mock(RemoteResourceInfo.class); + when(mock.getPath()).thenReturn("/sysroot/etc"); + when(mock.isDirectory()).thenReturn(false); + FileAttributes mockAttributes = + new FileAttributes.Builder().withType(FileMode.Type.SYMLINK).build(); + when(mock.getAttributes()).thenReturn(mockAttributes); + + SFTPClient mockClient = mock(SFTPClient.class); + mockAttributes = new FileAttributes.Builder().withType(FileMode.Type.DIRECTORY).build(); + when(mockClient.stat("/sysroot/etc")).thenThrow(new IOException()); + + assertThrows(IOException.class, () -> SshClientUtils.isDirectory(mockClient, mock)); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshConnectionPoolTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshConnectionPoolTest.java index 318010d4a1..8db0cccff9 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshConnectionPoolTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshConnectionPoolTest.java @@ -34,11 +34,8 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.database.UtilitiesDatabase; import com.amaze.filemanager.database.UtilsHandler; import com.amaze.filemanager.database.models.OperationData; @@ -49,14 +46,13 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import net.schmizz.sshj.common.SecurityUtils; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class, ShadowCryptUtil.class}, - maxSdk = 27) +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class, ShadowCryptUtil.class}) public class SshConnectionPoolTest { private SshServer server; @@ -305,8 +301,8 @@ private void saveSshConnectionSettings( @NonNull String validUsername, @Nullable String validPassword, @Nullable PrivateKey privateKey) { - utilitiesDatabase = UtilitiesDatabase.initialize(RuntimeEnvironment.application); - utilsHandler = new UtilsHandler(RuntimeEnvironment.application, utilitiesDatabase); + utilitiesDatabase = UtilitiesDatabase.initialize(ApplicationProvider.getApplicationContext()); + utilsHandler = new UtilsHandler(ApplicationProvider.getApplicationContext(), utilitiesDatabase); String privateKeyContents = null; if (privateKey != null) { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/usb/SingletonUsbOtgTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/usb/SingletonUsbOtgTest.java index 1f2694a006..be4cd8390d 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/usb/SingletonUsbOtgTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/usb/SingletonUsbOtgTest.java @@ -27,23 +27,21 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.ui.activities.MainActivity; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; + @Ignore("Test skipped due to Robolectric unable to inflate SpeedDialView") -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config( - constants = BuildConfig.class, shadows = {ShadowMultiDex.class}, - minSdk = 24, - maxSdk = 27) + minSdk = 24) public class SingletonUsbOtgTest { @Test public void usbConnectionTest() { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/usb/UsbOtgTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/usb/UsbOtgTest.java index 9d7ae3d5ed..7cac7181a2 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/usb/UsbOtgTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/usb/UsbOtgTest.java @@ -29,11 +29,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.adapters.data.StorageDirectoryParcelable; import com.amaze.filemanager.shadows.ShadowMultiDex; import com.amaze.filemanager.ui.activities.MainActivity; @@ -41,13 +39,13 @@ import android.text.TextUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; + @Ignore("Test skipped due to Robolectric unable to inflate SpeedDialView") -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config( - constants = BuildConfig.class, shadows = {ShadowMultiDex.class}, - minSdk = 24, - maxSdk = 27) + minSdk = 24) public class UsbOtgTest { @Test diff --git a/app/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java b/app/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java index 2896864971..f13a2f5ac4 100644 --- a/app/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java +++ b/app/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java @@ -56,4 +56,9 @@ public InputStream getInputStream() throws IOException { public long length() throws SmbException { return file.length(); } + + @Implementation + public SmbFile[] listFiles() { + return new SmbFile[0]; + } } diff --git a/app/src/test/java/com/amaze/filemanager/ssh/SshClientUtilTest.java b/app/src/test/java/com/amaze/filemanager/ssh/SshClientUtilTest.java new file mode 100644 index 0000000000..3c455db9a2 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ssh/SshClientUtilTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ssh; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.amaze.filemanager.filesystem.ssh.SshClientUtils; + +public class SshClientUtilTest { + @Test + public void testExtractRemotePathFromUri() { + assertEquals( + "/home/user/foo/bar", + SshClientUtils.extractRemotePathFrom("ssh://user:password@127.0.0.1:22/home/user/foo/bar")); + assertEquals("/", SshClientUtils.extractRemotePathFrom("ssh://user:password@127.0.0.1:22/")); + assertEquals("/", SshClientUtils.extractRemotePathFrom("ssh://user:password@127.0.0.1:22")); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/test/ShadowCryptUtilTest.java b/app/src/test/java/com/amaze/filemanager/test/ShadowCryptUtilTest.java index 9fcf0f6d32..8761127eff 100644 --- a/app/src/test/java/com/amaze/filemanager/test/ShadowCryptUtilTest.java +++ b/app/src/test/java/com/amaze/filemanager/test/ShadowCryptUtilTest.java @@ -27,11 +27,8 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.database.UtilitiesDatabase; import com.amaze.filemanager.database.UtilsHandler; import com.amaze.filemanager.database.models.OperationData; @@ -39,26 +36,28 @@ import com.amaze.filemanager.filesystem.ssh.SshClientUtils; import com.amaze.filemanager.shadows.ShadowMultiDex; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class, ShadowCryptUtil.class}, - maxSdk = 27) +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class, ShadowCryptUtil.class}) public class ShadowCryptUtilTest { @Test public void testEncryptDecrypt() throws GeneralSecurityException, IOException { String text = "test"; - String encrypted = CryptUtil.encryptPassword(RuntimeEnvironment.application, text); - assertEquals(text, CryptUtil.decryptPassword(RuntimeEnvironment.application, encrypted)); + String encrypted = CryptUtil.encryptPassword(ApplicationProvider.getApplicationContext(), text); + assertEquals( + text, CryptUtil.decryptPassword(ApplicationProvider.getApplicationContext(), encrypted)); } @Test public void testWithUtilsHandler() { UtilitiesDatabase utilitiesDatabase = - UtilitiesDatabase.initialize(RuntimeEnvironment.application); - UtilsHandler utilsHandler = new UtilsHandler(RuntimeEnvironment.application, utilitiesDatabase); + UtilitiesDatabase.initialize(ApplicationProvider.getApplicationContext()); + UtilsHandler utilsHandler = + new UtilsHandler(ApplicationProvider.getApplicationContext(), utilitiesDatabase); String fingerprint = "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff"; String url = "ssh://test:test@127.0.0.1:22"; diff --git a/app/src/test/java/com/amaze/filemanager/test/TestUtils.java b/app/src/test/java/com/amaze/filemanager/test/TestUtils.java index 1cf11ec007..2f011f86d1 100644 --- a/app/src/test/java/com/amaze/filemanager/test/TestUtils.java +++ b/app/src/test/java/com/amaze/filemanager/test/TestUtils.java @@ -20,15 +20,27 @@ package com.amaze.filemanager.test; +import static android.os.Build.VERSION_CODES.P; import static org.robolectric.Shadows.shadowOf; +import java.io.File; import java.lang.reflect.Field; +import org.robolectric.shadows.ShadowStorageManager; import org.robolectric.util.Scheduler; import com.amaze.filemanager.application.AppConfig; +import android.os.Build; +import android.os.Environment; import android.os.Handler; +import android.os.Parcel; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; + +import androidx.annotation.NonNull; +import androidx.test.core.app.ApplicationProvider; public class TestUtils { @@ -63,4 +75,63 @@ public static void flushAppConfigHandlerThread() { throw new AssertionError("Unable to access backgroundHandler within AppConfig"); } } + + /** + * Populate "internal device storage" to StorageManager with directory as provided by Robolectric. + * + *

Tests need storage access must call this on test case setup for SDK >= N to work. + */ + public static void initializeInternalStorage() { + Parcel parcel = Parcel.obtain(); + File dir = Environment.getExternalStorageDirectory(); + parcel.writeString("FS-internal"); + if (Build.VERSION.SDK_INT < P) parcel.writeInt(0); + parcel.writeString(dir.getAbsolutePath()); + if (Build.VERSION.SDK_INT >= P) parcel.writeString(dir.getAbsolutePath()); + parcel.writeString("robolectric internal storage"); + parcel.writeInt(1); + parcel.writeInt(0); + parcel.writeInt(1); + if (Build.VERSION.SDK_INT < P) parcel.writeLong(1024 * 1024); + parcel.writeInt(0); + parcel.writeLong(1024 * 1024); + parcel.writeParcelable(UserHandle.getUserHandleForUid(0), 0); + parcel.writeString("1234-5678"); + parcel.writeString(Environment.MEDIA_MOUNTED); + addVolumeToStorageManager(parcel); + } + + /** + * Populate "external device storage" to StorageManager with directory as provided by Robolectric. + * + *

Tests need storage access must call this on test case setup for SDK >= N to work. + */ + public static void initializeExternalStorage() { + Parcel parcel = Parcel.obtain(); + File dir = Environment.getExternalStoragePublicDirectory("external"); + parcel.writeString("FS-external"); + if (Build.VERSION.SDK_INT < P) parcel.writeInt(0); + parcel.writeString(dir.getAbsolutePath()); + if (Build.VERSION.SDK_INT >= P) parcel.writeString(dir.getAbsolutePath()); + parcel.writeString("robolectric external storage"); + parcel.writeInt(0); + parcel.writeInt(1); + parcel.writeInt(0); + if (Build.VERSION.SDK_INT < P) parcel.writeLong(1024 * 1024); + parcel.writeInt(0); + parcel.writeLong(1024 * 1024); + parcel.writeParcelable(UserHandle.getUserHandleForUid(0), 0); + parcel.writeString("ABCD-EFGH"); + parcel.writeString(Environment.MEDIA_MOUNTED); + addVolumeToStorageManager(parcel); + } + + private static void addVolumeToStorageManager(@NonNull Parcel parcel) { + parcel.setDataPosition(0); + ShadowStorageManager storageManager = + shadowOf( + ApplicationProvider.getApplicationContext().getSystemService(StorageManager.class)); + StorageVolume volume = StorageVolume.CREATOR.createFromParcel(parcel); + storageManager.addStorageVolume(volume); + } } diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/MainActivityTest.java b/app/src/test/java/com/amaze/filemanager/ui/activities/MainActivityTest.java index f88a610ad4..1197dbe822 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/MainActivityTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/MainActivityTest.java @@ -20,34 +20,125 @@ package com.amaze.filemanager.ui.activities; -import org.junit.Ignore; +import static android.os.Build.VERSION_CODES.N; +import static androidx.test.core.app.ActivityScenario.launch; +import static org.awaitility.Awaitility.await; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.robolectric.Shadows.shadowOf; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; +import org.robolectric.shadows.ShadowLooper; +import org.robolectric.shadows.ShadowStorageManager; -import com.amaze.filemanager.BuildConfig; +import com.amaze.filemanager.application.AppConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; +import com.amaze.filemanager.shadows.jcifs.smb.ShadowSmbFile; +import com.amaze.filemanager.test.ShadowCryptUtil; +import com.amaze.filemanager.test.TestUtils; +import com.amaze.filemanager.utils.SmbUtil; + +import android.os.Build; +import android.os.storage.StorageManager; -@RunWith(RobolectricTestRunner.class) +import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ActivityScenario; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) @Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) + shadows = { + ShadowMultiDex.class, + ShadowStorageManager.class, + ShadowCryptUtil.class, + ShadowSmbFile.class + }) +/* + * Need to make LooperMode PAUSED and flush the main looper before activity can show up. + * @see {@link LooperMode.Mode.PAUSED} + * @see {@link StackOverflow discussion} + */ +@LooperMode(LooperMode.Mode.PAUSED) public class MainActivityTest { + @Before + public void setUp() { + if (Build.VERSION.SDK_INT >= N) TestUtils.initializeInternalStorage(); + } + + @After + public void tearDown() { + if (Build.VERSION.SDK_INT >= N) + shadowOf(ApplicationProvider.getApplicationContext().getSystemService(StorageManager.class)) + .resetStorageVolumeList(); + } + @Test - @Ignore - public void testMainActivity() { - ActivityController controller = - Robolectric.buildActivity(MainActivity.class) - .create() - .start() - .resume() - .visible() - .pause() - .destroy(); + public void testUpdateSmbExceptionShouldNotThrowNPE() { + ActivityScenario scenario = launch(MainActivity.class); + + ShadowLooper.idleMainLooper(); + + scenario.moveToState(Lifecycle.State.STARTED); + + scenario.onActivity( + activity -> { + String path = "smb://root:toor@192.168.1.1"; + String oldName = "SMB connection"; + String newName = "root@192.168.1.1"; + try { + + activity.addConnection( + false, + oldName, + path, + SmbUtil.getSmbEncryptedPath(ApplicationProvider.getApplicationContext(), path), + null, + null); + activity.addConnection( + true, + newName, + path, + SmbUtil.getSmbEncryptedPath(ApplicationProvider.getApplicationContext(), path), + oldName, + path); + + ShadowLooper.idleMainLooper(); + + await() + .atMost(5, TimeUnit.SECONDS) + .until(() -> AppConfig.getInstance().getUtilsHandler().getSmbList().size() > 0); + await() + .atMost(5, TimeUnit.SECONDS) + .until( + () -> + AppConfig.getInstance() + .getUtilsHandler() + .getSmbList() + .get(0)[0] + .equals(newName)); + List verify = AppConfig.getInstance().getUtilsHandler().getSmbList(); + assertEquals(1, verify.size()); + String[] entry = verify.get(0); + assertEquals(path, entry[1]); + + } catch (GeneralSecurityException | IOException e) { + fail(e.getMessage()); + } finally { + scenario.moveToState(Lifecycle.State.DESTROYED); + scenario.close(); + } + }); } } diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/PreferencesActivityTest.java b/app/src/test/java/com/amaze/filemanager/ui/activities/PreferencesActivityTest.java new file mode 100644 index 0000000000..9c1f339cd0 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/PreferencesActivityTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ui.activities; + +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_BOOKMARKS_ADDED; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_CHANGEPATHS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_COLORED_NAVIGATION; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_COLORIZE_ICONS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_NEED_TO_SET_HOME; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_ROOTMODE; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_DIVIDERS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_FILE_SIZE; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_GOBACK_BUTTON; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_HEADERS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_HIDDENFILES; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_LAST_MODIFIED; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_PERMISSIONS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_SIDEBAR_FOLDERS; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_SIDEBAR_QUICKACCESSES; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_SHOW_THUMB; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_TEXTEDITOR_NEWSTACK; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_USE_CIRCULAR_IMAGES; +import static com.amaze.filemanager.ui.fragments.preference_fragments.PreferencesConstants.PREFERENCE_VIEW; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import androidx.lifecycle.Lifecycle; +import androidx.test.core.app.ActivityScenario; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +public class PreferencesActivityTest { + + private static final String[] DEFAULT_FALSE_PREFS = + new String[] { + PREFERENCE_SHOW_PERMISSIONS, + PREFERENCE_SHOW_GOBACK_BUTTON, + PREFERENCE_SHOW_HIDDENFILES, + PREFERENCE_BOOKMARKS_ADDED, + PREFERENCE_ROOTMODE, + PREFERENCE_COLORED_NAVIGATION, + PREFERENCE_TEXTEDITOR_NEWSTACK, + PREFERENCE_CHANGEPATHS + }; + + private static final String[] DEFAULT_TRUE_PREFS = + new String[] { + PREFERENCE_SHOW_FILE_SIZE, + PREFERENCE_SHOW_DIVIDERS, + PREFERENCE_SHOW_HEADERS, + PREFERENCE_USE_CIRCULAR_IMAGES, + PREFERENCE_COLORIZE_ICONS, + PREFERENCE_SHOW_THUMB, + PREFERENCE_SHOW_SIDEBAR_QUICKACCESSES, + PREFERENCE_NEED_TO_SET_HOME, + PREFERENCE_SHOW_SIDEBAR_FOLDERS, + PREFERENCE_VIEW, + PREFERENCE_SHOW_LAST_MODIFIED + }; + + private ActivityScenario scenario; + + @Before + public void setUp() { + scenario = ActivityScenario.launch(PreferencesActivity.class); + scenario.moveToState(Lifecycle.State.STARTED); + } + + @After + public void tearDown() { + scenario.close(); + } + + @Test + public void testGetBooleanWithNoSavedValue() { + scenario.onActivity( + activity -> { + for (String pref : DEFAULT_FALSE_PREFS) { + assertFalse(activity.getBoolean(pref)); + } + for (String pref : DEFAULT_TRUE_PREFS) { + assertTrue(activity.getBoolean(pref)); + } + assertThrows(IllegalArgumentException.class, () -> activity.getBoolean("foobar")); + }); + } + + @Test + public void testGetBooleanWithSavedValue() { + SharedPreferences preferences = + PreferenceManager.getDefaultSharedPreferences(ApplicationProvider.getApplicationContext()); + scenario.onActivity( + activity -> { + for (String pref : DEFAULT_FALSE_PREFS) { + preferences.edit().putBoolean(pref, true).commit(); + assertTrue(activity.getBoolean(pref)); + } + for (String pref : DEFAULT_TRUE_PREFS) { + preferences.edit().putBoolean(pref, false).commit(); + assertFalse(activity.getBoolean(pref)); + } + assertThrows(IllegalArgumentException.class, () -> activity.getBoolean("foobar")); + }); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java index 81fc202483..fc1c1db5c6 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java @@ -20,10 +20,8 @@ package com.amaze.filemanager.ui.activities; -import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.File; @@ -34,37 +32,27 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowContentResolver; import org.robolectric.shadows.ShadowEnvironment; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.R; import com.amaze.filemanager.application.AppConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.content.ContentResolver; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.widget.TextView; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - minSdk = 24, - maxSdk = 27) -/* - Restrict minSdk to 24 since it'd fail at SDK 21-23. - This may only be fixed by upgrading to Robolectric 4. - See https://github.com/robolectric/robolectric/issues/3947 -*/ +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class TextEditorActivityTest { private final String fileContents = "fsdfsdfs"; @@ -83,14 +71,15 @@ public void testOpenFileUri() throws IOException { intent.setData(Uri.fromFile(file)); generateActivity(intent); - assertThat(text.getText().toString(), is(fileContents + "\n")); + assertEquals(fileContents + "\n", text.getText().toString()); } @Test public void testOpenContentUri() throws Exception { Uri uri = Uri.parse("content://foo.bar.test.streamprovider/temp/thisisatest.txt"); - ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); + ContentResolver contentResolver = + ApplicationProvider.getApplicationContext().getContentResolver(); ShadowContentResolver shadowContentResolver = Shadows.shadowOf(contentResolver); shadowContentResolver.registerInputStream( uri, new ByteArrayInputStream(fileContents.getBytes("UTF-8"))); @@ -120,7 +109,7 @@ private File simulateFile() throws IOException { file.createNewFile(); if (!file.canWrite()) file.setWritable(true); - assertThat(file.canWrite(), is(true)); + assertTrue(file.canWrite()); PrintWriter out = new PrintWriter(file); out.write(fileContents); @@ -129,9 +118,4 @@ private File simulateFile() throws IOException { return file; } - - private Uri getFileContentUri(Context context, File file) { - fail("Cannot create content URI"); - return null; - } } diff --git a/app/src/test/java/com/amaze/filemanager/ui/colors/ColorUtilsTest.java b/app/src/test/java/com/amaze/filemanager/ui/colors/ColorUtilsTest.java new file mode 100644 index 0000000000..eef3000376 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ui/colors/ColorUtilsTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ui.colors; + +import static android.os.Build.VERSION_CODES.N; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.R; +import com.amaze.filemanager.ui.icons.Icons; +import com.amaze.filemanager.utils.Utils; + +import android.content.res.ColorStateList; +import android.graphics.drawable.GradientDrawable; + +import androidx.annotation.ColorInt; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = N) +public class ColorUtilsTest { + + @Test + public void testSetColorizeIcons() { + assertTrue(doTest(R.color.video_item, Icons.VIDEO)); + assertTrue(doTest(R.color.audio_item, Icons.AUDIO)); + assertTrue(doTest(R.color.pdf_item, Icons.PDF)); + assertTrue(doTest(R.color.code_item, Icons.CODE)); + assertTrue(doTest(R.color.text_item, Icons.TEXT)); + assertTrue(doTest(R.color.archive_item, Icons.COMPRESSED)); + assertTrue(doTest(R.color.apk_item, Icons.APK)); + assertTrue(doTest(R.color.generic_item, Icons.NOT_KNOWN)); + } + + @Test + public void testSetColorizeIconsGeneric() { + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.CERTIFICATE)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.CONTACT)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.EVENTS)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.FONT)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.PRESENTATION)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.SPREADSHEETS)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.DOCUMENTS)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.ENCRYPTED)); + assertTrue(doTestGeneric(R.color.primary_indigo, Icons.GIF)); + } + + private boolean doTest(@ColorInt int expected, int icon) { + GradientDrawable drawable = new GradientDrawable(); + ColorUtils.colorizeIcons( + ApplicationProvider.getApplicationContext(), icon, drawable, R.color.primary_indigo); + doCompare( + ColorStateList.valueOf( + Utils.getColor(ApplicationProvider.getApplicationContext(), expected)), + drawable); + drawable = null; + return true; + } + + private boolean doTestGeneric(@ColorInt int expected, int icon) { + GradientDrawable drawable = new GradientDrawable(); + ColorUtils.colorizeIcons( + ApplicationProvider.getApplicationContext(), icon, drawable, R.color.primary_indigo); + doCompare(ColorStateList.valueOf(expected), drawable); + drawable = null; + return true; + } + + private void doCompare(ColorStateList expected, GradientDrawable drawable) { + assertEquals(expected, drawable.getColor()); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java b/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java new file mode 100644 index 0000000000..69e35f03d2 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ui.fragments; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.robolectric.Shadows.shadowOf; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.database.CloudContract; + +import android.content.pm.PackageInfo; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = 19) +public class CloudSheetFragmentTest { + + @Test + public void testIsCloudProviderAvailable() { + assertFalse( + CloudSheetFragment.isCloudProviderAvailable(ApplicationProvider.getApplicationContext())); + + PackageInfo pi = new PackageInfo(); + pi.packageName = CloudContract.APP_PACKAGE_NAME; + shadowOf(ApplicationProvider.getApplicationContext().getPackageManager()).installPackage(pi); + + assertTrue( + CloudSheetFragment.isCloudProviderAvailable(ApplicationProvider.getApplicationContext())); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java index 7738346a9b..835de52ccf 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java @@ -25,21 +25,18 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowMimeTypeMap; -import com.amaze.filemanager.BuildConfig; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.webkit.MimeTypeMap; -@RunWith(RobolectricTestRunner.class) -@Config( - constants = BuildConfig.class, - shadows = {ShadowMultiDex.class}, - maxSdk = 27) +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(shadows = {ShadowMultiDex.class}) public class IconsTest { @Before diff --git a/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java new file mode 100644 index 0000000000..cbe7c34707 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ui.notifications; + +import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_MIN; +import static android.os.Build.VERSION_CODES.N; +import static android.os.Build.VERSION_CODES.O; +import static com.amaze.filemanager.ui.notifications.NotificationConstants.CHANNEL_FTP_ID; +import static com.amaze.filemanager.ui.notifications.NotificationConstants.CHANNEL_NORMAL_ID; +import static com.amaze.filemanager.ui.notifications.NotificationConstants.TYPE_FTP; +import static com.amaze.filemanager.ui.notifications.NotificationConstants.TYPE_NORMAL; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.robolectric.Shadows.shadowOf; + +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowNotificationManager; + +import com.amaze.filemanager.R; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +import androidx.core.app.NotificationCompat; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = 19) +public class NotificationConstantsTest { + + private Context context; + + private NotificationManager notificationManager; + + private ShadowNotificationManager shadowNotificationManager; + + @Before + public void setUp() { + context = ApplicationProvider.getApplicationContext(); + notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + shadowNotificationManager = shadowOf(notificationManager); + } + + @After + public void tearDown() { + notificationManager.cancelAll(); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetMetadataIllegalType() { + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_NORMAL_ID); + NotificationConstants.setMetadata(context, builder, -1); + NotificationConstants.setMetadata(context, builder, 2); + NotificationConstants.setMetadata(context, builder, Integer.MAX_VALUE); + builder = new NotificationCompat.Builder(context, CHANNEL_FTP_ID); + NotificationConstants.setMetadata(context, builder, -1); + NotificationConstants.setMetadata(context, builder, 2); + NotificationConstants.setMetadata(context, builder, Integer.MAX_VALUE); + } + + @Test + @Config(maxSdk = N) + public void testNormalNotification() { + NotificationCompat.Builder builder = + new NotificationCompat.Builder(context, CHANNEL_NORMAL_ID) + .setContentTitle(context.getString(R.string.waiting_title)) + .setContentText(context.getString(R.string.waiting_content)) + .setAutoCancel(false) + .setSmallIcon(R.drawable.ic_all_inclusive_white_36dp) + .setProgress(0, 0, true); + + NotificationConstants.setMetadata(context, builder, TYPE_NORMAL); + Notification result = builder.build(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + assertEquals(Notification.CATEGORY_SERVICE, result.category); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + assertEquals(Notification.PRIORITY_MIN, result.priority); + } else { + assertEquals(Notification.PRIORITY_DEFAULT, result.priority); + } + } + + @Test + @Config(maxSdk = N) + public void testFtpNotification() { + NotificationCompat.Builder builder = + new NotificationCompat.Builder(context, CHANNEL_FTP_ID) + .setContentTitle("FTP server test") + .setContentText("FTP listening at 127.0.0.1:22") + .setSmallIcon(R.drawable.ic_ftp_light) + .setTicker(context.getString(R.string.ftp_notif_starting)) + .setOngoing(true) + .setOnlyAlertOnce(true); + NotificationConstants.setMetadata(context, builder, TYPE_FTP); + Notification result = builder.build(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + assertEquals(Notification.CATEGORY_SERVICE, result.category); + assertEquals(Notification.VISIBILITY_PUBLIC, result.visibility); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + assertEquals(Notification.PRIORITY_MAX, result.priority); + } else { + assertEquals(Notification.PRIORITY_DEFAULT, result.priority); + } + } + + @Test + @Config(minSdk = O) + public void testCreateNormalChannel() { + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_NORMAL_ID); + NotificationConstants.setMetadata(context, builder, TYPE_NORMAL); + List channels = shadowNotificationManager.getNotificationChannels(); + assertNotNull(channels); + assertEquals(1, channels.size()); + NotificationChannel channel = (NotificationChannel) channels.get(0); + assertEquals(IMPORTANCE_MIN, channel.getImportance()); + assertEquals(CHANNEL_NORMAL_ID, channel.getId()); + assertEquals(context.getString(R.string.channel_name_normal), channel.getName()); + assertEquals(context.getString(R.string.channel_description_normal), channel.getDescription()); + } + + @Test + @Config(minSdk = O) + public void testCreateFtpChannel() { + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_FTP_ID); + NotificationConstants.setMetadata(context, builder, TYPE_FTP); + List channels = shadowNotificationManager.getNotificationChannels(); + assertNotNull(channels); + assertEquals(1, channels.size()); + NotificationChannel channel = (NotificationChannel) channels.get(0); + assertEquals(IMPORTANCE_HIGH, channel.getImportance()); + assertEquals(CHANNEL_FTP_ID, channel.getId()); + assertEquals(context.getString(R.string.channel_name_ftp), channel.getName()); + assertEquals(context.getString(R.string.channel_description_ftp), channel.getDescription()); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java b/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java new file mode 100644 index 0000000000..cbf609fafc --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.ui.views; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; + +import com.amaze.filemanager.R; + +import android.content.Context; +import android.widget.Button; +import android.widget.EditText; + +import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +public class WarnableTextInputValidatorTest { + + private Context context; + + @Before + public void setUp() { + context = ApplicationProvider.getApplicationContext(); + context.setTheme(R.style.appCompatBlack); + } + + @Test + public void testValidate() { + EditText textfield = new AppCompatEditText(context); + WarnableTextInputLayout layout = + new WarnableTextInputLayout(context, Robolectric.buildAttributeSet().build()); + Button button = new AppCompatButton(context); + WarnableTextInputValidator.OnTextValidate validator = + text -> + ("Pass".equals(text)) + ? new WarnableTextInputValidator.ReturnState( + WarnableTextInputValidator.ReturnState.STATE_NORMAL, R.string.ok) + : new WarnableTextInputValidator.ReturnState( + WarnableTextInputValidator.ReturnState.STATE_ERROR, R.string.error); + + WarnableTextInputValidator target = + new WarnableTextInputValidator( + ApplicationProvider.getApplicationContext(), textfield, layout, button, validator); + textfield.setText(""); + target.performClick(); + assertFalse(button.isEnabled()); + assertEquals(context.getString(R.string.error), layout.getError()); + textfield.setText("pass"); + target.performClick(); + assertFalse(button.isEnabled()); + assertEquals(context.getString(R.string.error), layout.getError()); + textfield.setText("Pass"); + target.performClick(); + assertTrue(button.isEnabled()); + assertNull(layout.getError()); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java b/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java new file mode 100644 index 0000000000..a5150b5406 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.utils; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.robolectric.Shadows.shadowOf; + +import java.lang.reflect.Field; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.ui.views.ThemedTextView; + +import android.os.Looper; +import android.view.animation.Interpolator; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = 19) +public class AnimUtilsTest { + + @Test + public void testGetFastOutSlowInInterpolator() + throws NoSuchFieldException, IllegalAccessException { + Field f = AnimUtils.class.getDeclaredField("fastOutSlowIn"); + f.setAccessible(true); + assertNull(f.get(null)); + Interpolator result = + AnimUtils.getFastOutSlowInInterpolator(ApplicationProvider.getApplicationContext()); + assertNotNull(result); + assertNotNull(f.get(null)); + } + + @Test + public void testMarqueeAfterDelay() { + ThemedTextView mock = mock(ThemedTextView.class); + doCallRealMethod().when(mock).setSelected(anyBoolean()); + doCallRealMethod().when(mock).isSelected(); + mock.setSelected(false); + + AnimUtils.marqueeAfterDelay(150, mock); + shadowOf(Looper.myLooper()).getScheduler().advanceToLastPostedRunnable(); + assertTrue(mock.isSelected()); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/utils/OpenModeTest.java b/app/src/test/java/com/amaze/filemanager/utils/OpenModeTest.java new file mode 100644 index 0000000000..4f7a66db42 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/utils/OpenModeTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.utils; + +import static com.amaze.filemanager.utils.OpenMode.BOX; +import static com.amaze.filemanager.utils.OpenMode.CUSTOM; +import static com.amaze.filemanager.utils.OpenMode.DROPBOX; +import static com.amaze.filemanager.utils.OpenMode.FILE; +import static com.amaze.filemanager.utils.OpenMode.GDRIVE; +import static com.amaze.filemanager.utils.OpenMode.ONEDRIVE; +import static com.amaze.filemanager.utils.OpenMode.OTG; +import static com.amaze.filemanager.utils.OpenMode.ROOT; +import static com.amaze.filemanager.utils.OpenMode.SFTP; +import static com.amaze.filemanager.utils.OpenMode.SMB; +import static com.amaze.filemanager.utils.OpenMode.UNKNOWN; +import static java.lang.Integer.MAX_VALUE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import org.junit.Test; + +public class OpenModeTest { + + @Test + public void testGetOpenMode() { + assertEquals(UNKNOWN, OpenMode.getOpenMode(0)); + assertEquals(FILE, OpenMode.getOpenMode(1)); + assertEquals(SMB, OpenMode.getOpenMode(2)); + assertEquals(SFTP, OpenMode.getOpenMode(3)); + assertEquals(CUSTOM, OpenMode.getOpenMode(4)); + assertEquals(ROOT, OpenMode.getOpenMode(5)); + assertEquals(OTG, OpenMode.getOpenMode(6)); + assertEquals(GDRIVE, OpenMode.getOpenMode(7)); + assertEquals(DROPBOX, OpenMode.getOpenMode(8)); + assertEquals(BOX, OpenMode.getOpenMode(9)); + assertEquals(ONEDRIVE, OpenMode.getOpenMode(10)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> OpenMode.getOpenMode(-1)); + assertThrows(ArrayIndexOutOfBoundsException.class, () -> OpenMode.getOpenMode(MAX_VALUE)); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.java b/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.java new file mode 100644 index 0000000000..eb6bb15ded --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import com.amaze.filemanager.test.ShadowCryptUtil; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config( + minSdk = 19, + shadows = {ShadowCryptUtil.class}) +public class SmbUtilTest { + + @Test + public void testEncryptDecrypt() throws GeneralSecurityException, IOException { + String path = "smb://root:toor@127.0.0.1"; + String encrypted = + SmbUtil.getSmbEncryptedPath(ApplicationProvider.getApplicationContext(), path); + assertNotEquals(path, encrypted); + assertTrue(encrypted.startsWith("smb://root:")); + assertTrue(encrypted.endsWith("@127.0.0.1")); + String decrypted = + SmbUtil.getSmbDecryptedPath(ApplicationProvider.getApplicationContext(), encrypted); + assertEquals(path, decrypted); + } + + @Test + public void testEncryptWithoutCredentials() throws GeneralSecurityException, IOException { + String path = "smb://127.0.0.1"; + assertEquals( + path, SmbUtil.getSmbEncryptedPath(ApplicationProvider.getApplicationContext(), path)); + } + + @Test + @Ignore("Good idea to fix me") + public void testEncryptWithoutPassword() throws GeneralSecurityException, IOException { + String path = "smb://toor@127.0.0.1"; + assertEquals( + path, SmbUtil.getSmbEncryptedPath(ApplicationProvider.getApplicationContext(), path)); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java b/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java new file mode 100644 index 0000000000..c297ad1a02 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014-2020 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.amaze.filemanager.utils; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = 19) +public class TinyDBTest { + + private SharedPreferences prefs; + + @Before + public void setUp() { + prefs = + PreferenceManager.getDefaultSharedPreferences(ApplicationProvider.getApplicationContext()); + } + + @Test + public void testSaveLoadBooleanArray() { + Boolean[] value = new Boolean[] {true, false, true, false, true, true, false}; + TinyDB.putBooleanArray(prefs, "foobar", value); + Boolean[] result = + TinyDB.getBooleanArray( + prefs, "foobar", new Boolean[] {false, false, false, false, false, false, false}); + assertArrayEquals(value, result); + } + + @Test + public void testLoadBooleanArrayShouldReturnDefaultValue() { + Boolean[] expected = + TinyDB.getBooleanArray( + prefs, "foobaz", new Boolean[] {true, false, true, false, false, false}); + Boolean[] result = TinyDB.getBooleanArray(prefs, "foobaz", expected); + assertArrayEquals(expected, result); + } + + @Test + public void testLoadBooleanArrayShouldReturnDefaultValue2() { + assertNull(TinyDB.getBooleanArray(prefs, "foobam", null)); + } +} diff --git a/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java b/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java index a9895512b7..4a4947f4ab 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java +++ b/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java @@ -20,12 +20,40 @@ package com.amaze.filemanager.utils; +import static android.os.Build.VERSION_CODES.N; import static com.amaze.filemanager.utils.Utils.formatTimer; import static com.amaze.filemanager.utils.Utils.sanitizeInput; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowToast; + +import com.amaze.filemanager.R; +import com.amaze.filemanager.filesystem.HybridFileParcelable; + +import android.net.Uri; +import android.os.Build; +import android.os.storage.StorageVolume; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@RunWith(AndroidJUnit4.class) +@Config(minSdk = 19) public class UtilsTest { @Test public void @@ -59,4 +87,80 @@ public void testFormatTimer() { assertEquals("02:45", formatTimer(165)); assertEquals("30:33", formatTimer(1833)); } + + @Test + public void testDifferenceStrings() { + assertNull(Utils.differenceStrings(null, null)); + assertEquals("abc", Utils.differenceStrings("abc", null)); + assertEquals("abc", Utils.differenceStrings(null, "abc")); + assertEquals("", Utils.differenceStrings("abc12345", "abc")); + assertEquals("", Utils.differenceStrings("pqrstuv345", "pqrstuv")); + assertEquals("12345", Utils.differenceStrings("abc", "abc12345")); + } + + @Test + public void testGetUriForBaseFile() { + HybridFileParcelable file = new HybridFileParcelable("/storage/emulated/0/test.txt"); + for (OpenMode m : new OpenMode[] {OpenMode.FILE, OpenMode.ROOT}) { + file.setMode(m); + Uri uri = Utils.getUriForBaseFile(ApplicationProvider.getApplicationContext(), file); + if (Build.VERSION.SDK_INT < N) { + assertEquals("file:///storage/emulated/0/test.txt", uri.toString()); + } else { + assertEquals( + "content://" + + ApplicationProvider.getApplicationContext().getPackageName() + + "/storage_root/storage/emulated/0/test.txt", + uri.toString()); + } + } + + for (OpenMode m : + new OpenMode[] { + OpenMode.DROPBOX, OpenMode.GDRIVE, OpenMode.ONEDRIVE, OpenMode.SMB, OpenMode.BOX + }) { + file = new HybridFileParcelable("/foo/bar/test.txt"); + file.setMode(m); + assertNull(Utils.getUriForBaseFile(ApplicationProvider.getApplicationContext(), file)); + assertEquals( + ApplicationProvider.getApplicationContext().getString(R.string.smb_launch_error), + ShadowToast.getTextOfLatestToast()); + } + + file.setMode(OpenMode.CUSTOM); + assertNull(Utils.getUriForBaseFile(ApplicationProvider.getApplicationContext(), file)); + } + + @Test + public void testIsNullOrEmptyCollection() { + assertTrue(Utils.isNullOrEmpty((Collection) null)); + assertTrue(Utils.isNullOrEmpty(Collections.EMPTY_SET)); + assertFalse(Utils.isNullOrEmpty(Collections.singletonList(null))); + assertFalse(Utils.isNullOrEmpty(Arrays.asList(new Object()))); + Collection l = new ArrayList(); + l.add(new Object()); + assertFalse(Utils.isNullOrEmpty(l)); + } + + @Test + public void testIsNullOrEmptyString() { + assertTrue(Utils.isNullOrEmpty((String) null)); + assertTrue(Utils.isNullOrEmpty("")); + assertFalse(Utils.isNullOrEmpty("null")); + assertFalse(Utils.isNullOrEmpty("empty")); + assertFalse(Utils.isNullOrEmpty("this is a string")); + } + + @Test + @Config(minSdk = N) + public void testGetVolumeDirectory() throws Exception { + StorageVolume mock = mock(StorageVolume.class); + Field f = StorageVolume.class.getDeclaredField("mPath"); + f.setAccessible(true); + f.set(mock, new File("/storage/emulated/0")); + + File result = Utils.getVolumeDirectory(mock); + assertNotNull(result); + assertEquals(new File("/storage/emulated/0"), result); + } } diff --git a/app/src/test/resources/robolectric.properties b/app/src/test/resources/robolectric.properties new file mode 100644 index 0000000000..6a520f2ee7 --- /dev/null +++ b/app/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +maxSdk=28 \ No newline at end of file diff --git a/app/src/test/resources/test.db b/app/src/test/resources/test.db new file mode 100644 index 0000000000..f86ffa33ed Binary files /dev/null and b/app/src/test/resources/test.db differ diff --git a/build.gradle b/build.gradle index 32441b83c7..d386348feb 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:3.6.4' classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4' // NOTE: Do not place your application dependencies here; they belong @@ -19,6 +19,7 @@ plugins { } allprojects { + repositories { google() jcenter() @@ -55,6 +56,8 @@ configurations { robo25 robo26 robo27 + robo28 + robo29 } dependencies { @@ -69,6 +72,8 @@ dependencies { robo25 "org.robolectric:android-all:7.1.0_r7-robolectric-r1" robo26 "org.robolectric:android-all:8.0.0_r4-robolectric-r1" robo27 "org.robolectric:android-all:8.1.0-robolectric-4611349" + robo28 "org.robolectric:android-all:9-robolectric-4913185-2" + robo29 "org.robolectric:android-all:10-robolectric-5803371" } def robolectricDependencies = "${rootProject.buildDir.path}/robolectric" @@ -85,6 +90,8 @@ task fetchRobolectricDependencies(type: Copy) { from configurations.robo25 from configurations.robo26 from configurations.robo27 + from configurations.robo28 + from configurations.robo29 into robolectricDependencies } @@ -102,5 +109,28 @@ subprojects { it.dependsOn fetchRobolectricDependencies } } + if (project.plugins.hasPlugin("jacoco-android")){ + android { + testOptions.unitTests.all { + jacoco { + excludes = ['jdk.internal.*'] + } + } + } + } + dependencies { + compileOnly 'com.github.pengrad:jdk9-deps:1.0' + + if (project.hasProperty('kapt')) { + kapt 'javax.xml.bind:jaxb-api:2.3.1' + kapt 'com.sun.xml.bind:jaxb-core:2.3.0.1' + kapt 'com.sun.xml.bind:jaxb-impl:2.3.2' + } + + annotationProcessor 'javax.xml.bind:jaxb-api:2.3.1' + annotationProcessor 'com.sun.xml.bind:jaxb-core:2.3.0.1' + annotationProcessor 'com.sun.xml.bind:jaxb-impl:2.3.2' + } } + } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5cbbfbb834..678f09d103 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.useAndroidX=true -android.enableUnitTestBinaryResources=false + # Workaround for Android Gradle Plugin before 3.6.0. # See https://github.com/robolectric/robolectric/issues/5299#issuecomment-543125381 # and https://issuetracker.google.com/issues/142580430 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0708d5ee2..b0225133bb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Sep 24 12:34:34 ART 2019 +#Sun Jul 19 11:09:24 HKT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip