From 35a8e8b42cd828a1c5634d4ee1d50fc4d0d98f5c Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Fri, 24 Jul 2020 14:33:55 +0530 Subject: [PATCH] Expand OTP and PasswordEntry tests (#968) (cherry picked from commit e3cf73885c112bc553d6a0cc01d594a87728f448) --- .github/workflows/pull_request.yml | 18 +++- .../model/PasswordEntryAndroidTest.kt | 91 +++++++++++++++++++ .../zeapo/pwdstore/utils/UriTotpFinderTest.kt | 5 + 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 app/src/androidTest/java/com/zeapo/pwdstore/model/PasswordEntryAndroidTest.kt diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 9f07976a..688ac96e 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -69,8 +69,8 @@ jobs: if: ${{ steps.service-changed.outputs.result == 'true' }} run: ./gradlew test${{ matrix.variant }} lint${{ matrix.variant}} -Dpre-dex=false - - name: Run instrumentation tests - if: ${{ steps.service-changed.outputs.result == 'true' }} + - name: Run instrumentation tests on free flavor + if: ${{ steps.service-changed.outputs.result == 'true' && matrix.variant == 'freeRelease' }} uses: reactivecircus/android-emulator-runner@v2.11.0 with: api-level: ${{ matrix.api-level }} @@ -79,4 +79,16 @@ jobs: adb shell settings put global animator_duration_scale 0 adb shell settings put global transition_animation_scale 0 adb shell settings put global window_animation_scale 0 - ./gradlew connectedCheck + ./gradlew :app:connectedFreeDebugAndroidTest + + - name: Run instrumentation tests on nonFree flavor + if: ${{ steps.service-changed.outputs.result == 'true' && matrix.variant == 'nonFreeRelease' }} + uses: reactivecircus/android-emulator-runner@v2.11.0 + with: + api-level: ${{ matrix.api-level }} + target: default + script: | + adb shell settings put global animator_duration_scale 0 + adb shell settings put global transition_animation_scale 0 + adb shell settings put global window_animation_scale 0 + ./gradlew :app:connectedNonFreeDebugAndroidTest diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/model/PasswordEntryAndroidTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/model/PasswordEntryAndroidTest.kt new file mode 100644 index 00000000..ba373f48 --- /dev/null +++ b/app/src/androidTest/java/com/zeapo/pwdstore/model/PasswordEntryAndroidTest.kt @@ -0,0 +1,91 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package com.zeapo.pwdstore.model + +import com.zeapo.pwdstore.utils.Otp +import com.zeapo.pwdstore.utils.UriTotpFinder +import java.util.Date +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue +import org.junit.Test + +class PasswordEntryAndroidTest { + + private fun makeEntry(content: String) = PasswordEntry(content, UriTotpFinder()) + + @Test fun testGetPassword() { + assertEquals("fooooo", makeEntry("fooooo\nbla\n").password) + assertEquals("fooooo", makeEntry("fooooo\nbla").password) + assertEquals("fooooo", makeEntry("fooooo\n").password) + assertEquals("fooooo", makeEntry("fooooo").password) + assertEquals("", makeEntry("\nblubb\n").password) + assertEquals("", makeEntry("\nblubb").password) + assertEquals("", makeEntry("\n").password) + assertEquals("", makeEntry("").password) + } + + @Test fun testGetExtraContent() { + assertEquals("bla\n", makeEntry("fooooo\nbla\n").extraContent) + assertEquals("bla", makeEntry("fooooo\nbla").extraContent) + assertEquals("", makeEntry("fooooo\n").extraContent) + assertEquals("", makeEntry("fooooo").extraContent) + assertEquals("blubb\n", makeEntry("\nblubb\n").extraContent) + assertEquals("blubb", makeEntry("\nblubb").extraContent) + assertEquals("", makeEntry("\n").extraContent) + assertEquals("", makeEntry("").extraContent) + } + + @Test fun testGetUsername() { + for (field in PasswordEntry.USERNAME_FIELDS) { + assertEquals("username", makeEntry("\n$field username").username) + assertEquals("username", makeEntry("\n${field.toUpperCase()} username").username) + } + assertEquals( + "username", + makeEntry("secret\nextra\nlogin: username\ncontent\n").username) + assertEquals( + "username", + makeEntry("\nextra\nusername: username\ncontent\n").username) + assertEquals( + "username", makeEntry("\nUSERNaMe: username\ncontent\n").username) + assertEquals("username", makeEntry("\nlogin: username").username) + assertEquals("foo@example.com", makeEntry("\nemail: foo@example.com").username) + assertEquals("username", makeEntry("\nidentity: username\nlogin: another_username").username) + assertEquals("username", makeEntry("\nLOGiN:username").username) + assertNull(makeEntry("secret\nextra\ncontent\n").username) + } + + @Test fun testHasUsername() { + assertTrue(makeEntry("secret\nextra\nlogin: username\ncontent\n").hasUsername()) + assertFalse(makeEntry("secret\nextra\ncontent\n").hasUsername()) + assertFalse(makeEntry("secret\nlogin failed\n").hasUsername()) + assertFalse(makeEntry("\n").hasUsername()) + assertFalse(makeEntry("").hasUsername()) + } + + @Test fun testGeneratesOtpFromTotpUri() { + val entry = makeEntry("secret\nextra\n$TOTP_URI") + assertTrue(entry.hasTotp()) + val code = Otp.calculateCode( + entry.totpSecret!!, + // The hardcoded date value allows this test to stay reproducible. + Date(8640000).time / (1000 * entry.totpPeriod), + entry.totpAlgorithm, + entry.digits + ) + assertNotNull(code) { "Generated OTP cannot be null" } + assertEquals(entry.digits.toInt(), code.length) + assertEquals("545293", code) + } + + companion object { + + const val TOTP_URI = "otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30" + } +} diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/utils/UriTotpFinderTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/utils/UriTotpFinderTest.kt index 8a836f89..0e4ac51c 100644 --- a/app/src/androidTest/java/com/zeapo/pwdstore/utils/UriTotpFinderTest.kt +++ b/app/src/androidTest/java/com/zeapo/pwdstore/utils/UriTotpFinderTest.kt @@ -16,25 +16,30 @@ class UriTotpFinderTest { fun findSecret() { assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(TOTP_URI)) assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret("name\npassword\ntotp: HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")) + assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(PASS_FILE_CONTENT)) } @Test fun findDigits() { assertEquals("12", totpFinder.findDigits(TOTP_URI)) + assertEquals("12", totpFinder.findDigits(PASS_FILE_CONTENT)) } @Test fun findPeriod() { assertEquals(25, totpFinder.findPeriod(TOTP_URI)) + assertEquals(25, totpFinder.findPeriod(PASS_FILE_CONTENT)) } @Test fun findAlgorithm() { assertEquals("SHA256", totpFinder.findAlgorithm(TOTP_URI)) + assertEquals("SHA256", totpFinder.findAlgorithm(PASS_FILE_CONTENT)) } companion object { const val TOTP_URI = "otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA256&digits=12&period=25" + const val PASS_FILE_CONTENT = "password\n$TOTP_URI" } }