From 86af6b11ed86e4a8dc72a74389079059081c81ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez?= Date: Mon, 28 Nov 2022 14:10:10 +0100 Subject: [PATCH] ADS: Framework related colors (#2567) Task/Issue URL: https://app.asana.com/0/1174433894299346/1203412677059168 ### Description Update toolbar, statusbar and navigation bar colors to latest spec ### UI changes | Light | Dark| | ------ | ----- | ![Screenshot_20221125_151024](https://user-images.githubusercontent.com/531613/204002612-76f95631-0dea-4bb4-a84a-251150a0dfb5.png)|![Screenshot_20221125_150923](https://user-images.githubusercontent.com/531613/204002617-3e850e89-1ea1-416d-b97a-b1b1fc790278.png)| Co-authored-by: Noelia Alcala --- .../animations/TrackersLottieAssetDelegate.kt | 2 +- .../ui/GlobalPrivacyControlActivity.kt | 1 - .../activity_accessibility_settings.xml | 150 ++++++------ .../activity_global_privacy_control.xml | 49 ++-- .../res/layout/include_new_browser_tab.xml | 1 + autoconsent/autoconsent-impl/build.gradle | 1 - .../layout/activity_autoconsent_settings.xml | 30 ++- .../ui/urlmatcher/AutofillUrlMatcher.kt | 24 -- .../duckduckgo/autofill/di/AutofillModule.kt | 15 +- .../suggestion/SuggestionMatcher.kt | 10 +- .../suggestion/SuggestionMatcherTest.kt | 10 +- autofill/autofill-store/build.gradle | 1 - .../store/SecureStoreBackedAutofillStore.kt | 20 +- .../AutofillDomainNameUrlMatcher.kt | 100 -------- .../SecureStoreBackedAutofillStoreTest.kt | 94 +------- .../AutofillDomainNameUrlMatcherTest.kt | 227 ------------------ .../background_text_view_container.xml | 21 -- .../src/main/res/drawable/popup_menu_bg.xml | 4 +- .../src/main/res/layout/view_dax_dialog.xml | 5 +- common-ui/src/main/res/values/attrs.xml | 1 - .../main/res/values/design-system-theming.xml | 22 +- .../res/values/design-system-typograhy.xml | 2 +- common-ui/src/main/res/values/styles.xml | 2 +- common-ui/src/main/res/values/widgets.xml | 10 +- .../secure-storage-store/build.gradle | 3 - .../store/db/WebsiteLoginCredentialsDao.kt | 2 +- .../store/RealSecureStorageRepositoryTest.kt | 150 ++++-------- versions.properties | 2 +- 28 files changed, 221 insertions(+), 738 deletions(-) delete mode 100644 autofill/autofill-api/src/main/java/com/duckduckgo/autofill/ui/urlmatcher/AutofillUrlMatcher.kt delete mode 100644 autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcher.kt delete mode 100644 autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcherTest.kt delete mode 100644 common-ui/src/main/res/drawable/background_text_view_container.xml diff --git a/app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/TrackersLottieAssetDelegate.kt b/app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/TrackersLottieAssetDelegate.kt index 782797548f8e..009ea0aa8976 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/TrackersLottieAssetDelegate.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/omnibar/animations/TrackersLottieAssetDelegate.kt @@ -92,7 +92,7 @@ internal class TrackersLottieAssetDelegate( } private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = context.getColorFromAttr(com.duckduckgo.mobile.android.R.attr.omnibarRoundedFieldBackgroundColor) + color = context.getColorFromAttr(com.duckduckgo.mobile.android.R.attr.daxColorContainer) typeface = Typeface.SANS_SERIF } diff --git a/app/src/main/java/com/duckduckgo/app/globalprivacycontrol/ui/GlobalPrivacyControlActivity.kt b/app/src/main/java/com/duckduckgo/app/globalprivacycontrol/ui/GlobalPrivacyControlActivity.kt index 2d38bb6935fe..60675677ca48 100644 --- a/app/src/main/java/com/duckduckgo/app/globalprivacycontrol/ui/GlobalPrivacyControlActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/globalprivacycontrol/ui/GlobalPrivacyControlActivity.kt @@ -77,7 +77,6 @@ class GlobalPrivacyControlActivity : DuckDuckGoActivity() { gpcSpannableString.getSpanFlags(it), ) removeSpan(it) - trim() } } binding.globalPrivacyControlDescription.apply { diff --git a/app/src/main/res/layout/activity_accessibility_settings.xml b/app/src/main/res/layout/activity_accessibility_settings.xml index 2c153370df97..b025536e3616 100644 --- a/app/src/main/res/layout/activity_accessibility_settings.xml +++ b/app/src/main/res/layout/activity_accessibility_settings.xml @@ -14,100 +14,114 @@ ~ limitations under the License. --> - + + android:id="@+id/includeToolbar" + layout="@layout/include_default_toolbar"/> - - + android:layout_height="match_parent" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + tools:ignore="Overdraw"> - + android:paddingTop="@dimen/keyline_4" + android:paddingBottom="@dimen/keyline_4" + android:orientation="vertical"> + + + android:id="@+id/fontSizeSettingsGroup" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + tools:ignore="Overdraw"> - + android:paddingEnd="@dimen/keyline_4" + android:text="@string/accessibilityFontSizeTitle" + tools:text="Text goes here"/> - + android:orientation="horizontal" + android:paddingStart="@dimen/keyline_4" + android:paddingEnd="@dimen/keyline_4"> + + + android:id="@+id/accessibilitySlider" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingTop="@dimen/keyline_4" + android:paddingBottom="@dimen/keyline_4" + android:stepSize="10" + android:valueFrom="70" + android:valueTo="170" + app:labelBehavior="gone" + app:tickVisible="false"/> - + + android:layout_height="wrap_content" + android:id="@+id/accessibilityDivider"/> + android:id="@+id/forceZoomToggle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:secondaryText="@string/accessibilityForceZoomSubtitle" + app:primaryText="@string/accessibilityForceZoomTitle" + app:showSwitch="true"/> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_global_privacy_control.xml b/app/src/main/res/layout/activity_global_privacy_control.xml index b6fae6a2f7be..9aaf97b6b72f 100644 --- a/app/src/main/res/layout/activity_global_privacy_control.xml +++ b/app/src/main/res/layout/activity_global_privacy_control.xml @@ -17,29 +17,42 @@ --> + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + tools:context="com.duckduckgo.app.globalprivacycontrol.ui.GlobalPrivacyControlActivity"> - - - + android:layout_height="match_parent"> + + + + + + diff --git a/app/src/main/res/layout/include_new_browser_tab.xml b/app/src/main/res/layout/include_new_browser_tab.xml index 9295e366cdd9..c7ef61f0bc95 100644 --- a/app/src/main/res/layout/include_new_browser_tab.xml +++ b/app/src/main/res/layout/include_new_browser_tab.xml @@ -21,6 +21,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" + android:clipChildren="false" tools:context="com.duckduckgo.app.browser.BrowserActivity" tools:showIn="@layout/fragment_browser_tab"> diff --git a/autoconsent/autoconsent-impl/build.gradle b/autoconsent/autoconsent-impl/build.gradle index c33082926551..64968f7658b9 100644 --- a/autoconsent/autoconsent-impl/build.gradle +++ b/autoconsent/autoconsent-impl/build.gradle @@ -41,7 +41,6 @@ dependencies { implementation AndroidX.appCompat implementation JakeWharton.timber implementation KotlinX.coroutines.core - implementation Google.android.material testImplementation (KotlinX.coroutines.test) { // https://github.com/Kotlin/kotlinx.coroutines/issues/2023 diff --git a/autoconsent/autoconsent-impl/src/main/res/layout/activity_autoconsent_settings.xml b/autoconsent/autoconsent-impl/src/main/res/layout/activity_autoconsent_settings.xml index db78f23954a0..e02584d37ed5 100644 --- a/autoconsent/autoconsent-impl/src/main/res/layout/activity_autoconsent_settings.xml +++ b/autoconsent/autoconsent-impl/src/main/res/layout/activity_autoconsent_settings.xml @@ -15,30 +15,34 @@ --> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + layout="@layout/include_default_toolbar"/> - + android:textColor="?attr/settingsMinorTextColor" + android:textSize="14sp" + android:textStyle="normal"/> + app:showSwitch="true" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> diff --git a/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/ui/urlmatcher/AutofillUrlMatcher.kt b/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/ui/urlmatcher/AutofillUrlMatcher.kt deleted file mode 100644 index a5523539f10b..000000000000 --- a/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/ui/urlmatcher/AutofillUrlMatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2022 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.ui.urlmatcher - -interface AutofillUrlMatcher { - fun extractUrlPartsForAutofill(originalUrl: String): ExtractedUrlParts - fun matchingForAutofill(visitedSite: ExtractedUrlParts, savedSite: ExtractedUrlParts): Boolean - - data class ExtractedUrlParts(val eTldPlus1: String?, val subdomain: String?) -} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/di/AutofillModule.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/di/AutofillModule.kt index 0a2ccc1b248c..4fdad217ffaa 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/di/AutofillModule.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/di/AutofillModule.kt @@ -24,8 +24,6 @@ import com.duckduckgo.autofill.store.RealAutofillPrefsStore import com.duckduckgo.autofill.store.RealInternalTestUserStore import com.duckduckgo.autofill.store.RealLastUpdatedTimeProvider import com.duckduckgo.autofill.store.SecureStoreBackedAutofillStore -import com.duckduckgo.autofill.store.urlmatcher.AutofillDomainNameUrlMatcher -import com.duckduckgo.autofill.ui.urlmatcher.AutofillUrlMatcher import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.securestorage.api.SecureStorage import com.squareup.anvil.annotations.ContributesTo @@ -46,17 +44,12 @@ class AutofillModule { secureStorage: SecureStorage, context: Context, internalTestUserChecker: InternalTestUserChecker, - autofillUrlMatcher: AutofillUrlMatcher, ): AutofillStore { return SecureStoreBackedAutofillStore( - secureStorage = secureStorage, - internalTestUserChecker = internalTestUserChecker, - lastUpdatedTimeProvider = RealLastUpdatedTimeProvider(), - autofillPrefsStore = RealAutofillPrefsStore(context, internalTestUserChecker), - autofillUrlMatcher = autofillUrlMatcher, + secureStorage, + internalTestUserChecker, + RealLastUpdatedTimeProvider(), + RealAutofillPrefsStore(context, internalTestUserChecker), ) } - - @Provides - fun provideAutofillUrlMatcher(): AutofillUrlMatcher = AutofillDomainNameUrlMatcher() } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcher.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcher.kt index a91a89964405..f777e32e7b35 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcher.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcher.kt @@ -16,24 +16,20 @@ package com.duckduckgo.autofill.ui.credential.management.suggestion +import com.duckduckgo.app.global.extractSchemeAndDomain import com.duckduckgo.autofill.domain.app.LoginCredentials -import com.duckduckgo.autofill.ui.urlmatcher.AutofillUrlMatcher import javax.inject.Inject -class SuggestionMatcher @Inject constructor(private val autofillUrlMatcher: AutofillUrlMatcher) { +class SuggestionMatcher @Inject constructor() { fun getSuggestions( currentUrl: String?, credentials: List, ): List { if (currentUrl == null) return emptyList() - val currentSite = autofillUrlMatcher.extractUrlPartsForAutofill(currentUrl) - if (currentSite.eTldPlus1 == null) return emptyList() return credentials.filter { - val storedDomain = it.domain ?: return@filter false - val savedSite = autofillUrlMatcher.extractUrlPartsForAutofill(storedDomain) - return@filter autofillUrlMatcher.matchingForAutofill(currentSite, savedSite) + it.domain?.extractSchemeAndDomain() == currentUrl.extractSchemeAndDomain() } } } diff --git a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcherTest.kt b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcherTest.kt index 6f5d0d84e01b..788fd43bde6d 100644 --- a/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcherTest.kt +++ b/autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/ui/credential/management/suggestion/SuggestionMatcherTest.kt @@ -17,7 +17,6 @@ package com.duckduckgo.autofill.ui.credential.management.suggestion import com.duckduckgo.autofill.domain.app.LoginCredentials -import com.duckduckgo.autofill.store.urlmatcher.AutofillDomainNameUrlMatcher import org.junit.Assert.* import org.junit.Test import org.junit.runner.RunWith @@ -26,7 +25,7 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class SuggestionMatcherTest { - private val testee = SuggestionMatcher(AutofillDomainNameUrlMatcher()) + private val testee = SuggestionMatcher() @Test fun whenUrlIsNullThenNoSuggestions() { @@ -70,13 +69,6 @@ class SuggestionMatcherTest { assertEquals(2, suggestions.size) } - @Test - fun whenSubdomainIncludedInSavedSiteAndVisitingRootSiteThenSuggestionOffered() { - val creds = listOf(creds("https://duckduckgo.com")) - val suggestions = testee.getSuggestions("https://test.duckduckgo.com", creds) - assertEquals(1, suggestions.size) - } - private fun creds(domain: String): LoginCredentials { return LoginCredentials(id = 0, domain = domain, username = "username", password = "password") } diff --git a/autofill/autofill-store/build.gradle b/autofill/autofill-store/build.gradle index b61bbe0c903d..bd38a0434874 100644 --- a/autofill/autofill-store/build.gradle +++ b/autofill/autofill-store/build.gradle @@ -15,7 +15,6 @@ dependencies { implementation KotlinX.coroutines.core implementation Google.android.material implementation project(path: ':secure-storage-api') - implementation Square.okHttp3.okHttp implementation Google.dagger implementation JakeWharton.timber diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStore.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStore.kt index df389f13f2a5..b35ac6af503c 100644 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStore.kt +++ b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStore.kt @@ -26,7 +26,6 @@ import com.duckduckgo.autofill.InternalTestUserChecker import com.duckduckgo.autofill.domain.app.LoginCredentials import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult.NoMatch -import com.duckduckgo.autofill.ui.urlmatcher.AutofillUrlMatcher import com.duckduckgo.securestorage.api.SecureStorage import com.duckduckgo.securestorage.api.WebsiteLoginDetails import com.duckduckgo.securestorage.api.WebsiteLoginDetailsWithCredentials @@ -42,7 +41,6 @@ class SecureStoreBackedAutofillStore( private val lastUpdatedTimeProvider: LastUpdatedTimeProvider, private val autofillPrefsStore: AutofillPrefsStore, private val dispatcherProvider: DispatcherProvider = DefaultDispatcherProvider(), - private val autofillUrlMatcher: AutofillUrlMatcher, ) : AutofillStore { override val autofillAvailable: Boolean @@ -81,21 +79,13 @@ class SecureStoreBackedAutofillStore( override suspend fun getCredentials(rawUrl: String): List { return withContext(dispatcherProvider.io()) { return@withContext if (autofillEnabled && autofillAvailable) { - Timber.i("Querying secure store for stored credentials. rawUrl: %s", rawUrl) + Timber.i("Querying secure store for stored credentials. rawUrl: %s, extractedDomain:%s", rawUrl, rawUrl.extractSchemeAndDomain()) + val url = rawUrl.extractSchemeAndDomain() ?: return@withContext emptyList() - val visitedSite = autofillUrlMatcher.extractUrlPartsForAutofill(rawUrl) - if (visitedSite.eTldPlus1 == null) return@withContext emptyList() + val storedCredentials = secureStorage.websiteLoginDetailsWithCredentialsForDomain(url).firstOrNull() ?: emptyList() + Timber.v("Found %d credentials for %s", storedCredentials.size, url) - // first part of domain matching happens at the DB level - val storedCredentials = - secureStorage.websiteLoginDetailsWithCredentialsForDomain(visitedSite.eTldPlus1!!).firstOrNull() ?: emptyList() - - // second part of domain matching requires filtering at code level - storedCredentials.filter { - val storedDomain = it.details.domain ?: return@filter false - val savedSite = autofillUrlMatcher.extractUrlPartsForAutofill(storedDomain) - return@filter autofillUrlMatcher.matchingForAutofill(visitedSite, savedSite) - }.map { it.toLoginCredentials() } + storedCredentials.map { it.toLoginCredentials() } } else { emptyList() } diff --git a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcher.kt b/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcher.kt deleted file mode 100644 index 6e0ff4d8c458..000000000000 --- a/autofill/autofill-store/src/main/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcher.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2022 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.urlmatcher - -import com.duckduckgo.app.global.extractDomain -import com.duckduckgo.autofill.ui.urlmatcher.AutofillUrlMatcher -import javax.inject.Inject -import okhttp3.HttpUrl.Companion.toHttpUrl -import timber.log.Timber - -class AutofillDomainNameUrlMatcher @Inject constructor() : AutofillUrlMatcher { - - override fun extractUrlPartsForAutofill(originalUrl: String): AutofillUrlMatcher.ExtractedUrlParts { - val normalizedUrl = originalUrl.normalizeScheme() - return try { - val eTldPlus1 = normalizedUrl.toHttpUrl().topPrivateDomain() - val domain = originalUrl.extractDomain() - val subdomain = determineSubdomain(domain, eTldPlus1) - AutofillUrlMatcher.ExtractedUrlParts(eTldPlus1, subdomain) - } catch (e: IllegalArgumentException) { - Timber.w("Unable to parse e-tld+1 from $originalUrl") - AutofillUrlMatcher.ExtractedUrlParts(null, null) - } - } - - private fun determineSubdomain( - domain: String?, - eTldPlus1: String?, - ): String? { - if (eTldPlus1 == null) return null - - val subdomain = domain?.replace(eTldPlus1 ?: "", "", ignoreCase = true)?.removeSuffix(".") - if (subdomain?.isBlank() == true) return null - - return subdomain - } - - override fun matchingForAutofill( - visitedSite: AutofillUrlMatcher.ExtractedUrlParts, - savedSite: AutofillUrlMatcher.ExtractedUrlParts, - ): Boolean { - // e-tld+1 must match - if (!identicalEffectiveTldPlusOne(visitedSite, savedSite)) return false - - // any of these rules can match - return identicalSubdomains(visitedSite, savedSite) || - specialHandlingForWwwSubdomainOnSavedSite(visitedSite, savedSite) || - savedSiteHasNoSubdomain(savedSite) - } - - private fun identicalEffectiveTldPlusOne( - visitedSite: AutofillUrlMatcher.ExtractedUrlParts, - savedSite: AutofillUrlMatcher.ExtractedUrlParts, - ): Boolean { - return visitedSite.eTldPlus1.equals(savedSite.eTldPlus1, ignoreCase = true) - } - - private fun identicalSubdomains( - visitedSite: AutofillUrlMatcher.ExtractedUrlParts, - savedSite: AutofillUrlMatcher.ExtractedUrlParts, - ): Boolean { - return visitedSite.subdomain.equals(savedSite.subdomain, ignoreCase = true) - } - - private fun specialHandlingForWwwSubdomainOnSavedSite( - visitedSite: AutofillUrlMatcher.ExtractedUrlParts, - savedSite: AutofillUrlMatcher.ExtractedUrlParts, - ): Boolean { - return (visitedSite.subdomain == null && savedSite.subdomain.equals(WWW, ignoreCase = true)) - } - - private fun savedSiteHasNoSubdomain(savedSite: AutofillUrlMatcher.ExtractedUrlParts): Boolean { - return savedSite.subdomain == null - } - - private fun String.normalizeScheme(): String { - if (!startsWith("https://") && !startsWith("http://")) { - return "https://$this" - } - return this - } - - companion object { - private const val WWW = "www" - } -} diff --git a/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStoreTest.kt b/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStoreTest.kt index 1c0a5a9220e3..fcd9c0bad22e 100644 --- a/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStoreTest.kt +++ b/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/SecureStoreBackedAutofillStoreTest.kt @@ -27,8 +27,6 @@ import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult.NoM import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult.UrlOnlyMatch import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult.UsernameMatch import com.duckduckgo.autofill.store.AutofillStore.ContainsCredentialsResult.UsernameMissing -import com.duckduckgo.autofill.store.urlmatcher.AutofillDomainNameUrlMatcher -import com.duckduckgo.autofill.ui.urlmatcher.AutofillUrlMatcher import com.duckduckgo.securestorage.api.SecureStorage import com.duckduckgo.securestorage.api.WebsiteLoginDetails import com.duckduckgo.securestorage.api.WebsiteLoginDetailsWithCredentials @@ -67,8 +65,6 @@ class SecureStoreBackedAutofillStoreTest { private lateinit var internalTestUserChecker: FakeInternalTestUserChecker private lateinit var secureStore: FakeSecureStore - private val autofillUrlMatcher: AutofillUrlMatcher = AutofillDomainNameUrlMatcher() - @Before fun setUp() { MockitoAnnotations.openMocks(this) @@ -353,75 +349,6 @@ class SecureStoreBackedAutofillStoreTest { assertNull(testee.getCredentialsWithId(1)) } - @Test - fun whenExactUrlMatchesThenCredentialsReturned() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://example.com" - val visitedSite = "https://example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(1, results.size) - assertEquals(1L, results[0].id) - } - - @Test - fun whenExactSubdomainMatchesThenCredentialsReturned() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://subdomain.example.com" - val visitedSite = "https://subdomain.example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(1, results.size) - assertEquals(1L, results[0].id) - } - - @Test - fun whenExactWwwSubdomainMatchesThenCredentialsReturned() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://www.example.com" - val visitedSite = "https://www.example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(1, results.size) - assertEquals(1L, results[0].id) - } - - @Test - fun whenSavedCredentialHasSubdomainAndVisitedPageDoesNotThenCredentialNotMatched() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://test.example.com" - val visitedSite = "https://example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(0, results.size) - } - - @Test - fun whenSavedCredentialHasNoSubdomainAndVisitedPageDoesThenCredentialNotMatched() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://example.com" - val visitedSite = "https://test.example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(1, results.size) - } - - @Test - fun whenSavedCredentialHasDifferentSubdomainToVisitedPageSubdomainThenCredentialNotMatched() = runTest { - setupTesteeWithAutofillAvailable() - val savedUrl = "https://test.example.com" - val visitedSite = "https://different.example.com" - storeCredentials(1, savedUrl, "username1", "password123") - - val results = testee.getCredentials(visitedSite) - assertEquals(0, results.size) - } - private fun List.assertHasNoLoginCredentials( url: String, username: String, @@ -449,13 +376,7 @@ class SecureStoreBackedAutofillStoreTest { private fun setupTesteeWithAutofillAvailable() { internalTestUserChecker = FakeInternalTestUserChecker(true) secureStore = FakeSecureStore(true) - testee = SecureStoreBackedAutofillStore( - secureStorage = secureStore, - internalTestUserChecker = internalTestUserChecker, - lastUpdatedTimeProvider = lastUpdatedTimeProvider, - autofillPrefsStore = autofillPrefsStore, - autofillUrlMatcher = autofillUrlMatcher, - ) + testee = SecureStoreBackedAutofillStore(secureStore, internalTestUserChecker, lastUpdatedTimeProvider, autofillPrefsStore) } private fun setupTestee( @@ -465,12 +386,11 @@ class SecureStoreBackedAutofillStoreTest { internalTestUserChecker = FakeInternalTestUserChecker(isInternalUser) secureStore = FakeSecureStore(canAccessSecureStorage) testee = SecureStoreBackedAutofillStore( - secureStorage = secureStore, - internalTestUserChecker = internalTestUserChecker, - lastUpdatedTimeProvider = lastUpdatedTimeProvider, - autofillPrefsStore = autofillPrefsStore, + secureStore, + internalTestUserChecker, + lastUpdatedTimeProvider, + autofillPrefsStore, dispatcherProvider = coroutineTestRule.testDispatcherProvider, - autofillUrlMatcher = autofillUrlMatcher, ) } @@ -522,7 +442,7 @@ class SecureStoreBackedAutofillStoreTest { return flow { emit( credentials.filter { - it.details.domain?.contains(domain) == true + it.details.domain == domain }.map { it.details }, @@ -544,7 +464,7 @@ class SecureStoreBackedAutofillStoreTest { return flow { emit( credentials.filter { - it.details.domain?.contains(domain) == true + it.details.domain == domain }, ) } diff --git a/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcherTest.kt b/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcherTest.kt deleted file mode 100644 index e6fcc7df8fc6..000000000000 --- a/autofill/autofill-store/src/test/java/com/duckduckgo/autofill/store/urlmatcher/AutofillDomainNameUrlMatcherTest.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2022 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.autofill.store.urlmatcher - -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue -import org.junit.Test -import org.junit.runner.RunWith -import org.robolectric.RobolectricTestRunner - -@RunWith(RobolectricTestRunner::class) -class AutofillDomainNameUrlMatcherTest { - - private val testee = AutofillDomainNameUrlMatcher() - - @Test - fun whenBasicDomainThenSameReturnedForEtldPlus1() { - val inputUrl = "duckduckgo.com" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals(inputUrl, result.eTldPlus1) - } - - @Test - fun whenUrlIsInvalidMissingTldThenEtldPlusOneIsNull() { - val inputUrl = "duckduckgo" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertNull(result.eTldPlus1) - } - - @Test - fun whenUrlIsInvalidMissingTldThenSubdomainIsNull() { - val inputUrl = "duckduckgo" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertNull(result.subdomain) - } - - @Test - fun whenContainsHttpSchemeThenEtldPlus1Returned() { - val inputUrl = "http://duckduckgo.com" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.com", result.eTldPlus1) - } - - @Test - fun whenContainsHttpsSchemeThenEtldPlus1Returned() { - val inputUrl = "https://duckduckgo.com" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.com", result.eTldPlus1) - } - - @Test - fun whenContainsWwwSubdomainThenEtldPlus1Returned() { - val inputUrl = "www.duckduckgo.com" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.com", result.eTldPlus1) - } - - @Test - fun whenContainsAnotherSubdomainThenEtldPlus1Returned() { - val inputUrl = "foo.duckduckgo.com" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.com", result.eTldPlus1) - } - - @Test - fun whenTwoPartTldWithNoSubdomainThenEtldPlus1Returned() { - val inputUrl = "duckduckgo.co.uk" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.co.uk", result.eTldPlus1) - } - - @Test - fun whenTwoPartTldWithSubdomainThenEtldPlus1Returned() { - val inputUrl = "www.duckduckgo.co.uk" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("duckduckgo.co.uk", result.eTldPlus1) - } - - @Test - fun whenSubdomainIsWwwThenCorrectlyIdentifiedAsSubdomain() { - val inputUrl = "www.duckduckgo.co.uk" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("www", result.subdomain) - } - - @Test - fun whenSubdomainIsPresentButNotWwwThenCorrectlyIdentifiedAsSubdomain() { - val inputUrl = "test.duckduckgo.co.uk" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("test", result.subdomain) - } - - @Test - fun whenSubdomainHasTwoLevelsThenCorrectlyIdentifiedAsSubdomain() { - val inputUrl = "foo.bar.duckduckgo.co.uk" - val result = testee.extractUrlPartsForAutofill(inputUrl) - assertEquals("foo.bar", result.subdomain) - } - - @Test - fun whenUrlsAreIdenticalThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("https://example.com") - val visitedSite = testee.extractUrlPartsForAutofill("https://example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenUrlsAreIdenticalExceptForUppercaseVisitedSiteThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("https://example.com") - val visitedSite = testee.extractUrlPartsForAutofill("https://EXAMPLE.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenUrlsAreIdenticalExceptForUppercaseSavedSiteThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("https://EXAMPLE.com") - val visitedSite = testee.extractUrlPartsForAutofill("https://example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenBothUrlsContainSameSubdomainThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("test.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("test.example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenBothUrlsContainWwwSubdomainThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("www.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("www.example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteContainsSubdomainAndVisitedSiteDoesNotThenNoMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("foo.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("example.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteDoesNotContainSubdomainAndVisitedSiteDoesThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("example.com") - val visitedSite = testee.extractUrlPartsForAutofill("foo.example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenUrlsHaveDifferentSubdomainsThenNoMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("bar.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("foo.example.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteContainsWwwSubdomainAndVisitedSiteDoesNotThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("www.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteContainsUppercaseWwwSubdomainAndVisitedSiteDoesNotThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("WWW.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteDoesNotContainSubdomainAndVisitedSiteDoesContainWwwSubdomainThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("example.com") - val visitedSite = testee.extractUrlPartsForAutofill("www.example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteDoesNotContainSubdomainAndVisitedSiteDoesContainUppercaseWwwSubdomainThenMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("example.com") - val visitedSite = testee.extractUrlPartsForAutofill("WWW.example.com") - assertTrue(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteContainNestedSubdomainsAndVisitedSiteContainsMatchingRootSubdomainThenNotMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("a.b.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("b.example.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteContainSubdomainAndVisitedSiteContainsNestedSubdomainsThenNotMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("b.example.com") - val visitedSite = testee.extractUrlPartsForAutofill("a.b.example.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedSiteHasNoSubdomainAndVisitedMaliciousSitePartiallyContainSavedSiteThenNoMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("example.com") - val visitedSite = testee.extractUrlPartsForAutofill("example.com.malicious.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } - - @Test - fun whenSavedMaliciousSitePartiallyContainsVisitedSiteThenNoMatchingForAutofill() { - val savedSite = testee.extractUrlPartsForAutofill("example.com.malicious.com") - val visitedSite = testee.extractUrlPartsForAutofill("example.com") - assertFalse(testee.matchingForAutofill(visitedSite, savedSite)) - } -} diff --git a/common-ui/src/main/res/drawable/background_text_view_container.xml b/common-ui/src/main/res/drawable/background_text_view_container.xml deleted file mode 100644 index accb8406b0c9..000000000000 --- a/common-ui/src/main/res/drawable/background_text_view_container.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/common-ui/src/main/res/drawable/popup_menu_bg.xml b/common-ui/src/main/res/drawable/popup_menu_bg.xml index 3b8d30ba237a..deb447fae7ff 100644 --- a/common-ui/src/main/res/drawable/popup_menu_bg.xml +++ b/common-ui/src/main/res/drawable/popup_menu_bg.xml @@ -15,6 +15,6 @@ --> - - + + \ No newline at end of file diff --git a/common-ui/src/main/res/layout/view_dax_dialog.xml b/common-ui/src/main/res/layout/view_dax_dialog.xml index 78aad676f524..a73bad53b379 100644 --- a/common-ui/src/main/res/layout/view_dax_dialog.xml +++ b/common-ui/src/main/res/layout/view_dax_dialog.xml @@ -25,7 +25,8 @@ + android:layout_height="match_parent" + android:clipChildren="false"> - diff --git a/common-ui/src/main/res/values/design-system-theming.xml b/common-ui/src/main/res/values/design-system-theming.xml index 92c17b46a376..22ad2edc60f6 100644 --- a/common-ui/src/main/res/values/design-system-theming.xml +++ b/common-ui/src/main/res/values/design-system-theming.xml @@ -136,19 +136,23 @@ @color/black60 @color/white + ?attr/daxColorSurface + ?attr/daxColorSurface + + + ?attr/daxColorSurface + ?attr/daxColorPrimaryIcon + ?attr/daxColorPrimaryText + ?attr/daxColorSecondaryText diff --git a/common-ui/src/main/res/values/widgets.xml b/common-ui/src/main/res/values/widgets.xml index 15bf52a0458b..393fa4b5152b 100644 --- a/common-ui/src/main/res/values/widgets.xml +++ b/common-ui/src/main/res/values/widgets.xml @@ -24,12 +24,12 @@ diff --git a/secure-storage/secure-storage-store/build.gradle b/secure-storage/secure-storage-store/build.gradle index 7f6012ea10db..1e9e1949854c 100644 --- a/secure-storage/secure-storage-store/build.gradle +++ b/secure-storage/secure-storage-store/build.gradle @@ -42,9 +42,6 @@ dependencies { kapt AndroidX.room.compiler testImplementation Testing.junit4 - testImplementation project(path: ':common-test') - testImplementation Testing.robolectric - testImplementation AndroidX.archCore.testing testImplementation "org.mockito.kotlin:mockito-kotlin:_" testImplementation (KotlinX.coroutines.test) { // https://github.com/Kotlin/kotlinx.coroutines/issues/2023 diff --git a/secure-storage/secure-storage-store/src/main/java/com/duckduckgo/securestorage/store/db/WebsiteLoginCredentialsDao.kt b/secure-storage/secure-storage-store/src/main/java/com/duckduckgo/securestorage/store/db/WebsiteLoginCredentialsDao.kt index 08d0fb22c792..a3ac9a3770db 100644 --- a/secure-storage/secure-storage-store/src/main/java/com/duckduckgo/securestorage/store/db/WebsiteLoginCredentialsDao.kt +++ b/secure-storage/secure-storage-store/src/main/java/com/duckduckgo/securestorage/store/db/WebsiteLoginCredentialsDao.kt @@ -36,7 +36,7 @@ interface WebsiteLoginCredentialsDao { @Query("select * from website_login_credentials") fun websiteLoginCredentials(): Flow> - @Query("select * from website_login_credentials where domain like '%' || :domain || '%'") + @Query("select * from website_login_credentials where domain = :domain") fun websiteLoginCredentialsByDomain(domain: String): Flow> @Query("select * from website_login_credentials where id = :id") diff --git a/secure-storage/secure-storage-store/src/test/java/com/duckduckgo/securestorage/store/RealSecureStorageRepositoryTest.kt b/secure-storage/secure-storage-store/src/test/java/com/duckduckgo/securestorage/store/RealSecureStorageRepositoryTest.kt index a4a7fb2f7cf9..8ccf0fbb9615 100644 --- a/secure-storage/secure-storage-store/src/test/java/com/duckduckgo/securestorage/store/RealSecureStorageRepositoryTest.kt +++ b/secure-storage/secure-storage-store/src/test/java/com/duckduckgo/securestorage/store/RealSecureStorageRepositoryTest.kt @@ -16,153 +16,97 @@ package com.duckduckgo.securestorage.store -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.room.Room -import com.duckduckgo.app.CoroutineTestRule -import com.duckduckgo.securestorage.store.db.SecureStorageDatabase import com.duckduckgo.securestorage.store.db.WebsiteLoginCredentialsDao import com.duckduckgo.securestorage.store.db.WebsiteLoginCredentialsEntity import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest -import org.junit.After import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Rule import org.junit.Test -import org.junit.runner.RunWith +import org.mockito.Mock import org.mockito.MockitoAnnotations -import org.robolectric.RobolectricTestRunner -import org.robolectric.RuntimeEnvironment +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever @ExperimentalCoroutinesApi -@RunWith(RobolectricTestRunner::class) class RealSecureStorageRepositoryTest { - - @get:Rule - @Suppress("unused") - val coroutineRule = CoroutineTestRule() - - @get:Rule - @Suppress("unused") - var instantTaskExecutorRule = InstantTaskExecutorRule() - - private lateinit var db: SecureStorageDatabase - + @Mock private lateinit var dao: WebsiteLoginCredentialsDao private lateinit var testee: RealSecureStorageRepository + private val testEntity = WebsiteLoginCredentialsEntity( + id = 1, + domain = "test.com", + username = "test", + password = "pass123", + passwordIv = "iv", + notes = "my notes", + notesIv = "notesIv", + domainTitle = "test", + lastUpdatedInMillis = 0L, + ) @Before fun setUp() { MockitoAnnotations.openMocks(this) - db = Room.inMemoryDatabaseBuilder(RuntimeEnvironment.getApplication(), SecureStorageDatabase::class.java) - .allowMainThreadQueries() - .build() - dao = db.websiteLoginCredentialsDao() testee = RealSecureStorageRepository(dao) } - @After - fun after() { - db.close() - } - @Test - fun whenRetrievingLoginCredentialByIdThenNullReturnedIfNotExists() = runTest { - assertNull(dao.getWebsiteLoginCredentialsById(entity().id)) - } + fun whenAddWebsiteLoginCredentialThenCallInsertToDao() { + runTest { + testee.addWebsiteLoginCredential(testEntity) + } - @Test - fun whenRetrievingLoginCredentialByIdThenReturnedIfExists() = runTest { - val testEntity = entity() - dao.insert(entity()) - val result = testee.getWebsiteLoginCredentialsForId(testEntity.id) - assertEquals(testEntity, result) + verify(dao).insert(testEntity) } @Test - fun whenRetrievingLoginCredentialByDomainThenReturnedIfDirectMatch() = runTest { - val testEntity = entity() - dao.insert(testEntity) - val result: List = testee.websiteLoginCredentialsForDomain("test.com").first() + fun whenGetWebsiteLoginCredentialsWithDomainThenCallGetWithDomainFromDao() = runTest { + whenever(dao.websiteLoginCredentialsByDomain("test")).thenReturn( + MutableStateFlow(listOf(testEntity)), + ) + + val result: List = + testee.websiteLoginCredentialsForDomain("test").first() + assertEquals(testEntity, result[0]) } @Test - fun whenRetrievingLoginCredentialByDomainThenEmptyListReturnedIfNoMatches() = runTest { - val testEntity = entity() - dao.insert(testEntity) - val result: List = testee.websiteLoginCredentialsForDomain("no-matches.com").first() - assertTrue(result.isEmpty()) - } + fun whenGetAllWebsiteLoginCredentialsThenCallGetAllFromDao() = runTest { + whenever(dao.websiteLoginCredentials()).thenReturn( + MutableStateFlow(listOf(testEntity)), + ) - @Test - fun whenGetAllWebsiteLoginCredentialsWithSitesThenEmptyListReturned() = runTest { - val result: List = testee.websiteLoginCredentials().first() - assertTrue(result.isEmpty()) - } + val result: List = + testee.websiteLoginCredentials().first() - @Test - fun whenGetAllWebsiteLoginCredentialsWithASingleSiteThenThatOneIsReturned() = runTest { - val testEntity = entity() - dao.insert(testEntity) - val result: List = testee.websiteLoginCredentials().first() assertEquals(listOf(testEntity), result) } @Test - fun whenGetAllWebsiteLoginCredentialsWithMultipleSitesThenThatAllReturned() = runTest { - val testEntity = entity() - val anotherEntity = entity(id = testEntity.id + 1) - dao.insert(testEntity) - dao.insert(anotherEntity) - val result: List = testee.websiteLoginCredentials().first() - assertEquals(listOf(testEntity, anotherEntity), result) + fun whenGetWebsiteLoginCredentialsWithIDThenCallGetWithIDFromDao() = runTest { + whenever(dao.getWebsiteLoginCredentialsById(1)).thenReturn(testEntity) + + val result = + testee.getWebsiteLoginCredentialsForId(1) + + assertEquals(testEntity, result) } @Test fun whenUpdateWebsiteLoginCredentialsThenCallUpdateToDao() = runTest { - val testEntity = entity() - dao.insert(testEntity) - testee.updateWebsiteLoginCredentials(testEntity.copy(username = "newUsername")) - val updated = testee.getWebsiteLoginCredentialsForId(testEntity.id) - assertNotNull(updated) - assertEquals("newUsername", updated!!.username) + testee.updateWebsiteLoginCredentials(testEntity) + + verify(dao).update(testEntity) } @Test - fun whenDeleteWebsiteLoginCredentialsThenEntityRemoved() = runTest { - val testEntity = entity() - dao.insert(testEntity) + fun whenDeleteWebsiteLoginCredentialsThenCallDeleteToDao() = runTest { testee.deleteWebsiteLoginCredentials(1) - val nowDeleted = dao.getWebsiteLoginCredentialsById(testEntity.id) - assertNull(nowDeleted) - } - private fun entity( - id: Long = 1, - domain: String = "test.com", - username: String = "test", - password: String = "pass123", - passwordIv: String = "iv", - notes: String = "my notes", - notesIv: String = "notesIv", - domainTitle: String = "test", - lastUpdatedInMillis: Long = 0L, - ): WebsiteLoginCredentialsEntity { - return WebsiteLoginCredentialsEntity( - id = id, - domain = domain, - username = username, - password = password, - passwordIv = passwordIv, - notes = notes, - notesIv = notesIv, - domainTitle = domainTitle, - lastUpdatedInMillis = lastUpdatedInMillis, - ) + verify(dao).delete(1) } } diff --git a/versions.properties b/versions.properties index 9f1b04227c57..9ca4d8b29fdf 100644 --- a/versions.properties +++ b/versions.properties @@ -67,7 +67,7 @@ version.com.github.bumptech.glide..okhttp3-integration=4.13.2 version.com.nhaarman.mockitokotlin2..mockito-kotlin=2.2.0 -version.google.android.material=1.7.0 +version.google.android.material=1.6.1 version.google.dagger=2.44.2