diff options
| author | Vincent Breitmoser <valodim@mugenguild.com> | 2015-06-17 19:24:07 +0200 | 
|---|---|---|
| committer | Vincent Breitmoser <valodim@mugenguild.com> | 2015-06-17 19:24:07 +0200 | 
| commit | 374b21410e82877efcdd1e5110376e975bddbf9f (patch) | |
| tree | e17df8931d627e58da677aee274249e1d51c34e2 /OpenKeychain/src/androidTest/java | |
| parent | 1a7677008bae900fb11a383d04766737aaa3f02f (diff) | |
| parent | 04d2b6a5076a1a7264687999152f8c24ece773ab (diff) | |
| download | open-keychain-374b21410e82877efcdd1e5110376e975bddbf9f.tar.gz open-keychain-374b21410e82877efcdd1e5110376e975bddbf9f.tar.bz2 open-keychain-374b21410e82877efcdd1e5110376e975bddbf9f.zip | |
Merge branch 'v/instrument' into v/multi-decrypt
Conflicts:
	.travis.yml
	OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/CreateKeyActivityTest.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
Diffstat (limited to 'OpenKeychain/src/androidTest/java')
11 files changed, 990 insertions, 2 deletions
| diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/AsymmetricOperationTests.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/AsymmetricOperationTests.java new file mode 100644 index 000000000..15de32c8a --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/AsymmetricOperationTests.java @@ -0,0 +1,262 @@ +/* + * 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 android.app.Activity; +import android.content.Intent; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; +import android.widget.AdapterView; + +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.pressBack; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.contrib.DrawerActions.openDrawer; +import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.not; +import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar; +import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource; +import static org.sufficientlysecure.keychain.TestHelpers.randomString; +import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken; +import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId; +import static org.sufficientlysecure.keychain.matcher.DrawableMatcher.withDrawable; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class AsymmetricOperationTests { + +    @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; +        } +    }; + +    @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' +        openDrawer(R.id.drawer_layout); +        onView(withText(R.string.nav_encrypt_decrypt)).perform(click()); +        onView(withId(R.id.encrypt_text)).perform(click()); + +        String cleartext = randomString(10, 30); + +        { // encrypt + +            // the EncryptKeyCompletionView is tested individually +            onView(withId(R.id.recipient_list)).perform(tokenEncryptViewAddToken(0x9D604D2F310716A3L)); + +            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(withId(R.id.decrypt_text_plaintext)).check(matches( +                    withText(cleartext))); + +            onView(withId(R.id.result_encryption_text)).check(matches( +                    withText(R.string.decrypt_result_encrypted))); +            onView(withId(R.id.result_signature_text)).check(matches( +                    withText(R.string.decrypt_result_no_signature))); +            onView(withId(R.id.result_signature_layout)).check(matches( +                    not(isDisplayed()))); + +            onView(withId(R.id.result_encryption_icon)).check(matches( +                    withDrawable(R.drawable.status_lock_closed_24dp))); +            onView(withId(R.id.result_signature_icon)).check(matches( +                    withDrawable(R.drawable.status_signature_unknown_cutout_24dp))); +        } + +    } + +    @Test +    public void testTextEncryptDecryptFromKeyView() throws Exception { + +        String cleartext = randomString(10, 30); + +        { // encrypt + +            // navigate to edit key dialog +            onData(withKeyItemId(0x9D604D2F310716A3L)) +                    .inAdapterView(allOf(isAssignableFrom(AdapterView.class), +                            isDescendantOfA(withId(R.id.key_list_list)))) +                    .perform(click()); +            onView(withId(R.id.view_key_action_encrypt_text)).perform(click()); + +            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(); +        pressBack(); + +        openDrawer(R.id.drawer_layout); +        onView(withText(R.string.nav_encrypt_decrypt)).perform(click()); +        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(withId(R.id.decrypt_text_plaintext)).check(matches( +                    withText(cleartext))); + +            onView(withId(R.id.result_encryption_text)).check(matches( +                    withText(R.string.decrypt_result_encrypted))); +            onView(withId(R.id.result_signature_text)).check(matches( +                    withText(R.string.decrypt_result_no_signature))); +            onView(withId(R.id.result_signature_layout)).check(matches( +                    not(isDisplayed()))); + +            onView(withId(R.id.result_encryption_icon)).check(matches( +                    withDrawable(R.drawable.status_lock_closed_24dp))); +            onView(withId(R.id.result_signature_icon)).check(matches( +                    withDrawable(R.drawable.status_signature_unknown_cutout_24dp))); + +        } + +        pressBack(); +        onView(withId(R.id.decrypt_from_clipboard)).perform(click()); + +        { // decrypt again, passphrase should be cached + +            onView(withId(R.id.decrypt_text_plaintext)).check(matches( +                    withText(cleartext))); + +            onView(withId(R.id.result_encryption_text)).check(matches( +                    withText(R.string.decrypt_result_encrypted))); +            onView(withId(R.id.result_signature_text)).check(matches( +                    withText(R.string.decrypt_result_no_signature))); +            onView(withId(R.id.result_signature_layout)).check(matches( +                    not(isDisplayed()))); + +            onView(withId(R.id.result_encryption_icon)).check(matches( +                    withDrawable(R.drawable.status_lock_closed_24dp))); +            onView(withId(R.id.result_signature_icon)).check(matches( +                    withDrawable(R.drawable.status_signature_unknown_cutout_24dp))); + +        } + +    } + +    @Test +    public void testSignVerify() throws Exception { + +        String cleartext = randomString(10, 30); + +        // navigate to 'encrypt text' +        openDrawer(R.id.drawer_layout); +        onView(withText(R.string.nav_encrypt_decrypt)).perform(click()); +        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); + +            // navigate to edit key dialog +            onView(withId(R.id.sign)).perform(click()); +            onData(withKeyItemId(0x9D604D2F310716A3L)) +                    .inAdapterView(isAssignableFrom(AdapterView.class)) +                    .perform(click()); + +            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(withId(R.id.decrypt_text_plaintext)).check(matches( +                    // startsWith because there may be extra newlines +                    withText(CoreMatchers.startsWith(cleartext)))); + +            onView(withId(R.id.result_encryption_text)).check(matches( +                    withText(R.string.decrypt_result_not_encrypted))); +            onView(withId(R.id.result_signature_text)).check(matches( +                    withText(R.string.decrypt_result_signature_secret))); +            onView(withId(R.id.result_signature_layout)).check(matches( +                    isDisplayed())); + +            onView(withId(R.id.result_encryption_icon)).check(matches( +                    withDrawable(R.drawable.status_lock_open_24dp))); +            onView(withId(R.id.result_signature_icon)).check(matches( +                    withDrawable(R.drawable.status_signature_verified_cutout_24dp))); + +        } + +    } + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/CreateKeyActivityTest.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/CreateKeyActivityTest.java index a20b61cf3..e81b312ac 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/CreateKeyActivityTest.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/CreateKeyActivityTest.java @@ -17,11 +17,16 @@  package org.sufficientlysecure.keychain; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4;  import android.test.ActivityInstrumentationTestCase2;  import android.test.suitebuilder.annotation.LargeTest;  import android.text.method.HideReturnsTransformationMethod;  import android.text.method.PasswordTransformationMethod; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith;  import org.sufficientlysecure.keychain.ui.CreateKeyActivity;  import static android.support.test.espresso.Espresso.onView; @@ -40,6 +45,7 @@ import static org.hamcrest.Matchers.allOf;  import static org.sufficientlysecure.keychain.matcher.EditTextMatchers.withError;  import static org.sufficientlysecure.keychain.matcher.EditTextMatchers.withTransformationMethod; +@RunWith(AndroidJUnit4.class)  @LargeTest  public class CreateKeyActivityTest extends ActivityInstrumentationTestCase2<CreateKeyActivity> { @@ -52,9 +58,10 @@ public class CreateKeyActivityTest extends ActivityInstrumentationTestCase2<Crea          super(CreateKeyActivity.class);      } -    @Override +    @Before      public void setUp() throws Exception {          super.setUp(); +        injectInstrumentation(InstrumentationRegistry.getInstrumentation());          getActivity();      } diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EditKeyTest.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EditKeyTest.java new file mode 100644 index 000000000..6773a7b2d --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EditKeyTest.java @@ -0,0 +1,89 @@ +/* + * 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 android.app.Activity; +import android.content.Intent; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; +import android.widget.AdapterView; + +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.CoreMatchers.allOf; +import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar; +import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource; +import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId; + + +@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(); + +        new KeychainDatabase(activity).clearDatabase(); + +        // import key for testing, get a stable initial state +        importKeysFromResource(activity, "x.sec.asc"); + +        // navigate to edit key dialog +        onData(withKeyItemId(0x9D604D2F310716A3L)) +                .inAdapterView(allOf(isAssignableFrom(AdapterView.class), +                        isDescendantOfA(withId(R.id.key_list_list)))) +                .perform(click()); +        onView(withId(R.id.menu_key_view_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); + +    } + + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptDecryptSymmetricTests.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptDecryptSymmetricTests.java new file mode 100644 index 000000000..f07566755 --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptDecryptSymmetricTests.java @@ -0,0 +1,132 @@ +/* + * 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 android.content.Intent; +import android.support.test.espresso.matcher.ViewMatchers; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; + +import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; +import static android.support.test.espresso.Espresso.pressBack; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.contrib.DrawerActions.openDrawer; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.CoreMatchers.not; +import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar; +import static org.sufficientlysecure.keychain.TestHelpers.randomString; +import static org.sufficientlysecure.keychain.matcher.DrawableMatcher.withDrawable; + + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(AndroidJUnit4.class) +@LargeTest +public class EncryptDecryptSymmetricTests { + +    public static final String PASSPHRASE = randomString(5, 20); + +    @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 testSymmetricTextEncryptDecrypt() throws Exception { + +        MainActivity activity = mActivity.getActivity(); + +        String text = randomString(10, 30); + +        // navigate to encrypt/decrypt +        openDrawer(R.id.drawer_layout); +        onView(ViewMatchers.withText(R.string.nav_encrypt_decrypt)).perform(click()); +        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(withId(R.id.decrypt_text_plaintext)).check(matches( +                    withText(text))); + +            // TODO write generic status verifier + +            onView(withId(R.id.result_encryption_text)).check(matches( +                    withText(R.string.decrypt_result_encrypted))); +            onView(withId(R.id.result_signature_text)).check(matches( +                    withText(R.string.decrypt_result_no_signature))); +            onView(withId(R.id.result_signature_layout)).check(matches( +                    not(isDisplayed()))); + +            onView(withId(R.id.result_encryption_icon)).check(matches( +                    withDrawable(R.drawable.status_lock_closed_24dp))); +            onView(withId(R.id.result_signature_icon)).check(matches( +                    withDrawable(R.drawable.status_signature_unknown_cutout_24dp))); + +        } + +    } + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptKeyCompletionViewTest.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptKeyCompletionViewTest.java new file mode 100644 index 000000000..40cdbd4eb --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/EncryptKeyCompletionViewTest.java @@ -0,0 +1,89 @@ +/* + * 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 android.app.Activity; +import android.content.Intent; +import android.support.test.espresso.action.ViewActions; +import android.support.test.espresso.matcher.RootMatchers; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.KeyEvent; +import android.widget.AdapterView; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sufficientlysecure.keychain.ui.EncryptTextActivity; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static org.hamcrest.CoreMatchers.allOf; +import static org.sufficientlysecure.keychain.TestHelpers.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; + + +@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(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)); + +    } + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/JacocoWorkaroundJUnitRunner.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/JacocoWorkaroundJUnitRunner.java new file mode 100644 index 000000000..b310ed5b8 --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/JacocoWorkaroundJUnitRunner.java @@ -0,0 +1,29 @@ +package org.sufficientlysecure.keychain; + + +import java.lang.reflect.Method; + +import android.os.Bundle; +import android.support.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); +    } +}
\ No newline at end of file diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java new file mode 100644 index 000000000..4c058940b --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java @@ -0,0 +1,86 @@ +/* + * 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.util.Random; + +import android.content.Context; +import android.support.annotation.StringRes; + +import org.hamcrest.CoreMatchers; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +import static android.support.test.espresso.matcher.ViewMatchers.withClassName; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSnackbarLineColor; + + +public class TestHelpers { + + +    public static void checkSnackbar(Style style, @StringRes Integer text) { + +        onView(withClassName(CoreMatchers.endsWith("Snackbar"))) +                .check(matches(withSnackbarLineColor(style.mLineColor))); + +        if (text != null) { +            onView(withClassName(CoreMatchers.endsWith("Snackbar"))) +                    .check(matches(hasDescendant(withText(text)))); +        } + +    } + + +    static void importKeysFromResource(Context context, String name) throws Exception { +        IteratorWithIOThrow<UncachedKeyRing> stream = UncachedKeyRing.fromStream( +                getInstrumentation().getContext().getAssets().open(name)); + +        ProviderHelper helper = new ProviderHelper(context); +        while(stream.hasNext()) { +            UncachedKeyRing ring = stream.next(); +            if (ring.isSecret()) { +                helper.saveSecretKeyRing(ring, new ProgressScaler()); +            } else { +                helper.savePublicKeyRing(ring, new ProgressScaler()); +            } +        } + +    } + +    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(); +    } + + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java new file mode 100644 index 000000000..75197ac9e --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java @@ -0,0 +1,82 @@ +/* + * 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 android.support.test.espresso.UiController; +import android.support.test.espresso.ViewAction; +import android.support.test.espresso.matcher.ViewMatchers; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.view.View; + +import com.tokenautocomplete.TokenCompleteTextView; +import org.hamcrest.Matcher; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; + +import static android.support.test.InstrumentationRegistry.getTargetContext; + + +public abstract class CustomActions { + +    public static ViewAction tokenEncryptViewAddToken(long keyId) throws Exception { +        CanonicalizedPublicKeyRing ring = +                new ProviderHelper(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); +            } +        }; +    } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/CustomMatchers.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/CustomMatchers.java new file mode 100644 index 000000000..1db902c4c --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/CustomMatchers.java @@ -0,0 +1,84 @@ +/* + * 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.support.annotation.ColorRes; +import android.support.test.espresso.matcher.BoundedMatcher; +import android.view.View; + +import com.nispok.snackbar.Snackbar; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.sufficientlysecure.keychain.EncryptKeyCompletionViewTest; +import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem; +import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; + +import static android.support.test.internal.util.Checks.checkNotNull; + + +public abstract class CustomMatchers { + +    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<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; +            } +        }; +    } + + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/DrawableMatcher.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/DrawableMatcher.java new file mode 100644 index 000000000..761fb8e0b --- /dev/null +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/DrawableMatcher.java @@ -0,0 +1,128 @@ +/* + * 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().equals(((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); +    } + +} diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/EditTextMatchers.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/EditTextMatchers.java index 7f2a7953b..a1df7912f 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/EditTextMatchers.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/matcher/EditTextMatchers.java @@ -1,5 +1,5 @@  /* - * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de> + * 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 | 
