more build system updates, ditch unused android tests
This commit is contained in:
parent
8d36a6c613
commit
13e9e91fdc
|
@ -75,22 +75,6 @@ dependencies {
|
|||
}
|
||||
testImplementation 'org.mockito:mockito-core:2.18.0'
|
||||
|
||||
// UI testing with Espresso
|
||||
// Force usage of support libs in the test app, since they are internally used by the runner module.
|
||||
// https://github.com/googlesamples/android-testing/blob/master/ui/espresso/BasicSample/app/build.gradle#L28
|
||||
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
|
||||
androidTestImplementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
androidTestImplementation 'com.google.android.material:material:1.1.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
|
||||
androidTestCompile ('androidx.test.espresso:espresso-contrib:3.1.0') {
|
||||
exclude group: 'com.android.support', module: 'appcompat'
|
||||
exclude group: 'com.android.support', module: 'support-v4'
|
||||
exclude module: 'recyclerview-v7'
|
||||
}
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
||||
implementation 'org.glassfish:javax.annotation:10.0-b28'
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.matcher.ViewMatchers;
|
||||
import android.view.View;
|
||||
|
||||
import com.nispok.snackbar.Snackbar;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.endsWith;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSnackbarLineColor;
|
||||
|
||||
|
||||
public class AndroidTestHelpers {
|
||||
|
||||
public static void dismissSnackbar() {
|
||||
onView(withClassName(endsWith("Snackbar")))
|
||||
.perform(new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return ViewMatchers.isAssignableFrom(Snackbar.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "dismiss snackbar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
((Snackbar) view).dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void checkSnackbar(Style style, @StringRes Integer text) {
|
||||
|
||||
onView(withClassName(endsWith("Snackbar")))
|
||||
.check(matches(withSnackbarLineColor(style.mLineColor)));
|
||||
|
||||
if (text != null) {
|
||||
onView(withClassName(endsWith("Snackbar")))
|
||||
.check(matches(hasDescendant(withText(text))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void checkAndDismissSnackbar(Style style, @StringRes Integer text) {
|
||||
checkSnackbar(style, text);
|
||||
dismissSnackbar();
|
||||
}
|
||||
|
||||
public static void importKeysFromResource(Context context, String name) throws Exception {
|
||||
IteratorWithIOThrow<UncachedKeyRing> stream = UncachedKeyRing.fromStream(
|
||||
getInstrumentation().getContext().getAssets().open(name));
|
||||
|
||||
KeyWritableRepository helper = KeyWritableRepository.create(context);
|
||||
while(stream.hasNext()) {
|
||||
UncachedKeyRing ring = stream.next();
|
||||
if (ring.isSecret()) {
|
||||
helper.saveSecretKeyRing(ring);
|
||||
} else {
|
||||
helper.savePublicKeyRing(ring);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void copyFiles() throws IOException {
|
||||
File cacheDir = getInstrumentation().getTargetContext().getFilesDir();
|
||||
byte[] buf = new byte[256];
|
||||
for (String filename : FILES) {
|
||||
File outFile = new File(cacheDir, filename);
|
||||
if (outFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
InputStream in = new BufferedInputStream(getInstrumentation().getContext().getAssets().open(filename));
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
|
||||
int len;
|
||||
while( (len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final String[] FILES = new String[] { "pa.png", "re.png", "ci.png" };
|
||||
public static File[] getImageNames() {
|
||||
File cacheDir = getInstrumentation().getTargetContext().getFilesDir();
|
||||
File[] ret = new File[FILES.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = new File(cacheDir, FILES[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static <T> T pickRandom(T[] haystack) {
|
||||
return haystack[new Random().nextInt(haystack.length)];
|
||||
}
|
||||
|
||||
public static String randomString(int min, int max) {
|
||||
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789!@#$%^&*()-_=";
|
||||
Random r = new Random();
|
||||
StringBuilder passbuilder = new StringBuilder();
|
||||
// 5% chance for an empty string
|
||||
for(int i = 0, j = r.nextInt(max)+min; i < j; i++) {
|
||||
passbuilder.append(chars.charAt(r.nextInt(chars.length())));
|
||||
}
|
||||
return passbuilder.toString();
|
||||
}
|
||||
|
||||
public static void cleanupForTests(Context context) throws Exception {
|
||||
|
||||
// KeychainDatabase.getInstance(context).clearDatabase();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(context, "x.sec.asc");
|
||||
|
||||
// make sure no passphrases are cached
|
||||
PassphraseCacheService.clearCachedPassphrases(context);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package org.sufficientlysecure.keychain;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.test.runner.AndroidJUnitRunner;
|
||||
|
||||
|
||||
public class JacocoWorkaroundJUnitRunner extends AndroidJUnitRunner {
|
||||
static {
|
||||
System.setProperty("jacoco-agent.destfile", "/data/data/"
|
||||
+ BuildConfig.APPLICATION_ID + "/coverage.ec");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(int resultCode, Bundle results) {
|
||||
try {
|
||||
Class rt = Class.forName("org.jacoco.agent.rt.RT");
|
||||
Method getAgent = rt.getMethod("getAgent");
|
||||
Method dump = getAgent.getReturnType().getMethod("dump", boolean.class);
|
||||
Object agent = getAgent.invoke(null);
|
||||
dump.invoke(agent, false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
super.finish(resultCode, results);
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.actions;
|
||||
|
||||
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.espresso.matcher.ViewMatchers;
|
||||
import android.view.View;
|
||||
|
||||
import com.tokenautocomplete.TokenCompleteTextView;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getTargetContext;
|
||||
|
||||
|
||||
public abstract class CustomActions {
|
||||
|
||||
public static ViewAction tokenEncryptViewAddToken(long keyId) throws Exception {
|
||||
CanonicalizedPublicKeyRing ring =
|
||||
KeyWritableRepository.create(getTargetContext()).getCanonicalizedPublicKeyRing(keyId);
|
||||
final Object item = new KeyAdapter.KeyItem(ring);
|
||||
|
||||
return new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return ViewMatchers.isAssignableFrom(TokenCompleteTextView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "add completion token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
((TokenCompleteTextView) view).addObject(item);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static ViewAction tokenViewAddToken(final Object item) {
|
||||
return new ViewAction() {
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return ViewMatchers.isAssignableFrom(TokenCompleteTextView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "add completion token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
((TokenCompleteTextView) view).addObject(item);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package org.sufficientlysecure.keychain.actions;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import androidx.test.espresso.UiController;
|
||||
import androidx.test.espresso.ViewAction;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
import android.view.View;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
|
||||
public class OrientationChangeAction implements ViewAction {
|
||||
private final int orientation;
|
||||
|
||||
private OrientationChangeAction(int orientation) {
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matcher<View> getConstraints() {
|
||||
return isRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "change orientation to " + orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform(UiController uiController, View view) {
|
||||
uiController.loopMainThreadUntilIdle();
|
||||
|
||||
final Activity activity = findActivity(view.getContext());
|
||||
if (activity == null){
|
||||
throw new IllegalStateException("Could not find the current activity");
|
||||
}
|
||||
|
||||
activity.setRequestedOrientation(orientation);
|
||||
|
||||
Collection<Activity> resumedActivities = ActivityLifecycleMonitorRegistry
|
||||
.getInstance().getActivitiesInStage(Stage.RESUMED);
|
||||
|
||||
if (resumedActivities.isEmpty()) {
|
||||
throw new RuntimeException("Could not change orientation");
|
||||
}
|
||||
}
|
||||
|
||||
private static Activity findActivity(Context context) {
|
||||
if (context == null)
|
||||
return null;
|
||||
else if (context instanceof Activity)
|
||||
return (Activity) context;
|
||||
else if (context instanceof ContextWrapper)
|
||||
return findActivity(((ContextWrapper) context).getBaseContext());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ViewAction orientationLandscape() {
|
||||
return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
|
||||
public static ViewAction orientationPortrait() {
|
||||
return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* From the droidcon anroid espresso repository.
|
||||
* https://github.com/xrigau/droidcon-android-espresso/
|
||||
*
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.matcher;
|
||||
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
|
||||
public class BitmapMatcher extends TypeSafeMatcher<View> {
|
||||
|
||||
private final Bitmap mBitmap;
|
||||
|
||||
public BitmapMatcher(Bitmap bitmap) {
|
||||
super(View.class);
|
||||
mBitmap = bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(View view) {
|
||||
if ( !(view instanceof ImageView) ) {
|
||||
return false;
|
||||
}
|
||||
Drawable drawable = ((ImageView) view).getDrawable();
|
||||
return drawable != null && (drawable instanceof BitmapDrawable)
|
||||
&& ((BitmapDrawable) drawable).getBitmap().sameAs(mBitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with equivalent specified bitmap");
|
||||
}
|
||||
|
||||
public static BitmapMatcher withBitmap(Bitmap bitmap) {
|
||||
return new BitmapMatcher(bitmap);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.matcher;
|
||||
|
||||
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.test.espresso.matcher.BoundedMatcher;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import com.nispok.snackbar.Snackbar;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.sufficientlysecure.keychain.matcher.DrawableMatcher.withDrawable;
|
||||
|
||||
|
||||
public abstract class CustomMatchers {
|
||||
|
||||
public static Matcher<View> withDisplayedChild(final int child) {
|
||||
return new BoundedMatcher<View, ViewAnimator>(ViewAnimator.class) {
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with displayed child: " + child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(ViewAnimator viewAnimator) {
|
||||
return viewAnimator.getDisplayedChild() == child;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<View> withSnackbarLineColor(@ColorRes final int colorRes) {
|
||||
return new BoundedMatcher<View, Snackbar>(Snackbar.class) {
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with color resource id: " + colorRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(Snackbar snackbar) {
|
||||
return snackbar.getResources().getColor(colorRes) == snackbar.getLineColor();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<Object> withKeyItemId(final long keyId) {
|
||||
return new BoundedMatcher<Object, KeyItem>(KeyItem.class) {
|
||||
@Override
|
||||
public boolean matchesSafely(KeyItem item) {
|
||||
return item.mKeyId == keyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with key id: " + keyId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<RecyclerView.ViewHolder> withKeyHolderId(final long keyId) {
|
||||
return new BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder>(RecyclerView.ViewHolder.class) {
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with ViewHolder id: " + keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(View item) {
|
||||
return item.getItemId() == keyId;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<View> withKeyToken(@ColorRes final long keyId) {
|
||||
return new BoundedMatcher<View, EncryptKeyCompletionView>(EncryptKeyCompletionView.class) {
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with key id token: " + keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(EncryptKeyCompletionView tokenView) {
|
||||
for (Object object : tokenView.getObjects()) {
|
||||
if (object instanceof KeyItem && ((KeyItem) object).mKeyId == keyId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<View> withRecyclerView(@IdRes int viewId) {
|
||||
return allOf(isAssignableFrom(RecyclerView.class), withId(viewId));
|
||||
}
|
||||
|
||||
public static Matcher<View> isRecyclerItemView(@IdRes int recyclerId, Matcher<View> specificChildMatcher) {
|
||||
return allOf(withParent(withRecyclerView(recyclerId)), specificChildMatcher);
|
||||
}
|
||||
|
||||
public static Matcher<View> withEncryptionStatus(boolean encrypted) {
|
||||
|
||||
if (encrypted) {
|
||||
return allOf(
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_encryption_text), withText(R.string.decrypt_result_encrypted))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_encryption_icon), withDrawable(R.drawable.status_lock_closed_24dp, true)))
|
||||
);
|
||||
} else {
|
||||
return allOf(
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_encryption_text), withText(R.string.decrypt_result_not_encrypted))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_encryption_icon), withDrawable(R.drawable.status_lock_open_24dp, true)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static Matcher<View> withSignatureNone() {
|
||||
|
||||
return allOf(
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_text), withText(R.string.decrypt_result_no_signature))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_icon), withDrawable(R.drawable.status_signature_invalid_cutout_24dp, true))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_layout), not(isDisplayed())))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public static Matcher<View> withSignatureMyKey() {
|
||||
|
||||
return allOf(
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_text), withText(R.string.decrypt_result_signature_certified))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_icon), withDrawable(R.drawable.status_signature_verified_cutout_24dp, true))),
|
||||
hasDescendant(allOf(
|
||||
withId(R.id.result_signature_layout), isDisplayed()))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Xavi Rigau <xrigau@gmail.com>
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* From the droidcon anroid espresso repository.
|
||||
* https://github.com/xrigau/droidcon-android-espresso/
|
||||
*
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.matcher;
|
||||
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
|
||||
public class DrawableMatcher extends TypeSafeMatcher<View> {
|
||||
|
||||
private final int mResourceId;
|
||||
private final boolean mIgnoreFilters;
|
||||
|
||||
public DrawableMatcher(int resourceId, boolean ignoreFilters) {
|
||||
super(View.class);
|
||||
mResourceId = resourceId;
|
||||
mIgnoreFilters = ignoreFilters;
|
||||
}
|
||||
|
||||
private String resourceName = null;
|
||||
private Drawable expectedDrawable = null;
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(View target) {
|
||||
if (expectedDrawable == null) {
|
||||
loadDrawableFromResources(target.getResources());
|
||||
}
|
||||
if (invalidExpectedDrawable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target instanceof ImageView) {
|
||||
return hasImage((ImageView) target) || hasBackground(target);
|
||||
}
|
||||
if (target instanceof TextView) {
|
||||
return hasCompoundDrawable((TextView) target) || hasBackground(target);
|
||||
}
|
||||
return hasBackground(target);
|
||||
}
|
||||
|
||||
private void loadDrawableFromResources(Resources resources) {
|
||||
try {
|
||||
expectedDrawable = resources.getDrawable(mResourceId);
|
||||
resourceName = resources.getResourceEntryName(mResourceId);
|
||||
} catch (Resources.NotFoundException ignored) {
|
||||
// view could be from a context unaware of the resource id.
|
||||
}
|
||||
}
|
||||
|
||||
private boolean invalidExpectedDrawable() {
|
||||
return expectedDrawable == null;
|
||||
}
|
||||
|
||||
private boolean hasImage(ImageView target) {
|
||||
return isSameDrawable(target.getDrawable());
|
||||
}
|
||||
|
||||
private boolean hasCompoundDrawable(TextView target) {
|
||||
for (Drawable drawable : target.getCompoundDrawables()) {
|
||||
if (isSameDrawable(drawable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasBackground(View target) {
|
||||
return isSameDrawable(target.getBackground());
|
||||
}
|
||||
|
||||
private boolean isSameDrawable(Drawable drawable) {
|
||||
if (drawable == null) {
|
||||
return false;
|
||||
}
|
||||
// if those are both bitmap drawables, compare their bitmaps (ignores color filters, which is what we want!)
|
||||
if (mIgnoreFilters && drawable instanceof BitmapDrawable && expectedDrawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable) drawable).getBitmap().sameAs((((BitmapDrawable) expectedDrawable).getBitmap()));
|
||||
}
|
||||
return expectedDrawable.getConstantState().equals(drawable.getConstantState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with drawable from resource id: ");
|
||||
description.appendValue(mResourceId);
|
||||
if (resourceName != null) {
|
||||
description.appendText("[");
|
||||
description.appendText(resourceName);
|
||||
description.appendText("]");
|
||||
}
|
||||
}
|
||||
|
||||
public static DrawableMatcher withDrawable(int resourceId, boolean ignoreFilters) {
|
||||
return new DrawableMatcher(resourceId, ignoreFilters);
|
||||
}
|
||||
public static DrawableMatcher withDrawable(int resourceId) {
|
||||
return new DrawableMatcher(resourceId, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.matcher;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.method.TransformationMethod;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
public class EditTextMatchers {
|
||||
|
||||
public static TypeSafeMatcher<View> withError(final int errorResId) {
|
||||
return new TypeSafeMatcher<View>() {
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(View view) {
|
||||
Context context = view.getContext();
|
||||
|
||||
if (view instanceof EditText) {
|
||||
CharSequence error = ((EditText) view).getError();
|
||||
return error != null && error.equals(context.getString(errorResId));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("EditText with error");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static TypeSafeMatcher<View> withTransformationMethod(final Class<? extends TransformationMethod> transformationClass) {
|
||||
return new TypeSafeMatcher<View>() {
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(View view) {
|
||||
if (view instanceof EditText) {
|
||||
TransformationMethod transformation = ((EditText) view).getTransformationMethod();
|
||||
return transformation != null && transformationClass.isInstance(transformation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("EditText with transformation method");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package org.sufficientlysecure.keychain.remote;
|
||||
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.openintents.openpgp.IOpenPgpService2;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import static androidx.test.espresso.Espresso.closeSoftKeyboard;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.cleanupForTests;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class OpenPgpServiceTest {
|
||||
|
||||
public static final int ACTIVITY_WAIT_TIME = 2 * 1000;
|
||||
|
||||
@Rule
|
||||
public final ServiceTestRule mServiceRule = new ServiceTestRule();
|
||||
|
||||
private OpenPgpApi mApi;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Context context = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
cleanupForTests(context);
|
||||
|
||||
Intent serviceIntent = new Intent(context, OpenPgpService2.class);
|
||||
IBinder binder = mServiceRule.bindService(serviceIntent);
|
||||
|
||||
mApi = new OpenPgpApi(context, IOpenPgpService2.Stub.asInterface(binder));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStuff() throws Exception {
|
||||
// TODO why does this not ask for general usage permissions?!
|
||||
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OpenPgpApi.ACTION_ENCRYPT);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[]{0x9D604D2F310716A3L});
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream("swag".getBytes());
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
Intent result = mApi.executeApi(intent, is, os);
|
||||
|
||||
assertThat("result is pending accept",
|
||||
result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR),
|
||||
is(OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED));
|
||||
|
||||
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
pi.send();
|
||||
|
||||
Thread.sleep(ACTIVITY_WAIT_TIME); // Wait for activity to start
|
||||
onView(withText(R.string.button_allow)).perform(click());
|
||||
}
|
||||
|
||||
byte[] ciphertext;
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OpenPgpApi.ACTION_ENCRYPT);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
intent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, new long[]{0x9D604D2F310716A3L});
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream("swag".getBytes());
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
Intent result = mApi.executeApi(intent, is, os);
|
||||
|
||||
assertThat("result is encrypt ok",
|
||||
result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR),
|
||||
is(OpenPgpApi.RESULT_CODE_SUCCESS));
|
||||
|
||||
ciphertext = os.toByteArray();
|
||||
}
|
||||
|
||||
{ // decrypt
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(ciphertext);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
Intent result = mApi.executeApi(intent, is, os);
|
||||
|
||||
assertThat("result is pending input",
|
||||
result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR),
|
||||
is(OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED));
|
||||
|
||||
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
pi.send();
|
||||
|
||||
Thread.sleep(ACTIVITY_WAIT_TIME); // Wait for activity to start
|
||||
onView(withText(R.string.button_allow)).perform(click());
|
||||
}
|
||||
|
||||
{ // decrypt again, this time pending passphrase
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(ciphertext);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
Intent result = mApi.executeApi(intent, is, os);
|
||||
|
||||
assertThat("result is pending passphrase",
|
||||
result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR),
|
||||
is(OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED));
|
||||
|
||||
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
pi.send();
|
||||
|
||||
Thread.sleep(ACTIVITY_WAIT_TIME); // Wait for activity to start
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText("x"));
|
||||
|
||||
// Needed to correctly execute test on Travis
|
||||
closeSoftKeyboard();
|
||||
Thread.sleep(1 * 1000);
|
||||
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
}
|
||||
|
||||
{ // decrypt again, NOW it should work with passphrase cached =)
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(ciphertext);
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
Intent result = mApi.executeApi(intent, is, os);
|
||||
|
||||
assertThat("result is decrypt ok",
|
||||
result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR),
|
||||
is(OpenPgpApi.RESULT_CODE_SUCCESS));
|
||||
|
||||
byte[] plaintext = os.toByteArray();
|
||||
assertThat("decrypted plaintext matches plaintext", new String(plaintext), is("swag"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,385 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation.ActivityResult;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.AndroidTestHelpers;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.espresso.Espresso.onData;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasCategories;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtraWithKey;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasType;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withEncryptionStatus;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureMyKey;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureNone;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class AsymmetricFileOperationTests {
|
||||
|
||||
@Rule
|
||||
public final IntentsTestRule<MainActivity> mActivity
|
||||
= new IntentsTestRule<MainActivity>(MainActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.putExtra(MainActivity.EXTRA_SKIP_FIRST_TIME, true);
|
||||
intent.putExtra(MainActivity.EXTRA_INIT_FRAG, MainActivity.ID_ENCRYPT_DECRYPT);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Activity activity = mActivity.getActivity();
|
||||
|
||||
AndroidTestHelpers.copyFiles();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
||||
// make sure no passphrases are cached
|
||||
PassphraseCacheService.clearCachedPassphrases(activity);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testFileSaveEncryptDecrypt() throws Exception {
|
||||
|
||||
// navigate to 'encrypt text'
|
||||
onView(withId(R.id.encrypt_files)).perform(click());
|
||||
|
||||
File file = pickRandom(getImageNames());
|
||||
File outputFile = new File(getInstrumentation().getTargetContext().getFilesDir(), "output-token.gpg");
|
||||
|
||||
{ // encrypt
|
||||
|
||||
// the EncryptKeyCompletionView is tested individually
|
||||
onView(withId(R.id.recipient_list)).perform(tokenEncryptViewAddToken(0x9D604D2F310716A3L));
|
||||
|
||||
handleAddFileIntent(file);
|
||||
onView(withId(R.id.file_list_entry_add)).perform(click());
|
||||
|
||||
handleSaveEncryptedFileIntent(outputFile);
|
||||
onView(withId(R.id.encrypt_save)).perform(click());
|
||||
|
||||
assertThat("output file has been written", true, is(outputFile.exists()));
|
||||
|
||||
}
|
||||
|
||||
// go to decrypt from clipboard view
|
||||
pressBack();
|
||||
|
||||
handleOpenFileIntentKitKat(outputFile);
|
||||
onView(withId(R.id.decrypt_files)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText("x"));
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
|
||||
onView(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(file.getName()))))
|
||||
.check(matches(allOf(withEncryptionStatus(true), withSignatureNone())));
|
||||
}
|
||||
|
||||
{ // delete original file
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(file.getName())))),
|
||||
withId(R.id.context_menu))).perform(click());
|
||||
|
||||
// delete file
|
||||
onView(withText(R.string.btn_delete_original)).perform(click());
|
||||
|
||||
checkSnackbar(Style.OK, R.string.file_delete_ok);
|
||||
assertThat("output file has been deleted", false, is(outputFile.exists()));
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(file.getName())))),
|
||||
withId(R.id.context_menu))).perform(click());
|
||||
|
||||
// delete file
|
||||
onView(withText(R.string.btn_delete_original)).perform(click());
|
||||
|
||||
checkSnackbar(Style.WARN, R.string.file_delete_none);
|
||||
|
||||
}
|
||||
|
||||
{ // save file (*after* deletion~)
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(file.getName())))),
|
||||
withId(R.id.context_menu))).perform(click());
|
||||
|
||||
File savedFile =
|
||||
new File(getInstrumentation().getTargetContext().getFilesDir(), "vo.png");
|
||||
handleSaveDecryptedFileIntent(savedFile, file.getName());
|
||||
|
||||
// save decrypted content
|
||||
onView(withText(R.string.btn_save_file)).perform(click());
|
||||
|
||||
checkSnackbar(Style.OK, R.string.file_saved);
|
||||
assertThat("decrypted file has been saved", true, is(savedFile.exists()));
|
||||
|
||||
// cleanup
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleAddFileIntent(File file) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
|
||||
handleAddFileIntentKitKat(file);
|
||||
} else {
|
||||
handleAddFileIntentOlder(file);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleAddFileIntentKitKat(File file) {
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_OPEN_DOCUMENT),
|
||||
hasType("*/*"),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE)),
|
||||
hasExtraWithKey(Intent.EXTRA_ALLOW_MULTIPLE)
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
private void handleAddFileIntentOlder(File file) {
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_GET_CONTENT),
|
||||
hasType("*/*"),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleSaveDecryptedFileIntent(File file, String expectedTitle) {
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_CREATE_DOCUMENT),
|
||||
hasExtra("android.content.extra.SHOW_ADVANCED", true),
|
||||
hasExtra(Intent.EXTRA_TITLE, expectedTitle),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleSaveEncryptedFileIntent(File file) {
|
||||
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
} catch (Exception e) {
|
||||
// nvm
|
||||
}
|
||||
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_CREATE_DOCUMENT),
|
||||
hasType("*/*"),
|
||||
hasExtra("android.content.extra.SHOW_ADVANCED", true),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleOpenFileIntentKitKat(File file) {
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_OPEN_DOCUMENT),
|
||||
hasType("*/*"),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
// hasExtraWithKey(Intent.EXTRA_ALLOW_MULTIPLE)
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testSignVerify() throws Exception {
|
||||
|
||||
String cleartext = randomString(10, 30);
|
||||
|
||||
// navigate to 'encrypt text'
|
||||
onView(withId(R.id.encrypt_text)).perform(click());
|
||||
|
||||
{ // sign
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_empty_text);
|
||||
|
||||
onView(withId(R.id.result_signature_icon)).check(matches(withDisplayedChild(0)));
|
||||
onView(withId(R.id.sign)).perform(click());
|
||||
onData(withKeyItemId(0x9D604D2F310716A3L))
|
||||
.inAdapterView(isAssignableFrom(AdapterView.class))
|
||||
.perform(click());
|
||||
onView(withId(R.id.result_signature_icon)).check(matches(withDisplayedChild(1)));
|
||||
|
||||
onView(withId(R.id.encrypt_text_text)).perform(typeText(cleartext));
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText("x"));
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
|
||||
checkSnackbar(Style.OK, R.string.msg_se_success);
|
||||
|
||||
}
|
||||
|
||||
// go to decrypt from clipboard view
|
||||
pressBack();
|
||||
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
|
||||
onView(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown))))
|
||||
.check(matches(allOf(withEncryptionStatus(false), withSignatureMyKey())));
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown)))),
|
||||
withId(R.id.context_menu))).perform(click());
|
||||
|
||||
// check if log looks ok
|
||||
onView(withText(R.string.snackbar_details)).perform(click());
|
||||
onView(withText(R.string.msg_dc_clear_signature_ok)).check(matches(isDisplayed()));
|
||||
pressBack();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testGeneralErrorHandling() throws Exception {
|
||||
|
||||
// navigate to encrypt files fragment
|
||||
onView(withId(R.id.encrypt_files)).perform(click());
|
||||
|
||||
File[] files = getImageNames();
|
||||
|
||||
{ // encrypt screen
|
||||
|
||||
onView(withId(R.id.encrypt_share)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_no_file_selected);
|
||||
|
||||
handleAddFileIntent(files[0]);
|
||||
onView(withId(R.id.file_list_entry_add)).perform(click());
|
||||
|
||||
handleAddFileIntent(files[1]);
|
||||
onView(withId(R.id.file_list_entry_add)).perform(click());
|
||||
|
||||
onView(withId(R.id.encrypt_share)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.select_encryption_key);
|
||||
|
||||
onView(withId(R.id.sign)).perform(click());
|
||||
onData(withKeyItemId(0x9D604D2F310716A3L))
|
||||
.inAdapterView(isAssignableFrom(AdapterView.class))
|
||||
.perform(click());
|
||||
|
||||
onView(withId(R.id.encrypt_share)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_detached_signature);
|
||||
|
||||
// the EncryptKeyCompletionView is tested individually
|
||||
onView(withId(R.id.recipient_list)).perform(tokenEncryptViewAddToken(0x9D604D2F310716A3L));
|
||||
|
||||
onView(withId(R.id.encrypt_save)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_multi_files);
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
|
||||
onView(withText(R.string.btn_copy_encrypted_signed)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_multi_clipboard);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onData;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withEncryptionStatus;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureMyKey;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureNone;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class AsymmetricTextOperationTests {
|
||||
|
||||
@Rule
|
||||
public final ActivityTestRule<MainActivity> mActivity
|
||||
= new ActivityTestRule<MainActivity>(MainActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.putExtra(MainActivity.EXTRA_SKIP_FIRST_TIME, true);
|
||||
intent.putExtra(MainActivity.EXTRA_INIT_FRAG, MainActivity.ID_ENCRYPT_DECRYPT);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Activity activity = mActivity.getActivity();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
||||
// make sure no passphrases are cached
|
||||
PassphraseCacheService.clearCachedPassphrases(activity);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testTextEncryptDecryptFromToken() throws Exception {
|
||||
|
||||
// navigate to 'encrypt text'
|
||||
onView(withId(R.id.encrypt_text)).perform(click());
|
||||
|
||||
String cleartext = randomString(10, 30);
|
||||
|
||||
{ // encrypt
|
||||
|
||||
// the EncryptKeyCompletionView is tested individually
|
||||
onView(withId(R.id.result_encryption_icon)).check(matches(withDisplayedChild(0)));
|
||||
onView(withId(R.id.recipient_list)).perform(tokenEncryptViewAddToken(0x9D604D2F310716A3L));
|
||||
onView(withId(R.id.result_encryption_icon)).check(matches(withDisplayedChild(1)));
|
||||
|
||||
onView(withId(R.id.encrypt_text_text)).perform(typeText(cleartext));
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
}
|
||||
|
||||
// go to decrypt from clipboard view
|
||||
pressBack();
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText("x"));
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
|
||||
onView(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown_text))))
|
||||
.check(matches(allOf(
|
||||
hasDescendant(withText(FileHelper.readableFileSize(cleartext.length()))),
|
||||
withEncryptionStatus(true),
|
||||
withSignatureNone()
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testSignVerify() throws Exception {
|
||||
|
||||
String cleartext = randomString(10, 30);
|
||||
|
||||
// navigate to 'encrypt text'
|
||||
onView(withId(R.id.encrypt_text)).perform(click());
|
||||
|
||||
{ // sign
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_empty_text);
|
||||
|
||||
onView(withId(R.id.result_signature_icon)).check(matches(withDisplayedChild(0)));
|
||||
onView(withId(R.id.sign)).perform(click());
|
||||
onData(withKeyItemId(0x9D604D2F310716A3L))
|
||||
.inAdapterView(isAssignableFrom(AdapterView.class))
|
||||
.perform(click());
|
||||
onView(withId(R.id.result_signature_icon)).check(matches(withDisplayedChild(1)));
|
||||
|
||||
onView(withId(R.id.encrypt_text_text)).perform(typeText(cleartext));
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText("x"));
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
|
||||
checkSnackbar(Style.OK, R.string.msg_se_success);
|
||||
|
||||
}
|
||||
|
||||
// go to decrypt from clipboard view
|
||||
pressBack();
|
||||
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
|
||||
onView(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown))))
|
||||
.check(matches(allOf(withEncryptionStatus(false), withSignatureMyKey())));
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown)))),
|
||||
withId(R.id.context_menu))).perform(click());
|
||||
|
||||
// check if log looks ok
|
||||
onView(withText(R.string.snackbar_details)).perform(click());
|
||||
onView(withText(R.string.msg_dc_clear_signature_ok)).check(matches(isDisplayed()));
|
||||
pressBack();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import androidx.test.espresso.matcher.ViewMatchers;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
|
||||
import org.junit.Rule;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.swipeLeft;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class CreateKeyActivityTest {
|
||||
|
||||
public static final String SAMPLE_NAME = "Sample Name";
|
||||
public static final String SAMPLE_EMAIL = "sample_email@gmail.com";
|
||||
public static final String SAMPLE_ADDITIONAL_EMAIL = "sample_additional_email@gmail.com";
|
||||
public static final String SAMPLE_PASSWORD = "sample_password";
|
||||
|
||||
@Rule
|
||||
public final ActivityTestRule<CreateKeyActivity> mActivity
|
||||
= new ActivityTestRule<>(CreateKeyActivity.class);
|
||||
|
||||
//@Test
|
||||
public void testCreateMyKey() {
|
||||
/*
|
||||
|
||||
mActivity.getActivity();
|
||||
|
||||
// Clicks create my key
|
||||
onView(ViewMatchers.withId(R.id.create_key_create_key_button))
|
||||
.perform(click());
|
||||
|
||||
// Clicks next with empty name
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_name))
|
||||
.check(matches(withError(R.string.create_key_empty)));
|
||||
|
||||
// Types name and clicks next
|
||||
onView(withId(R.id.create_key_name))
|
||||
.perform(typeText(SAMPLE_NAME));
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
|
||||
// Clicks next with empty email
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_email))
|
||||
.check(matches(withError(R.string.create_key_empty)));
|
||||
|
||||
// Types email
|
||||
onView(withId(R.id.create_key_email))
|
||||
.perform(typeText(SAMPLE_EMAIL));
|
||||
|
||||
// Adds same email as additional email and dismisses the snackbar
|
||||
onView(withId(R.id.create_key_add_email))
|
||||
.perform(click());
|
||||
onView(withId(R.id.add_email_address))
|
||||
.perform(typeText(SAMPLE_EMAIL));
|
||||
onView(withText(android.R.string.ok))
|
||||
.inRoot(isDialog())
|
||||
.perform(click());
|
||||
onView(allOf(withId(R.id.sb__text), withText(R.string.create_key_email_already_exists_text)))
|
||||
.check(matches(isDisplayed()));
|
||||
onView(allOf(withId(R.id.sb__text), withText(R.string.create_key_email_already_exists_text)))
|
||||
.perform(swipeLeft());
|
||||
|
||||
// Adds additional email
|
||||
onView(withId(R.id.create_key_add_email))
|
||||
.perform(click());
|
||||
onView(withId(R.id.add_email_address))
|
||||
.perform(typeText(SAMPLE_ADDITIONAL_EMAIL));
|
||||
onView(withText(android.R.string.ok))
|
||||
.inRoot(isDialog())
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_emails))
|
||||
.check(matches(hasDescendant(allOf(withId(R.id.create_key_email_item_email), withText(SAMPLE_ADDITIONAL_EMAIL)))));
|
||||
|
||||
// Removes additional email and clicks next
|
||||
onView(allOf(withId(R.id.create_key_email_item_delete_button), hasSibling(allOf(withId(R.id.create_key_email_item_email), withText(SAMPLE_ADDITIONAL_EMAIL)))))
|
||||
.perform(click())
|
||||
.check(doesNotExist());
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click(click()));
|
||||
|
||||
// Clicks next with empty password
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_passphrase))
|
||||
.check(matches(withError(R.string.create_key_empty)));
|
||||
|
||||
// Types password
|
||||
onView(withId(R.id.create_key_passphrase))
|
||||
.perform(typeText(SAMPLE_PASSWORD));
|
||||
|
||||
// Clicks next with empty confirm password
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_passphrase_again))
|
||||
.check(matches(withError(R.string.create_key_passphrases_not_equal)));
|
||||
|
||||
// Types confirm password
|
||||
onView(withId(R.id.create_key_passphrase_again))
|
||||
.perform(typeText(SAMPLE_PASSWORD));
|
||||
|
||||
// Clicks show password twice and clicks next
|
||||
onView(withId(R.id.create_key_show_passphrase))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_passphrase))
|
||||
.check(matches(withTransformationMethod(HideReturnsTransformationMethod.class)));
|
||||
onView(withId(R.id.create_key_passphrase_again))
|
||||
.check(matches(withTransformationMethod(HideReturnsTransformationMethod.class)));
|
||||
onView(withId(R.id.create_key_show_passphrase))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_passphrase))
|
||||
.check(matches(withTransformationMethod(PasswordTransformationMethod.class)));
|
||||
onView(withId(R.id.create_key_passphrase_again))
|
||||
.check(matches(withTransformationMethod(PasswordTransformationMethod.class)));
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
|
||||
// Verifies name and email
|
||||
onView(withId(R.id.name))
|
||||
.check(matches(withText(SAMPLE_NAME)));
|
||||
onView(withId(R.id.email))
|
||||
.check(matches(withText(SAMPLE_EMAIL)));
|
||||
|
||||
// Verifies backstack
|
||||
onView(withId(R.id.create_key_back_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_back_button))
|
||||
.perform(click());
|
||||
onView(withId(R.id.create_key_back_button))
|
||||
.perform(click());
|
||||
|
||||
onView(withId(R.id.create_key_name))
|
||||
.check(matches(withText(SAMPLE_NAME)));
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
|
||||
onView(withId(R.id.create_key_email))
|
||||
.check(matches(withText(SAMPLE_EMAIL)));
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
|
||||
// TODO: Uncomment when fixed in main
|
||||
// onView(withId(R.id.create_key_passphrase))
|
||||
// .check(matches(withText(SAMPLE_PASSWORD)));
|
||||
// onView(withId(R.id.create_key_passphrase_again))
|
||||
// .check(matches(withText(SAMPLE_PASSWORD)));
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
|
||||
onView(withId(R.id.name))
|
||||
.check(matches(withText(SAMPLE_NAME)));
|
||||
onView(withId(R.id.email))
|
||||
.check(matches(withText(SAMPLE_EMAIL)));
|
||||
|
||||
// Clicks create key
|
||||
onView(withId(R.id.create_key_next_button))
|
||||
.perform(click());
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnHolderItem;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyHolderId;
|
||||
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class EditKeyTest {
|
||||
|
||||
@Rule
|
||||
public final ActivityTestRule<MainActivity> mActivity
|
||||
= new ActivityTestRule<MainActivity>(MainActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.putExtra(MainActivity.EXTRA_SKIP_FIRST_TIME, true);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
|
||||
//@Test
|
||||
public void test01Edit() throws Exception {
|
||||
Activity activity = mActivity.getActivity();
|
||||
|
||||
// KeychainDatabase.getInstance(activity).clearDatabase();
|
||||
|
||||
// import key for testing, get a stable initial state
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
||||
// navigate to edit key dialog
|
||||
onView(allOf(
|
||||
isAssignableFrom(RecyclerView.class),
|
||||
withId(android.R.id.list)))
|
||||
.perform(actionOnHolderItem(
|
||||
withKeyHolderId(0x9D604D2F310716A3L), click()));
|
||||
|
||||
onView(withId(R.id.view_key_card_user_ids_edit)).perform(click());
|
||||
|
||||
// no-op should yield snackbar
|
||||
onView(withText(R.string.btn_save)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.msg_mf_error_noop);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation.ActivityResult;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.AndroidTestHelpers;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnHolderItem;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasCategories;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasType;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isChecked;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withChild;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.dismissSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyHolderId;
|
||||
import static org.sufficientlysecure.keychain.matcher.DrawableMatcher.withDrawable;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class MiscCryptOperationTests {
|
||||
|
||||
@Rule
|
||||
public final IntentsTestRule<MainActivity> mActivityRule
|
||||
= new IntentsTestRule<MainActivity>(MainActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.putExtra(MainActivity.EXTRA_SKIP_FIRST_TIME, true);
|
||||
intent.putExtra(MainActivity.EXTRA_INIT_FRAG, MainActivity.ID_ENCRYPT_DECRYPT);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// clear dis shit
|
||||
Preferences.getPreferences(getInstrumentation().getTargetContext()).clear();
|
||||
|
||||
mActivity = mActivityRule.getActivity();
|
||||
|
||||
AndroidTestHelpers.copyFiles();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(mActivity, "x.sec.asc");
|
||||
|
||||
// make sure no passphrases are cached
|
||||
PassphraseCacheService.clearCachedPassphrases(mActivity);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testDecryptNonPgpFile() throws Exception {
|
||||
|
||||
// decrypt any non-pgp file
|
||||
File file = pickRandom(getImageNames());
|
||||
handleOpenFileIntentKitKat(file);
|
||||
onView(withId(R.id.decrypt_files)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(allOf(
|
||||
hasDescendant(withDrawable(R.drawable.status_signature_invalid_cutout_24dp, true)),
|
||||
hasDescendant(withText(R.string.msg_dc_error_invalid_data)))))),
|
||||
withId(R.id.result_error_log))).perform(click());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testDecryptEmptySelection() throws Exception {
|
||||
|
||||
// decrypt any non-pgp file
|
||||
handleOpenFileEmptyKitKat();
|
||||
onView(withId(R.id.decrypt_files)).perform(click());
|
||||
|
||||
checkSnackbar(Style.ERROR, R.string.no_file_selected);
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testDecryptEmptyClipboard() throws Exception {
|
||||
|
||||
// decrypt any non-pgp file
|
||||
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("", ""));
|
||||
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
checkSnackbar(Style.ERROR, R.string.error_clipboard_empty);
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testDecryptNonPgpClipboard() throws Exception {
|
||||
|
||||
// decrypt any non-pgp file
|
||||
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, randomString(0, 50));
|
||||
clipboard.setPrimaryClip(clip);
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
|
||||
{ // decrypt
|
||||
|
||||
// open context menu
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(allOf(
|
||||
hasDescendant(withDrawable(R.drawable.status_signature_invalid_cutout_24dp, true)),
|
||||
hasDescendant(withText(R.string.msg_dc_error_invalid_data)))))),
|
||||
withId(R.id.result_error_log))).perform(click());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleOpenFileEmptyKitKat() {
|
||||
Intent data = new Intent();
|
||||
data.setData(null);
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_OPEN_DOCUMENT),
|
||||
hasType("*/*"),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
// hasExtraWithKey(Intent.EXTRA_ALLOW_MULTIPLE)
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
private void handleOpenFileIntentKitKat(File file) {
|
||||
Intent data = new Intent();
|
||||
data.setData(Uri.fromFile(file));
|
||||
|
||||
Intents.intending(allOf(
|
||||
hasAction(Intent.ACTION_OPEN_DOCUMENT),
|
||||
hasType("*/*"),
|
||||
hasCategories(hasItem(Intent.CATEGORY_OPENABLE))
|
||||
// hasExtraWithKey(Intent.EXTRA_ALLOW_MULTIPLE)
|
||||
)).respondWith(
|
||||
new ActivityResult(Activity.RESULT_OK, data)
|
||||
);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testEncryptTokenFromKeyView() throws Exception {
|
||||
onView(allOf(
|
||||
isAssignableFrom(RecyclerView.class),
|
||||
withId(android.R.id.list)))
|
||||
.perform(actionOnHolderItem(
|
||||
withKeyHolderId(0x9D604D2F310716A3L), click()));
|
||||
|
||||
onView(withId(R.id.view_key_action_encrypt_text)).perform(click());
|
||||
|
||||
// make sure the encrypt is correctly set
|
||||
onView(withId(R.id.result_encryption_icon)).check(matches(withDisplayedChild(1)));
|
||||
// TODO check token id
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testMenuSaveDefault() throws Exception {
|
||||
|
||||
onView(withId(R.id.encrypt_files)).perform(click());
|
||||
|
||||
{ // save checked options
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(mActivity);
|
||||
|
||||
// check initial button states
|
||||
onView(allOf(withId(R.id.checkbox),
|
||||
hasSibling(withChild(withText(R.string.label_delete_after_encryption)))))
|
||||
.check(matches(isNotChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_enable_compression)))))
|
||||
.check(matches(isChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_encrypt_filenames)))))
|
||||
.check(matches(isChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_file_ascii_armor)))))
|
||||
.check(matches(isNotChecked()));
|
||||
|
||||
// press some buttons
|
||||
|
||||
onView(withText(R.string.label_enable_compression)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.snack_compression_off);
|
||||
onView(withText(R.string.btn_save_default)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.btn_saved);
|
||||
dismissSnackbar();
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(mActivity);
|
||||
onView(withText(R.string.label_encrypt_filenames)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.snack_encrypt_filenames_off);
|
||||
onView(withText(R.string.btn_save_default)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.btn_saved);
|
||||
dismissSnackbar();
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(mActivity);
|
||||
onView(withText(R.string.label_file_ascii_armor)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.snack_armor_on);
|
||||
onView(withText(R.string.btn_save_default)).perform(click());
|
||||
checkSnackbar(Style.OK, R.string.btn_saved);
|
||||
dismissSnackbar();
|
||||
|
||||
}
|
||||
|
||||
pressBack();
|
||||
onView(withId(R.id.encrypt_files)).perform(click());
|
||||
|
||||
{ // save checked options
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(mActivity);
|
||||
|
||||
// check initial button states (as saved from before!)
|
||||
onView(allOf(withId(R.id.checkbox),
|
||||
hasSibling(withChild(withText(R.string.label_delete_after_encryption)))))
|
||||
.check(matches(isNotChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_enable_compression)))))
|
||||
.check(matches(isNotChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_encrypt_filenames)))))
|
||||
.check(matches(isNotChecked()));
|
||||
onView(allOf(withId(R.id.checkbox), hasSibling(withChild(withText(R.string.label_file_ascii_armor)))))
|
||||
.check(matches(isChecked()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation.ActivityResult;
|
||||
import android.content.Intent;
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
|
||||
import static androidx.test.espresso.Espresso.pressBack;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.intent.Intents.intending;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtraWithKey;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasFlags;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasType;
|
||||
import static androidx.test.espresso.intent.matcher.UriMatchers.hasHost;
|
||||
import static androidx.test.espresso.intent.matcher.UriMatchers.hasScheme;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withEncryptionStatus;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureNone;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class SymmetricTextOperationTests {
|
||||
|
||||
public static final String PASSPHRASE = randomString(5, 20);
|
||||
|
||||
@Rule
|
||||
public final IntentsTestRule<MainActivity> mActivity
|
||||
= new IntentsTestRule<MainActivity>(MainActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.putExtra(MainActivity.EXTRA_SKIP_FIRST_TIME, true);
|
||||
intent.putExtra(MainActivity.EXTRA_INIT_FRAG, MainActivity.ID_ENCRYPT_DECRYPT);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
|
||||
//@Test
|
||||
public void testSymmetricCryptClipboard() throws Exception {
|
||||
|
||||
mActivity.getActivity();
|
||||
|
||||
String text = randomString(10, 30);
|
||||
|
||||
// navigate to encrypt/decrypt
|
||||
onView(withId(R.id.encrypt_text)).perform(click());
|
||||
|
||||
{
|
||||
onView(withId(R.id.encrypt_text_text)).perform(typeText(text));
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
|
||||
onView(withText(R.string.label_symmetric)).perform(click());
|
||||
|
||||
onView(withId(R.id.passphrase)).perform(typeText(PASSPHRASE));
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
|
||||
checkSnackbar(Style.ERROR, R.string.passphrases_do_not_match);
|
||||
|
||||
onView(withId(R.id.passphraseAgain)).perform(typeText(PASSPHRASE));
|
||||
|
||||
onView(withId(R.id.encrypt_text_text)).check(matches(withText(text)));
|
||||
|
||||
onView(withId(R.id.encrypt_copy)).perform(click());
|
||||
|
||||
checkSnackbar(Style.OK, R.string.msg_se_success);
|
||||
}
|
||||
|
||||
// go to decrypt from clipboard view
|
||||
pressBack();
|
||||
onView(withId(R.id.decrypt_from_clipboard)).perform(click());
|
||||
|
||||
{
|
||||
onView(withId(R.id.passphrase_passphrase)).perform(typeText(PASSPHRASE));
|
||||
onView(withText(R.string.btn_unlock)).perform(click());
|
||||
|
||||
onView(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown_text))))
|
||||
.check(matches(allOf(withEncryptionStatus(true), withSignatureNone())));
|
||||
|
||||
intending(allOf(
|
||||
hasAction("android.intent.action.CHOOSER"),
|
||||
hasExtra(equalTo(Intent.EXTRA_INTENT), allOf(
|
||||
hasAction(Intent.ACTION_VIEW),
|
||||
hasFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),
|
||||
hasData(allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY))),
|
||||
hasType("text/plain")
|
||||
))
|
||||
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
|
||||
|
||||
onView(allOf(isDescendantOfA(isRecyclerItemView(R.id.decrypted_files_list,
|
||||
hasDescendant(withText(R.string.filename_unknown_text)))),
|
||||
withId(R.id.file))).perform(click());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testSymmetricCryptShare() throws Exception {
|
||||
|
||||
mActivity.getActivity();
|
||||
|
||||
String text = randomString(10, 30);
|
||||
|
||||
// navigate to encrypt/decrypt
|
||||
onView(withId(R.id.encrypt_text)).perform(click());
|
||||
|
||||
{
|
||||
onView(withId(R.id.encrypt_text_text)).perform(typeText(text));
|
||||
|
||||
openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());
|
||||
onView(withText(R.string.label_symmetric)).perform(click());
|
||||
|
||||
onView(withId(R.id.passphrase)).perform(typeText(PASSPHRASE));
|
||||
|
||||
onView(withId(R.id.passphraseAgain)).perform(typeText(PASSPHRASE));
|
||||
|
||||
onView(withId(R.id.encrypt_text_text)).check(matches(withText(text)));
|
||||
|
||||
intending(allOf(
|
||||
hasAction("android.intent.action.CHOOSER"),
|
||||
hasExtra(equalTo(Intent.EXTRA_INTENT), allOf(
|
||||
hasAction(Intent.ACTION_SEND),
|
||||
hasFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),
|
||||
hasExtraWithKey(Intent.EXTRA_TEXT),
|
||||
hasType("text/plain")
|
||||
))
|
||||
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
|
||||
|
||||
onView(withId(R.id.encrypt_share)).perform(click());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.widget;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import androidx.test.espresso.action.ViewActions;
|
||||
import androidx.test.espresso.matcher.RootMatchers;
|
||||
import androidx.test.espresso.matcher.ViewMatchers;
|
||||
import androidx.test.rule.ActivityTestRule;
|
||||
import android.view.KeyEvent;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.EncryptTextActivity;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onData;
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.typeText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyToken;
|
||||
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class EncryptKeyCompletionViewTest {
|
||||
|
||||
@Rule
|
||||
public final ActivityTestRule<EncryptTextActivity> mActivity
|
||||
= new ActivityTestRule<>(EncryptTextActivity.class);
|
||||
|
||||
//@Test
|
||||
public void testTextEncryptDecryptFromToken() throws Exception {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, new long[]{0x9D604D2F310716A3L});
|
||||
Activity activity = mActivity.launchActivity(intent);
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
||||
// check if the element passed in from intent
|
||||
onView(ViewMatchers.withId(R.id.recipient_list)).check(matches(withKeyToken(0x9D604D2F310716A3L)));
|
||||
onView(withId(R.id.recipient_list)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL));
|
||||
|
||||
// type X, select from list, check if it's there
|
||||
onView(withId(R.id.recipient_list)).perform(typeText("x"));
|
||||
onData(withKeyItemId(0x9D604D2F310716A3L)).inRoot(RootMatchers.isPlatformPopup())
|
||||
.inAdapterView(allOf(isAssignableFrom(AdapterView.class),
|
||||
hasDescendant(withId(R.id.key_list_item_name)))).perform(click());
|
||||
onView(withId(R.id.recipient_list)).check(matches(withKeyToken(0x9D604D2F310716A3L)));
|
||||
onView(withId(R.id.recipient_list)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL));
|
||||
onView(withId(R.id.recipient_list)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL));
|
||||
|
||||
// add directly, check if it's there
|
||||
onView(withId(R.id.recipient_list)).perform(tokenEncryptViewAddToken(0x9D604D2F310716A3L));
|
||||
onView(withId(R.id.recipient_list)).check(matches(withKeyToken(0x9D604D2F310716A3L)));
|
||||
onView(withId(R.id.recipient_list)).perform(ViewActions.pressKey(KeyEvent.KEYCODE_DEL));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 27
|
||||
targetSdkVersion 28
|
||||
versionCode 114
|
||||
versionName "1.1.4"
|
||||
|
||||
|
@ -21,15 +21,10 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
compile 'androidx.appcompat:appcompat:1.0.0'
|
||||
testCompile 'junit:junit:4.12'
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
|
||||
// recycler
|
||||
compile 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
compile 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.beloo.widget:ChipsLayoutManager:0.3.7@aar'
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 596f050d09dc1a87c09b45e822c673399f41bab1
|
||||
Subproject commit 66dca453c37440678760e0c14d4989fb2ddfb771
|
|
@ -1,8 +1,6 @@
|
|||
include ':OpenKeychain'
|
||||
include ':nfcsweetspot'
|
||||
include ':extern:bouncycastle:core'
|
||||
include ':extern:bouncycastle:pg'
|
||||
include ':extern:minidns'
|
||||
include ':extern:MaterialChipsInput:library'
|
||||
|
||||
// Workaround for Android Gradle Plugin 2.0, as described in http://stackoverflow.com/a/36544850
|
||||
|
|
Loading…
Reference in New Issue