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 org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.amaze.filemanager.fileoperations.filesystem.OpenMode;
+
+import android.os.Parcel;
+
+/** Created by Rustam Khadipash on 29/3/2018. */
+public class HybridFileParcelableTest {
+ private HybridFileParcelable filePath;
+ private HybridFileParcelable directory;
+ private HybridFileParcelable file;
+
+ @Before
+ public void setUp() {
+ filePath = new HybridFileParcelable("/storage/sdcard0/Test1/Test1.txt");
+
+ directory = new HybridFileParcelable("/storage/sdcard0/Test2", "rw", 123456, 654321, true);
+
+ file =
+ new HybridFileParcelable("/storage/sdcard0/Test3/Test3.txt", "rw", 123456, 654321, false);
+ }
+
+ /** Purpose: Get name of a file / directory Input: no Expected: return file / directory's name */
+ @Test
+ public void getName() {
+ assertEquals("Test1.txt", filePath.getName());
+ assertEquals("Test2", directory.getName());
+ assertEquals("Test3.txt", file.getName());
+ }
+
+ /**
+ * Purpose: Change name of a file / directory Input: setName newName Expected: File / directory's
+ * name is changed
+ */
+ @Test
+ public void setName() {
+ filePath.setName("Tset1.txt");
+ assertEquals("Tset1.txt", filePath.getName());
+ directory.setName("Tset2");
+ assertEquals("Tset2", directory.getName());
+ file.setName("Tset3.txt");
+ assertEquals("Tset3.txt", file.getName());
+ }
+
+ /**
+ * Purpose: Get open mode of a file / directory Input: no Expected: return OpenMode.FILE
+ *
+ * All files and directories in this class have open mode set as OpenMode.FILE
+ */
+ @Test
+ public void getMode() {
+ assertEquals(OpenMode.FILE, filePath.getMode());
+ assertEquals(OpenMode.FILE, directory.getMode());
+ assertEquals(OpenMode.FILE, file.getMode());
+ }
+
+ /** Purpose: Get link to a file / directory Input: no Expected: return empty string */
+ @Test
+ public void getLink() {
+ assertEquals("", filePath.getLink());
+ assertEquals("", directory.getLink());
+ assertEquals("", file.getLink());
+ }
+
+ /**
+ * Purpose: Set link to a file / directory Input: setLink newLink Expected: File / directory's
+ * link is changed
+ */
+ @Test
+ public void setLink() {
+ filePath.setLink("abc");
+ assertEquals("abc", filePath.getLink());
+ directory.setLink("def");
+ assertEquals("def", directory.getLink());
+ file.setLink("ghi");
+ assertEquals("ghi", file.getLink());
+ }
+
+ /** Purpose: Get creation date of a file / directory Input: no Expected: return date */
+ @Test
+ public void getDate() {
+ assertEquals(0, filePath.getDate());
+ assertEquals(123456, directory.getDate());
+ assertEquals(123456, file.getDate());
+ }
+
+ /**
+ * Purpose: Change creation date of a file / directory Input: setDate newDate Expected: File /
+ * directory's creation date is changed
+ */
+ @Test
+ public void setDate() {
+ filePath.setDate(746352);
+ assertEquals(746352, filePath.getDate());
+ directory.setDate(474587);
+ assertEquals(474587, directory.getDate());
+ file.setDate(3573335);
+ assertEquals(3573335, file.getDate());
+ }
+
+ /** Purpose: Get size of a file / directory Input: no Expected: return size */
+ @Test
+ public void getSize() {
+ assertEquals(0, filePath.getSize());
+ assertEquals(654321, directory.getSize());
+ assertEquals(654321, file.getSize());
+ }
+
+ /**
+ * Purpose: Change size of a file / directory Input: setSize newSize Expected: File / directory's
+ * size is changed
+ */
+ @Test
+ public void setSize() {
+ filePath.setSize(3534546);
+ assertEquals(3534546, filePath.getSize());
+ directory.setSize(1745534);
+ assertEquals(1745534, directory.getSize());
+ file.setSize(7546543);
+ assertEquals(7546543, file.getSize());
+ }
+
+ /** Purpose: Check whether it is a file or directory Input: no Expected: return directory */
+ @Test
+ public void isDirectory() {
+ assertEquals(false, filePath.isDirectory());
+ assertEquals(true, directory.isDirectory());
+ assertEquals(false, file.isDirectory());
+ }
+
+ /**
+ * Purpose: Change type to file / directory Input: setDirectory isDirectory Expected: File /
+ * directory's type is changed
+ */
+ @Test
+ public void setDirectory() {
+ filePath.setDirectory(true);
+ assertEquals(true, filePath.isDirectory());
+ directory.setDirectory(false);
+ assertEquals(false, directory.isDirectory());
+ file.setDirectory(true);
+ assertEquals(true, file.isDirectory());
+ }
+
+ /** Purpose: Get path to a file / directory Input: no Expected: return path */
+ @Test
+ public void getPath() {
+ assertEquals("/storage/sdcard0/Test1/Test1.txt", filePath.getPath());
+ assertEquals("/storage/sdcard0/Test2", directory.getPath());
+ assertEquals("/storage/sdcard0/Test3/Test3.txt", file.getPath());
+ }
+
+ /** Purpose: Get file / directory's permissions Input: no Expected: return permissions */
+ @Test
+ public void getPermission() {
+ assertEquals(null, filePath.getPermission());
+ assertEquals("rw", directory.getPermission());
+ assertEquals("rw", file.getPermission());
+ }
+
+ /**
+ * Purpose: Change permissions of a file / directory Input: setPermission newPermission Expected:
+ * File / directory's permissions are changed
+ */
+ @Test
+ public void setPermission() {
+ filePath.setPermission("rwx");
+ assertEquals("rwx", filePath.getPermission());
+ directory.setPermission("rwx");
+ assertEquals("rwx", directory.getPermission());
+ file.setPermission("rwx");
+ assertEquals("rwx", file.getPermission());
+ }
+
+ /**
+ * Purpose: Write an object into a parcel, send it through an intent and read the object from the
+ * parcel Input: writeToParcel parcel object Expected: The parcel can be sent and the object can
+ * be extracted from the parcel
+ */
+ @Test
+ public void writeToParcel() {
+ Parcel parcel = Parcel.obtain();
+ file.writeToParcel(parcel, file.describeContents());
+ parcel.setDataPosition(0);
+
+ HybridFileParcelable createdFromParcel = HybridFileParcelable.CREATOR.createFromParcel(parcel);
+ assertEquals(file.getDate(), createdFromParcel.getDate());
+ assertEquals(file.getLink(), createdFromParcel.getLink());
+ assertEquals(file.getMode(), createdFromParcel.getMode());
+ assertEquals(file.getName(), createdFromParcel.getName());
+ assertEquals(file.getPath(), createdFromParcel.getPath());
+ assertEquals(file.getPermission(), createdFromParcel.getPermission());
+ assertEquals(file.getSize(), createdFromParcel.getSize());
+ assertEquals(file.isDirectory(), createdFromParcel.isDirectory());
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/CryptUtilTest.java b/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/CryptUtilTest.java
new file mode 100644
index 0000000..7b7728b
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/CryptUtilTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014-2024 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.files;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.amaze.filemanager.BuildConfig;
+import com.amaze.filemanager.utils.PasswordUtil;
+
+import android.content.Context;
+import android.util.Base64;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+@RunWith(AndroidJUnit4.class)
+public class CryptUtilTest {
+
+ private Context context;
+
+ @Before
+ public void setUp() {
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ @Test
+ public void testIvValueIsCorrect() {
+ assertEquals("LxbHiJhhUXcj", BuildConfig.CRYPTO_IV);
+ }
+
+ @Test
+ public void testEncryptDecrypt() throws Exception {
+ String password = "hackme";
+ String encrypted = PasswordUtil.INSTANCE.encryptPassword(context, password, Base64.URL_SAFE);
+ assertEquals(
+ password, PasswordUtil.INSTANCE.decryptPassword(context, encrypted, Base64.URL_SAFE));
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/GenericCopyUtilEspressoTest.java b/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/GenericCopyUtilEspressoTest.java
new file mode 100644
index 0000000..5ff4562
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/filesystem/files/GenericCopyUtilEspressoTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014-2024 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.files;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.amaze.filemanager.asynchronous.management.ServiceWatcherUtil;
+import com.amaze.filemanager.test.DummyFileGenerator;
+import com.amaze.filemanager.utils.ProgressHandler;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+@RunWith(AndroidJUnit4.class)
+public class GenericCopyUtilEspressoTest {
+
+ private GenericCopyUtil copyUtil;
+
+ private File file1, file2;
+
+ @Before
+ public void setUp() throws IOException {
+ copyUtil =
+ new GenericCopyUtil(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), new ProgressHandler());
+ file1 = File.createTempFile("test", "bin");
+ file2 = File.createTempFile("test", "bin");
+ file1.deleteOnExit();
+ file2.deleteOnExit();
+ }
+
+ @Test
+ public void testCopyFile1() throws IOException, NoSuchAlgorithmException {
+ doTestCopyFile1(512);
+ doTestCopyFile1(10 * 1024 * 1024);
+ }
+
+ @Test
+ public void testCopyFile2() throws IOException, NoSuchAlgorithmException {
+ doTestCopyFile2(512);
+ doTestCopyFile2(10 * 1024 * 1024);
+ }
+
+ @Test
+ public void testCopyFile3() throws IOException, NoSuchAlgorithmException {
+ doTestCopyFile3(512);
+ doTestCopyFile3(10 * 1024 * 1024);
+ }
+
+ // doCopy(ReadableByteChannel in, WritableByteChannel out)
+ private void doTestCopyFile1(int size) throws IOException, NoSuchAlgorithmException {
+ byte[] checksum = DummyFileGenerator.createFile(file1, size);
+ copyUtil.doCopy(
+ new FileInputStream(file1).getChannel(),
+ Channels.newChannel(new FileOutputStream(file2)),
+ ServiceWatcherUtil.UPDATE_POSITION);
+ assertEquals(file1.length(), file2.length());
+ assertSha1Equals(checksum, file2);
+ }
+
+ // copy(FileChannel in, FileChannel out)
+ private void doTestCopyFile2(int size) throws IOException, NoSuchAlgorithmException {
+ byte[] checksum = DummyFileGenerator.createFile(file1, size);
+ copyUtil.copyFile(
+ new FileInputStream(file1).getChannel(),
+ new FileOutputStream(file2).getChannel(),
+ ServiceWatcherUtil.UPDATE_POSITION);
+ assertEquals(file1.length(), file2.length());
+ assertSha1Equals(checksum, file2);
+ }
+
+ // copy(BufferedInputStream in, BufferedOutputStream out)
+ private void doTestCopyFile3(int size) throws IOException, NoSuchAlgorithmException {
+ byte[] checksum = DummyFileGenerator.createFile(file1, size);
+ copyUtil.copyFile(
+ new BufferedInputStream(new FileInputStream(file1)),
+ new BufferedOutputStream(new FileOutputStream(file2)),
+ ServiceWatcherUtil.UPDATE_POSITION);
+ assertEquals(file1.length(), file2.length());
+ assertSha1Equals(checksum, file2);
+ }
+
+ private void assertSha1Equals(byte[] expected, File file)
+ throws NoSuchAlgorithmException, IOException {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ DigestInputStream in = new DigestInputStream(new FileInputStream(file), md);
+ byte[] buffer = new byte[GenericCopyUtil.DEFAULT_BUFFER_SIZE];
+ while (in.read(buffer) > -1) {}
+ in.close();
+ assertArrayEquals(expected, md.digest());
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/ssh/SshClientUtilTest.java b/app/src/androidTest/java/com/amaze/filemanager/ssh/SshClientUtilTest.java
new file mode 100644
index 0000000..42774f9
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/ssh/SshClientUtilTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014-2024 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 static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.amaze.filemanager.filesystem.ftp.NetCopyClientUtils;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+public class SshClientUtilTest {
+
+ @Test
+ public void testEncryptDecryptUriWithNoPassword() {
+ String uri = "ssh://testuser@127.0.0.1:22";
+ assertEquals(uri, NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri));
+ assertEquals(uri, NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri));
+ }
+
+ @Test
+ public void testEncryptDecryptPasswordWithMinusSign1() {
+ String uri = "ssh://testuser:abcd-efgh@127.0.0.1:22";
+ String result = NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri);
+ assertTrue(result.contains("ssh://testuser:"));
+ assertTrue(result.contains("@127.0.0.1:22"));
+ String verify = NetCopyClientUtils.INSTANCE.decryptFtpPathAsNecessary(result);
+ assertEquals(uri, verify);
+ }
+
+ @Test
+ public void testEncryptDecryptPasswordWithMinusSign2() {
+ String uri = "ssh://testuser:---------------@127.0.0.1:22";
+ String result = NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri);
+ assertTrue(result.contains("ssh://testuser:"));
+ assertTrue(result.contains("@127.0.0.1:22"));
+ String verify = NetCopyClientUtils.INSTANCE.decryptFtpPathAsNecessary(result);
+ assertEquals(uri, verify);
+ }
+
+ @Test
+ public void testEncryptDecryptPasswordWithMinusSign3() {
+ String uri = "ssh://testuser:--agdiuhdpost15@127.0.0.1:22";
+ String result = NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri);
+ assertTrue(result.contains("ssh://testuser:"));
+ assertTrue(result.contains("@127.0.0.1:22"));
+ String verify = NetCopyClientUtils.INSTANCE.decryptFtpPathAsNecessary(result);
+ assertEquals(uri, verify);
+ }
+
+ @Test
+ public void testEncryptDecryptPasswordWithMinusSign4() {
+ String uri = "ssh://testuser:t-h-i-s-i-s-p-a-s-s-w-o-r-d-@127.0.0.1:22";
+ String result = NetCopyClientUtils.INSTANCE.encryptFtpPathAsNecessary(uri);
+ assertTrue(result.contains("ssh://testuser:"));
+ assertTrue(result.contains("@127.0.0.1:22"));
+ String verify = NetCopyClientUtils.INSTANCE.decryptFtpPathAsNecessary(result);
+ assertEquals(uri, verify);
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/test/DummyFileGenerator.java b/app/src/androidTest/java/com/amaze/filemanager/test/DummyFileGenerator.java
new file mode 100644
index 0000000..43f6591
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/test/DummyFileGenerator.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014-2024 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.test;
+
+import static com.amaze.filemanager.filesystem.files.GenericCopyUtil.DEFAULT_BUFFER_SIZE;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Generate file of specified size using randomly generated bytes.
+ *
+ * Because of the need that both Espresso and Robolectric tests depends on it, it needs to be
+ * placed at the main source tree, and hide it using {@link VisibleForTesting}.
+ */
+@VisibleForTesting(otherwise = VisibleForTesting.NONE)
+@RestrictTo(RestrictTo.Scope.TESTS)
+public abstract class DummyFileGenerator {
+
+ /**
+ * @param destFile File to be generated with random bytes
+ * @param size file size
+ * @return SHA1 checksum of the generated file, as byte array
+ * @throws IOException in case any I/O error occurred
+ */
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ @RestrictTo(RestrictTo.Scope.TESTS)
+ public static byte[] createFile(@NonNull File destFile, int size) throws IOException {
+ Random rand = new SecureRandom();
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException shouldNeverHappen) {
+ throw new IOException("SHA-1 implementation not found");
+ }
+
+ FileOutputStream out = new FileOutputStream(destFile);
+ DigestOutputStream dout = new DigestOutputStream(out, md);
+ int count = 0;
+ for (int i = size; i >= 0; i -= DEFAULT_BUFFER_SIZE, count += DEFAULT_BUFFER_SIZE) {
+ byte[] bytes = new byte[i > DEFAULT_BUFFER_SIZE ? DEFAULT_BUFFER_SIZE : i];
+ rand.nextBytes(bytes);
+ dout.write(bytes);
+ }
+ dout.flush();
+ dout.close();
+
+ return md.digest();
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/test/StoragePermissionHelper.kt b/app/src/androidTest/java/com/amaze/filemanager/test/StoragePermissionHelper.kt
new file mode 100644
index 0000000..c71d892
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/test/StoragePermissionHelper.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014-2022 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.test
+
+// import android.content.Intent
+// import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+// import android.net.Uri
+// import android.os.Build
+// import android.os.Build.VERSION.SDK_INT
+// import android.os.Environment
+// import android.provider.Settings
+// import android.widget.Switch
+// import androidx.test.platform.app.InstrumentationRegistry
+// import androidx.test.uiautomator.UiDevice
+// import androidx.test.uiautomator.UiSelector
+// import org.junit.Assert.assertTrue
+
+object StoragePermissionHelper {
+ /**
+ * This method is intended for Android R or above devices to obtain MANAGE_EXTERNAL_STORAGE
+ * permission via UI Automator framework when running relevant Espresso tests.
+ *
+ * This method is flat commented out because UI Automator requires Android SDK 18, while
+ * currently we still want to support SDK 14.
+ */
+ @JvmStatic
+ fun obtainManageAppAllFileAccessPermissionAutomatically() {
+// if (!Environment.isExternalStorageManager() && SDK_INT > Build.VERSION_CODES.R) {
+// InstrumentationRegistry.getInstrumentation().run {
+// val device = androidx.test.uiautomator.UiDevice.getInstance(this)
+// val context = this.targetContext
+// device.pressHome()
+// val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
+// .setData(Uri.parse("package:${context.packageName}"))
+// .addFlags(FLAG_ACTIVITY_NEW_TASK)
+// context.startActivity(intent)
+// val switch = device.findObject(
+// androidx.test.uiautomator.UiSelector()
+// .packageName("com.android.settings")
+// .className(Switch::class.java.name)
+// .resourceId("android:id/switch_widget")
+// )
+// switch.click()
+// assertTrue(switch.isChecked)
+// device.pressHome()
+// }
+// }
+// assertTrue(Environment.isExternalStorageManager())
+ return // Try to get codacy happy if they ever check me... pretend I am doing something
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/ui/activities/TextEditorActivityEspressoTest.java b/app/src/androidTest/java/com/amaze/filemanager/ui/activities/TextEditorActivityEspressoTest.java
new file mode 100644
index 0000000..e88eab8
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/ui/activities/TextEditorActivityEspressoTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014-2024 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 org.junit.Assert.assertNotEquals;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.amaze.filemanager.ui.activities.texteditor.TextEditorActivity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Suppress
+// Have to rewrite to cope with Android 11 storage access model
+public class TextEditorActivityEspressoTest {
+
+ @Rule
+ public ActivityTestRule activityRule =
+ new ActivityTestRule<>(TextEditorActivity.class, true, false);
+
+ private Context context;
+
+ private Uri uri;
+
+ @Before
+ public void setUp() {
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ File file = new File("/default.prop");
+ uri = Uri.fromFile(file);
+ }
+
+ @Test
+ public void testOpenFile() throws Exception {
+ Intent intent =
+ new Intent(context, TextEditorActivity.class)
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_DEFAULT)
+ .setType("text/plain")
+ .setData(uri);
+ activityRule.launchActivity(intent);
+ CountDownLatch waiter = new CountDownLatch(1);
+ while ("".equals(activityRule.getActivity().mainTextView.getText().toString())) {
+ waiter.await();
+ }
+ waiter.countDown();
+ assertNotEquals("", activityRule.getActivity().mainTextView.getText());
+ assertNotEquals("foobar", activityRule.getActivity().mainTextView.getText());
+ // Add extra time for you to see the Activity did load, and text is actually there
+ // Thread.sleep(1000);
+ }
+}
diff --git a/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/BackupPrefsFragmentTest.kt b/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/BackupPrefsFragmentTest.kt
new file mode 100644
index 0000000..027f5c5
--- /dev/null
+++ b/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/BackupPrefsFragmentTest.kt
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2014-2022 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 android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.net.Uri
+import androidx.lifecycle.Lifecycle
+import androidx.preference.PreferenceManager
+import androidx.test.core.app.ActivityScenario
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.amaze.filemanager.R
+import com.amaze.filemanager.ui.activities.PreferencesActivity
+import com.amaze.filemanager.ui.fragments.preferencefragments.BackupPrefsFragment
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.io.File
+
+@RunWith(AndroidJUnit4::class)
+class BackupPrefsFragmentTest {
+ var storagePath = "/storage/emulated/0"
+ var fileName = "amaze_backup.json"
+
+ /** Test exporting */
+ @Test
+ fun testExport() {
+ val backupPrefsFragment = BackupPrefsFragment()
+
+ val activityScenario = ActivityScenario.launch(PreferencesActivity::class.java)
+
+ activityScenario.moveToState(Lifecycle.State.STARTED)
+
+ val exportFile =
+ File(
+ storagePath +
+ File.separator +
+ fileName,
+ )
+
+ exportFile.delete() // delete if already exists
+
+ activityScenario.onActivity {
+ it.supportFragmentManager.beginTransaction()
+ .add(backupPrefsFragment, null)
+ .commitNow()
+
+ backupPrefsFragment.exportPrefs()
+ }
+
+ val tempFile =
+ File(
+ ApplicationProvider.getApplicationContext().cacheDir.absolutePath +
+ File.separator +
+ fileName,
+ )
+
+ Assert.assertTrue(tempFile.exists())
+
+ // terrible hack :cringe:
+ onView(withId(R.id.home)).perform(ViewActions.click())
+ Thread.sleep(500)
+
+ onView(withText(R.string.save)).perform(ViewActions.click())
+ Thread.sleep(500)
+
+ Assert.assertTrue(exportFile.exists())
+ }
+
+ /** Test whether the exported file contains the expected preference values */
+ @Test
+ fun verifyExportFile() {
+ val backupPrefsFragment = BackupPrefsFragment()
+
+ val activityScenario = ActivityScenario.launch(PreferencesActivity::class.java)
+
+ activityScenario.moveToState(Lifecycle.State.STARTED)
+
+ val file =
+ File(
+ storagePath +
+ File.separator +
+ fileName,
+ )
+
+ activityScenario.onActivity { preferencesActivity ->
+ preferencesActivity.supportFragmentManager.beginTransaction()
+ .add(backupPrefsFragment, null)
+ .commitNow()
+
+ val preferences =
+ PreferenceManager
+ .getDefaultSharedPreferences(preferencesActivity)
+
+ val preferenceMap: Map = preferences.all
+
+ val inputString =
+ file
+ .inputStream()
+ .bufferedReader()
+ .use {
+ it.readText()
+ }
+
+ val type = object : TypeToken