aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarsh Shandilya <msfjarvis@gmail.com>2020-04-17 00:24:13 +0530
committerGitHub <noreply@github.com>2020-04-17 00:24:13 +0530
commit4ffd7ed9bffa5139277ffb91de5a69f2b714222c (patch)
treebccd7b27685d602da42d03111eeb4a36b1a803c1
parent8b4751f8250dea3efe04c73a87bdfe2926e2ac3f (diff)
Enable emulator tests (#708)
* github: Enable instrumentation testing in PRs Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Upgrade to Gradle 6.3 Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Remove outdated and broken tests, redo PasswordEntryTest in Kotlin Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Remove now unused test assets Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * github: Disable debug APK uploads in PR testing Signed-off-by: Harsh Shandilya <me@msfjarvis.dev> * Update .github/workflows/pull_request.yml * Update .github/workflows/pull_request.yml Switching to Ubuntu fails due to the SDK 29 missing. Co-authored-by: Fabian Henneke <FabianHenneke@users.noreply.github.com>
-rw-r--r--.github/workflows/pull_request.yml16
-rw-r--r--app/src/androidTest/assets/clear-store/category/sub3
-rw-r--r--app/src/androidTest/assets/clear-store/pass3
-rw-r--r--app/src/androidTest/assets/encrypted-store/category/sub.gpgbin362 -> 0 bytes
-rw-r--r--app/src/androidTest/assets/encrypted-store/pass.gpgbin361 -> 0 bytes
-rw-r--r--app/src/androidTest/assets/private_keybin2575 -> 0 bytes
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt182
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/EncryptTest.kt100
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/OtpTest.java15
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.java97
-rw-r--r--app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.kt97
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin58695 -> 58694 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
13 files changed, 109 insertions, 406 deletions
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index 9d4d1f07..2e1fae0a 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -3,7 +3,10 @@ on: pull_request
name: Check pull request
jobs:
test-pr:
- runs-on: ubuntu-latest
+ runs-on: macos-latest
+ strategy:
+ matrix:
+ api-level: [23, 25, 27, 29]
steps:
- uses: actions/checkout@master
@@ -16,9 +19,12 @@ jobs:
path: ~/.gradle/caches
key: gradle-${{ runner.os }}-${{ hashFiles('**/build.gradle') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}-${{ hashFiles('**/dependencies.gradle') }}
- - run: ./gradlew spotlessCheck assembleDebug testDebug lintDebug -Dpre-dex=false
+ - name: Run unit tests
+ run: ./gradlew spotlessCheck testDebug lintDebug -Dpre-dex=false
- - uses: actions/upload-artifact@master
+ - name: Run instrumentation tests
+ uses: reactivecircus/android-emulator-runner@v2
with:
- name: Debug APK
- path: app/build/outputs/apk/debug/app-debug.apk
+ api-level: ${{ matrix.api-level }}
+ target: default
+ script: ./gradlew connectedCheck
diff --git a/app/src/androidTest/assets/clear-store/category/sub b/app/src/androidTest/assets/clear-store/category/sub
deleted file mode 100644
index eb9106c1..00000000
--- a/app/src/androidTest/assets/clear-store/category/sub
+++ /dev/null
@@ -1,3 +0,0 @@
-sub_pass
-login: user
-sub_extra
diff --git a/app/src/androidTest/assets/clear-store/pass b/app/src/androidTest/assets/clear-store/pass
deleted file mode 100644
index 8415d1ab..00000000
--- a/app/src/androidTest/assets/clear-store/pass
+++ /dev/null
@@ -1,3 +0,0 @@
-password
-username: user
-extra
diff --git a/app/src/androidTest/assets/encrypted-store/category/sub.gpg b/app/src/androidTest/assets/encrypted-store/category/sub.gpg
deleted file mode 100644
index dded0132..00000000
--- a/app/src/androidTest/assets/encrypted-store/category/sub.gpg
+++ /dev/null
Binary files differ
diff --git a/app/src/androidTest/assets/encrypted-store/pass.gpg b/app/src/androidTest/assets/encrypted-store/pass.gpg
deleted file mode 100644
index 53c614c4..00000000
--- a/app/src/androidTest/assets/encrypted-store/pass.gpg
+++ /dev/null
Binary files differ
diff --git a/app/src/androidTest/assets/private_key b/app/src/androidTest/assets/private_key
deleted file mode 100644
index 7141d6f4..00000000
--- a/app/src/androidTest/assets/private_key
+++ /dev/null
Binary files differ
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt
deleted file mode 100644
index 17c7cbed..00000000
--- a/app/src/androidTest/java/com/zeapo/pwdstore/DecryptTest.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package com.zeapo.pwdstore
-
-import android.annotation.SuppressLint
-import android.content.ClipboardManager
-import android.content.Context
-import android.content.Intent
-import android.os.IBinder
-import android.os.ParcelFileDescriptor
-import android.os.SystemClock
-import android.util.Log
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.ActivityTestRule
-import com.zeapo.pwdstore.crypto.PgpActivity
-import java.io.File
-import java.io.FileOutputStream
-import java.io.IOException
-import java.nio.charset.StandardCharsets
-import kotlinx.android.synthetic.main.decrypt_layout.crypto_extra_show
-import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_category_decrypt
-import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_file
-import kotlinx.android.synthetic.main.decrypt_layout.crypto_password_show
-import kotlinx.android.synthetic.main.decrypt_layout.crypto_username_show
-import org.apache.commons.io.FileUtils
-import org.apache.commons.io.IOUtils
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.openintents.openpgp.IOpenPgpService2
-
-@RunWith(AndroidJUnit4::class)
-@LargeTest
-class DecryptTest {
- private lateinit var targetContext: Context
- private lateinit var testContext: Context
- lateinit var activity: PgpActivity
-
- private val name = "sub"
- private val parentPath = "/category/"
- lateinit var path: String
- lateinit var repoPath: String
-
- @Rule @JvmField
- var mActivityRule: ActivityTestRule<PgpActivity> = ActivityTestRule<PgpActivity>(PgpActivity::class.java, true, false)
-
- private fun init() {
- targetContext = InstrumentationRegistry.getInstrumentation().targetContext
- testContext = InstrumentationRegistry.getInstrumentation().context
- copyAssets("encrypted-store", File(targetContext.filesDir, "test-store").absolutePath)
- repoPath = File(targetContext.filesDir, "test-store").absolutePath
- path = "$repoPath/$parentPath/$name.gpg".replace("//", "/")
-
- val intent = Intent(targetContext, PgpActivity::class.java)
- intent.putExtra("OPERATION", "DECRYPT")
- intent.putExtra("FILE_PATH", path)
- intent.putExtra("REPO_PATH", repoPath)
-
- activity = mActivityRule.launchActivity(intent)
- }
-
- @Test
- fun pathShouldDecompose() {
- val pathOne = "/fake/path/cat1/n1.gpg"
- val pathTwo = "/fake/path/n2.gpg"
-
- assertEquals("/cat1/n1.gpg", PgpActivity.getRelativePath(pathOne, "/fake/path"))
- assertEquals("/cat1/", PgpActivity.getParentPath(pathOne, "/fake/path"))
- assertEquals("n1", PgpActivity.getName("$pathOne/fake/path"))
- // test that even if we append a `/` it still works
- assertEquals("n1", PgpActivity.getName("$pathOne/fake/path/"))
-
- assertEquals("/n2.gpg", PgpActivity.getRelativePath(pathTwo, "/fake/path"))
- assertEquals("/", PgpActivity.getParentPath(pathTwo, "/fake/path"))
- assertEquals("n2", PgpActivity.getName("$pathTwo/fake/path"))
- assertEquals("n2", PgpActivity.getName("$pathTwo/fake/path/"))
- }
-
- @Test
- fun activityShouldShowName() {
- init()
-
- val categoryView = activity.crypto_password_category_decrypt
- assertNotNull(categoryView)
- assertEquals(parentPath, categoryView.text)
-
- val nameView = activity.crypto_password_file
- assertNotNull(nameView)
- assertEquals(name, nameView.text)
- }
-
- @SuppressLint("ApplySharedPref") // we need the preferences right away
- @Test
- fun shouldDecrypt() {
- init()
- val clearPass = IOUtils.toString(testContext.assets.open("clear-store/category/sub"), StandardCharsets.UTF_8)
- val passEntry = PasswordEntry(clearPass)
-
- // Setup the timer to 1 second
- // first remember the previous timer to set it back later
- val showTime = try {
- Integer.parseInt(activity.settings.getString("general_show_time", "45") ?: "45")
- } catch (e: NumberFormatException) {
- 45
- }
- // second set the new timer
- activity.settings.edit().putString("general_show_time", "2").commit()
-
- activity.onBound(object : IOpenPgpService2 {
- override fun createOutputPipe(p0: Int): ParcelFileDescriptor {
- TODO("Not yet implemented")
- }
-
- override fun asBinder(): IBinder {
- TODO("Not yet implemented")
- }
-
- override fun execute(p0: Intent?, p1: ParcelFileDescriptor?, p2: Int): Intent {
- TODO("Not yet implemented")
- }
- })
-
- // have we decrypted things correctly?
- assertEquals(passEntry.password, activity.crypto_password_show.text)
- assertEquals(passEntry.username, activity.crypto_username_show.text.toString())
- assertEquals(passEntry.extraContent, activity.crypto_extra_show.text.toString())
-
- // did we copy the password?
- val clipboard: ClipboardManager = activity.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- assertEquals(passEntry.password, clipboard.primaryClip!!.getItemAt(0).text)
-
- // wait until the clipboard is cleared
- SystemClock.sleep(4000)
-
- // The clipboard should be cleared!!
- for (i in 0..clipboard.primaryClip!!.itemCount) {
- assertEquals("", clipboard.primaryClip!!.getItemAt(i).text)
- }
-
- // set back the timer
- activity.settings.edit().putString("general_show_time", showTime.toString()).commit()
- }
-
- companion object {
- fun copyAssets(source: String, destination: String) {
- FileUtils.forceMkdir(File(destination))
- FileUtils.cleanDirectory(File(destination))
-
- val testContext = InstrumentationRegistry.getInstrumentation().context
- val assetManager = testContext.assets
- val files: Array<String>? = assetManager.list(source)
-
- files?.map { filename ->
- val destPath = "$destination/$filename"
- val sourcePath = "$source/$filename"
-
- if (assetManager.list(sourcePath)!!.isNotEmpty()) {
- FileUtils.forceMkdir(File(destination, filename))
- copyAssets("$source/$filename", destPath)
- } else {
- try {
- val input = assetManager.open(sourcePath)
- val outFile = File(destination, filename)
- val output = FileOutputStream(outFile)
- IOUtils.copy(input, output)
- input.close()
- output.flush()
- output.close()
- } catch (e: IOException) {
- Log.e("tag", "Failed to copy asset file: $filename", e)
- }
- }
- }
- }
- }
-}
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/EncryptTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/EncryptTest.kt
deleted file mode 100644
index ba63ce1a..00000000
--- a/app/src/androidTest/java/com/zeapo/pwdstore/EncryptTest.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package com.zeapo.pwdstore
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.content.Intent
-import android.os.IBinder
-import android.os.ParcelFileDescriptor
-import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.action.ViewActions.click
-import androidx.test.espresso.action.ViewActions.scrollTo
-import androidx.test.espresso.action.ViewActions.typeText
-import androidx.test.espresso.assertion.ViewAssertions
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.espresso.matcher.ViewMatchers.withText
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.ActivityTestRule
-import com.zeapo.pwdstore.crypto.PgpActivity
-import java.io.File
-import org.apache.commons.io.FileUtils
-import org.apache.commons.io.IOUtils
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.openintents.openpgp.IOpenPgpService2
-
-@RunWith(AndroidJUnit4::class)
-@LargeTest
-class EncryptTest {
- private lateinit var targetContext: Context
- private lateinit var testContext: Context
- private lateinit var activity: PgpActivity
-
- private val name = "sub"
- private val parentPath = "/category/"
- private lateinit var path: String
- private lateinit var repoPath: String
-
- @Rule @JvmField
- var mActivityRule: ActivityTestRule<PgpActivity> = ActivityTestRule<PgpActivity>(PgpActivity::class.java, true, false)
-
- private fun init() {
- targetContext = InstrumentationRegistry.getInstrumentation().targetContext
- testContext = InstrumentationRegistry.getInstrumentation().context
-
- // have an empty store
- FileUtils.forceMkdir(File(targetContext.filesDir, "test-store"))
- FileUtils.cleanDirectory(File(targetContext.filesDir, "test-store"))
-
- repoPath = File(targetContext.filesDir, "test-store").absolutePath
-
- path = "$repoPath/$parentPath/".replace("//", "/")
-
- val intent = Intent(targetContext, PgpActivity::class.java)
- intent.putExtra("OPERATION", "ENCRYPT")
- intent.putExtra("FILE_PATH", path)
- intent.putExtra("REPO_PATH", repoPath)
-
- activity = mActivityRule.launchActivity(intent)
- }
-
- @SuppressLint("ApplySharedPref", "SetTextI18n")
- @Test
- fun shouldEncrypt() {
- init()
-
- onView(withId(R.id.crypto_password_category)).check(ViewAssertions.matches(withText(parentPath)))
- activity.onBound(object : IOpenPgpService2 {
- override fun createOutputPipe(p0: Int): ParcelFileDescriptor {
- TODO("Not yet implemented")
- }
-
- override fun asBinder(): IBinder {
- TODO("Not yet implemented")
- }
-
- override fun execute(p0: Intent?, p1: ParcelFileDescriptor?, p2: Int): Intent {
- TODO("Not yet implemented")
- }
- })
- val clearPass = IOUtils.toString(testContext.assets.open("clear-store/category/sub"), Charsets.UTF_8.name())
- val passEntry = PasswordEntry(clearPass)
-
- onView(withId(R.id.crypto_password_file_edit)).perform(typeText("sub"))
- onView(withId(R.id.crypto_password_edit)).perform(typeText(passEntry.password))
- onView(withId(R.id.crypto_extra_edit)).perform(scrollTo(), click())
- onView(withId(R.id.crypto_extra_edit)).perform(typeText(passEntry.extraContent))
-
- // we should return to the home screen once we confirm
- onView(withId(R.id.crypto_confirm_add)).perform(click())
-
- // The resulting file should exist
- assert(File("$path/$name.gpg").exists())
- }
-}
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/OtpTest.java b/app/src/androidTest/java/com/zeapo/pwdstore/OtpTest.java
deleted file mode 100644
index 76be43a1..00000000
--- a/app/src/androidTest/java/com/zeapo/pwdstore/OtpTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package com.zeapo.pwdstore;
-
-import com.zeapo.pwdstore.utils.Otp;
-import junit.framework.TestCase;
-
-public class OtpTest extends TestCase {
- public void testOtp() {
- String code = Otp.calculateCode("JBSWY3DPEHPK3PXP", 0L, "sha1", "s");
- assertEquals("282760", code);
- }
-}
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.java b/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.java
deleted file mode 100644
index dd55fbda..00000000
--- a/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-package com.zeapo.pwdstore;
-
-import junit.framework.TestCase;
-
-public class PasswordEntryTest extends TestCase {
-
- public void testGetPassword() {
- assertEquals("fooooo", new PasswordEntry("fooooo\nbla\n").getPassword());
- assertEquals("fooooo", new PasswordEntry("fooooo\nbla").getPassword());
- assertEquals("fooooo", new PasswordEntry("fooooo\n").getPassword());
- assertEquals("fooooo", new PasswordEntry("fooooo").getPassword());
- assertEquals("", new PasswordEntry("\nblubb\n").getPassword());
- assertEquals("", new PasswordEntry("\nblubb").getPassword());
- assertEquals("", new PasswordEntry("\n").getPassword());
- assertEquals("", new PasswordEntry("").getPassword());
- }
-
- public void testGetExtraContent() {
- assertEquals("bla\n", new PasswordEntry("fooooo\nbla\n").getExtraContent());
- assertEquals("bla", new PasswordEntry("fooooo\nbla").getExtraContent());
- assertEquals("", new PasswordEntry("fooooo\n").getExtraContent());
- assertEquals("", new PasswordEntry("fooooo").getExtraContent());
- assertEquals("blubb\n", new PasswordEntry("\nblubb\n").getExtraContent());
- assertEquals("blubb", new PasswordEntry("\nblubb").getExtraContent());
- assertEquals("", new PasswordEntry("\n").getExtraContent());
- assertEquals("", new PasswordEntry("").getExtraContent());
- }
-
- public void testGetUsername() {
- assertEquals(
- "username",
- new PasswordEntry("secret\nextra\nlogin: username\ncontent\n").getUsername());
- assertEquals(
- "username",
- new PasswordEntry("\nextra\nusername: username\ncontent\n").getUsername());
- assertEquals(
- "username", new PasswordEntry("\nUSERNaMe: username\ncontent\n").getUsername());
- assertEquals("username", new PasswordEntry("\nLOGiN:username").getUsername());
- assertNull(new PasswordEntry("secret\nextra\ncontent\n").getUsername());
- }
-
- public void testHasUsername() {
- assertTrue(new PasswordEntry("secret\nextra\nlogin: username\ncontent\n").hasUsername());
- assertFalse(new PasswordEntry("secret\nextra\ncontent\n").hasUsername());
- assertFalse(new PasswordEntry("secret\nlogin failed\n").hasUsername());
- assertFalse(new PasswordEntry("\n").hasUsername());
- assertFalse(new PasswordEntry("").hasUsername());
- }
-
- public void testNoTotpUriPresent() {
- PasswordEntry entry = new PasswordEntry("secret\nextra\nlogin: username\ncontent");
- assertFalse(entry.hasTotp());
- assertNull(entry.getTotpSecret());
- }
-
- public void testTotpUriInPassword() {
- PasswordEntry entry = new PasswordEntry("otpauth://totp/test?secret=JBSWY3DPEHPK3PXP");
- assertTrue(entry.hasTotp());
- assertEquals("JBSWY3DPEHPK3PXP", entry.getTotpSecret());
- }
-
- public void testTotpUriInContent() {
- PasswordEntry entry =
- new PasswordEntry(
- "secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP");
- assertTrue(entry.hasTotp());
- assertEquals("JBSWY3DPEHPK3PXP", entry.getTotpSecret());
- }
-
- public void testNoHotpUriPresent() {
- PasswordEntry entry = new PasswordEntry("secret\nextra\nlogin: username\ncontent");
- assertFalse(entry.hasHotp());
- assertNull(entry.getHotpSecret());
- assertNull(entry.getHotpCounter());
- }
-
- public void testHotpUriInPassword() {
- PasswordEntry entry =
- new PasswordEntry("otpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25");
- assertTrue(entry.hasHotp());
- assertEquals("JBSWY3DPEHPK3PXP", entry.getHotpSecret());
- assertEquals(new Long(25), entry.getHotpCounter());
- }
-
- public void testHotpUriInContent() {
- PasswordEntry entry =
- new PasswordEntry(
- "secret\nusername: test\notpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25");
- assertTrue(entry.hasHotp());
- assertEquals("JBSWY3DPEHPK3PXP", entry.getHotpSecret());
- assertEquals(new Long(25), entry.getHotpCounter());
- }
-}
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.kt
new file mode 100644
index 00000000..2f7028a4
--- /dev/null
+++ b/app/src/androidTest/java/com/zeapo/pwdstore/PasswordEntryTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+package com.zeapo.pwdstore
+
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+import org.junit.Test
+
+class PasswordEntryTest {
+ @Test fun testGetPassword() {
+ assertEquals("fooooo", PasswordEntry("fooooo\nbla\n").password)
+ assertEquals("fooooo", PasswordEntry("fooooo\nbla").password)
+ assertEquals("fooooo", PasswordEntry("fooooo\n").password)
+ assertEquals("fooooo", PasswordEntry("fooooo").password)
+ assertEquals("", PasswordEntry("\nblubb\n").password)
+ assertEquals("", PasswordEntry("\nblubb").password)
+ assertEquals("", PasswordEntry("\n").password)
+ assertEquals("", PasswordEntry("").password)
+ }
+
+ @Test fun testGetExtraContent() {
+ assertEquals("bla\n", PasswordEntry("fooooo\nbla\n").extraContent)
+ assertEquals("bla", PasswordEntry("fooooo\nbla").extraContent)
+ assertEquals("", PasswordEntry("fooooo\n").extraContent)
+ assertEquals("", PasswordEntry("fooooo").extraContent)
+ assertEquals("blubb\n", PasswordEntry("\nblubb\n").extraContent)
+ assertEquals("blubb", PasswordEntry("\nblubb").extraContent)
+ assertEquals("", PasswordEntry("\n").extraContent)
+ assertEquals("", PasswordEntry("").extraContent)
+ }
+
+ @Test fun testGetUsername() {
+ assertEquals(
+ "username",
+ PasswordEntry("secret\nextra\nlogin: username\ncontent\n").username)
+ assertEquals(
+ "username",
+ PasswordEntry("\nextra\nusername: username\ncontent\n").username)
+ assertEquals(
+ "username", PasswordEntry("\nUSERNaMe: username\ncontent\n").username)
+ assertEquals("username", PasswordEntry("\nLOGiN:username").username)
+ assertNull(PasswordEntry("secret\nextra\ncontent\n").username)
+ }
+
+ @Test fun testHasUsername() {
+ assertTrue(PasswordEntry("secret\nextra\nlogin: username\ncontent\n").hasUsername())
+ assertFalse(PasswordEntry("secret\nextra\ncontent\n").hasUsername())
+ assertFalse(PasswordEntry("secret\nlogin failed\n").hasUsername())
+ assertFalse(PasswordEntry("\n").hasUsername())
+ assertFalse(PasswordEntry("").hasUsername())
+ }
+
+ @Test fun testNoTotpUriPresent() {
+ val entry = PasswordEntry("secret\nextra\nlogin: username\ncontent")
+ assertFalse(entry.hasTotp())
+ assertNull(entry.totpSecret)
+ }
+
+ @Test fun testTotpUriInPassword() {
+ val entry = PasswordEntry("otpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
+ assertTrue(entry.hasTotp())
+ assertEquals("JBSWY3DPEHPK3PXP", entry.totpSecret)
+ }
+
+ @Test fun testTotpUriInContent() {
+ val entry = PasswordEntry(
+ "secret\nusername: test\notpauth://totp/test?secret=JBSWY3DPEHPK3PXP")
+ assertTrue(entry.hasTotp())
+ assertEquals("JBSWY3DPEHPK3PXP", entry.totpSecret)
+ }
+
+ @Test fun testNoHotpUriPresent() {
+ val entry = PasswordEntry("secret\nextra\nlogin: username\ncontent")
+ assertFalse(entry.hasHotp())
+ assertNull(entry.hotpSecret)
+ assertNull(entry.hotpCounter)
+ }
+
+ @Test fun testHotpUriInPassword() {
+ val entry = PasswordEntry("otpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25")
+ assertTrue(entry.hasHotp())
+ assertEquals("JBSWY3DPEHPK3PXP", entry.hotpSecret)
+ assertEquals(25, entry.hotpCounter)
+ }
+
+ @Test fun testHotpUriInContent() {
+ val entry = PasswordEntry(
+ "secret\nusername: test\notpauth://hotp/test?secret=JBSWY3DPEHPK3PXP&counter=25")
+ assertTrue(entry.hasHotp())
+ assertEquals("JBSWY3DPEHPK3PXP", entry.hotpSecret)
+ assertEquals(25, entry.hotpCounter)
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f3d88b1c..490fda85 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 84a90661..6623300b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists