8000 Merge branch 'release/5.67.0' into main · githublucas420/Android@13759ea · GitHub
[go: up one dir, main page]

Skip to content

Commit 13759ea

Browse files
committed
Merge branch 'release/5.67.0' into main
2 parents da193b6 + 7707286 commit 13759ea

26 files changed

+751
-22
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,78 @@ class BrowserTabViewModelTest {
28382838
}
28392839
}
28402840

2841+
@Test
2842+
fun whenUserSubmittedQueryIfGpcIsEnabledThenAddHeaderToUrl() {
2843+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
2844+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true)
2845+
2846+
testee.onUserSubmittedQuery("foo")
2847+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2848+
2849+
val command = commandCaptor.lastValue as Navigate
2850+
assertEquals(BrowserTabViewModel.GPC_HEADER_VALUE, command.headers[BrowserTabViewModel.GPC_HEADER])
2851+
}
2852+
2853+
@Test
2854+
fun whenUserSubmittedQueryIfGpcIsDisabledThenDoNotAddHeaderToUrl() {
2855+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
2856+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false)
2857+
2858+
testee.onUserSubmittedQuery("foo")
2859+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2860+
2861+
val command = commandCaptor.lastValue as Navigate
2862+
assertTrue(command.headers.isEmpty())
2863+
}
2864+
2865+
@Test
2866+
fun whenOnDesktopSiteModeToggledIfGpcIsEnabledThenAddHeaderToUrl() {
2867+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true)
2868+
loadUrl("http://m.example.com")
2869+
2870+
testee.onDesktopSiteModeToggled(true)
2871+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2872+
2873+
val command = commandCaptor.lastValue as Navigate
2874+
assertEquals(BrowserTabViewModel.GPC_HEADER_VALUE, command.headers[BrowserTabViewModel.GPC_HEADER])
2875+
}
2876+
2877+
@Test
2878+
fun whenOnDesktopSiteModeToggledIfGpcIsDisabledThenDoNotAddHeaderToUrl() {
2879+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false)
2880+
loadUrl("http://m.example.com")
2881+
2882+
testee.onDesktopSiteModeToggled(true)
2883+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2884+
2885+
val command = commandCaptor.lastValue as Navigate
2886+
assertTrue(command.headers.isEmpty())
2887+
}
2888+
2889+
@Test
2890+
fun whenExternalAppLinkClickedIfGpcIsEnabledThenAddHeaderToUrl() {
2891+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true)
2892+
val intentType = SpecialUrlDetector.UrlType.IntentType("query", mock(), null)
2893+
2894+
testee.externalAppLinkClicked(intentType)
2895+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2896+
2897+
val command = commandCaptor.lastValue as Command.HandleExternalAppLink
2898+
assertEquals(BrowserTabViewModel.GPC_HEADER_VALUE, command.headers[BrowserTabViewModel.GPC_HEADER])
2899+
}
2900+
2901+
@Test
2902+
fun whenExternalAppLinkClickedIfGpcIsDisabledThenDoNotAddHeaderToUrl() {
2903+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false)
2904+
val intentType = SpecialUrlDetector.UrlType.IntentType("query", mock(), null)
2905+
2906+
testee.externalAppLinkClicked(intentType)
2907+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
2908+
2909+
val command = commandCaptor.lastValue as Command.HandleExternalAppLink
2910+
assertTrue(command.headers.isEmpty())
2911+
}
2912+
28412913
private fun givenNewPermissionRequestFromDomain(domain: String) {
28422914
testee.onSiteLocationPermissionRequested(domain, StubPermissionCallback())
28432915
}

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserWebViewClientTest.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.duckduckgo.app.browser.logindetection.DOMLoginDetector
2727
import com.duckduckgo.app.browser.logindetection.WebNavigationEvent
2828
import com.duckduckgo.app.browser.model.BasicAuthenticationRequest
2929
import com.duckduckgo.app.global.exception.UncaughtExceptionRepository
30+
import com.duckduckgo.app.globalprivacycontrol.GlobalPrivacyControlInjector
3031
import com.duckduckgo.app.runBlocking
3132
import com.duckduckgo.app.statistics.store.OfflinePixelCountDataStore
3233
import com.nhaarman.mockitokotlin2.*
@@ -53,6 +54,7 @@ class BrowserWebViewClientTest {
5354
private val offlinePixelCountDataStore: OfflinePixelCountDataStore = mock()
5455
private val uncaughtExceptionRepository: UncaughtExceptionRepository = mock()
5556
private val dosDetector: DosDetector = DosDetector()
57+
private val globalPrivacyControlInjector: GlobalPrivacyControlInjector = mock()
5658

5759
@UiThreadTest
5860
@Before
@@ -66,7 +68,8 @@ class BrowserWebViewClientTest {
6668
uncaughtExceptionRepository,
6769
cookieManager,
6870
loginDetector,
69-
dosDetector
71+
dosDetector,
72+
globalPrivacyControlInjector
7073
)
7174
testee.webViewClientListener = listener
7275
}
@@ -101,6 +104,13 @@ class BrowserWebViewClientTest {
101104
verify(loginDetector).onEvent(WebNavigationEvent.OnPageStarted(webView))
102105
}
103106

107+
@UiThreadTest
108+
@Test
109+
fun whenOnPageStartedCalledThenInjectDoNotSellToDom() = coroutinesTestRule.runBlocking {
110+
testee.onPageStarted(webView, EXAMPLE_URL, null)
111+
verify(globalPrivacyControlInjector).injectDoNotSellToDom(webView)
112+
}
113+
104114
@UiThreadTest
105115
@Test
106116
fun whenOnPageFinishedCalledThenListenerInstructedToUpdateNavigationState() {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2020 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.globalprivacycontrol
18+
19+
import android.webkit.WebView
20+
import androidx.test.annotation.UiThreadTest
21+
import androidx.test.platform.app.InstrumentationRegistry
22+
import com.duckduckgo.app.browser.R
23+
import com.duckduckgo.app.settings.db.SettingsDataStore
24+
import com.nhaarman.mockitokotlin2.mock
25+
import com.nhaarman.mockitokotlin2.never
26+
import com.nhaarman.mockitokotlin2.spy
27+
import com.nhaarman.mockitokotlin2.verify
28+
import com.nhaarman.mockitokotlin2.whenever
29+
import org.junit.Before
30+
import org.junit.Test
31+
32+
class GlobalPrivacyControlInjectorJsTest {
33+
34+
private val mockSettingsStore: SettingsDataStore = mock()
35+
lateinit var testee: GlobalPrivacyControlInjectorJs
36+
37+
@Before
38+
fun setup() {
39+
testee = GlobalPrivacyControlInjectorJs(mockSettingsStore)
40+
}
41+
42+
@UiThreadTest
43+
@Test
44+
fun whenInjectDoNotSellToDomAndGcpIsEnabledThenInjectToDom() {
45+
val jsToEvaluate = getJsToEvaluate()
46+
val webView = spy(WebView(InstrumentationRegistry.getInstrumentation().targetContext))
47+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true)
48+
49+
testee.injectDoNotSellToDom(webView)
50+
51+
verify(webView).evaluateJavascript(jsToEvaluate, null)
52+
}
53+
54+
@UiThreadTest
55+
@Test
56+
fun whenInjectDoNotSellToDomAndGcpIsNotEnabledThenDoNotInjectToDom() {
57+
val jsToEvaluate = getJsToEvaluate()
58+
val webView = spy(WebView(InstrumentationRegistry.getInstrumentation().targetContext))
59+
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false)
60+
61+
testee.injectDoNotSellToDom(webView)
62+
63+
verify(webView, never()).evaluateJavascript(jsToEvaluate, null)
64+
}
65+
66+
private fun getJsToEvaluate(): String {
67+
val js = InstrumentationRegistry.getInstrumentation().targetContext.resources.openRawResource(R.raw.donotsell)
68+
.bufferedReader()
69+
.use { it.readText() }
70+
return "javascript:$js"
71+
}
72+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright (c) 2020 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.globalprivacycontrol.ui
18+
19+
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
20+
import androidx.lifecycle.Observer
21+
import com.duckduckgo.app.InstantSchedulersRule
22+
import com.duckduckgo.app.globalprivacycontrol.ui.GlobalPrivacyControlViewModel.Companion.LEARN_MORE_URL
23+
import com.duckduckgo.app.settings.db.SettingsDataStore
24+
import com.duckduckgo.app.statistics.pixels.Pixel
25+
import com.nhaarman.mockitokotlin2.atLeastOnce
26+
import com.nhaarman.mockitokotlin2.lastValue
27+
import com.nhaarman.mockitokotlin2.mock
28+
import com.nhaarman.mockitokotlin2.verify
29+
import org.junit.After
30+
import org.junit.Assert.*
31+
import org.junit.Before
32+
import org.junit.Rule
33+
import org.junit.Test
34+
import org.mockito.ArgumentCaptor
35+
36+
class GlobalPrivacyControlViewModelTest {
37+
38+
@get:Rule
39+
var instantTaskExecutorRule = InstantTaskExecutorRule()
40+
41+
@get:Rule
42+
val schedulers = InstantSchedulersRule()
43+
44+
private val mockPixel: Pixel = mock()
45+
private val mockSettingsStore: SettingsDataStore = mock()
46+
private val commandCaptor = ArgumentCaptor.forClass(GlobalPrivacyControlViewModel.Command::class.java)
47+
private val viewStateCaptor = ArgumentCaptor.forClass(GlobalPrivacyControlViewModel.ViewState::class.java)
48+
private val mockCommandObserver: Observer<GlobalPrivacyControlViewModel.Command> = mock()
49+
private val mockViewStateObserver: Observer<GlobalPrivacyControlViewModel.ViewState> = mock()
50+
lateinit var testee: GlobalPrivacyControlViewModel
51+
52+
@Before
53+
fun setup() {
54+
testee = GlobalPrivacyControlViewModel(mockPixel, mockSettingsStore)
55+
testee.command.observeForever(mockCommandObserver)
56+
testee.viewState.observeForever(mockViewStateObserver)
57+
}
58+
59+
@After
60+
fun after() {
61+
testee.command.removeObserver(mockCommandObserver)
62+
testee.viewState.removeObserver(mockViewStateObserver)
63+
}
64+
65+
@Test
66+
fun whenViewModelCreateThenInitialisedWithDefaultViewState() {
67+
val defaultViewState = GlobalPrivacyControlViewModel.ViewState()
68+
verify(mockViewStateObserver, atLeastOnce()).onChanged(viewStateCaptor.capture())
69+
assertEquals(defaultViewState, viewStateCaptor.value)
70+
}
71+
72+
@Test
73+
fun whenViewModelCreateThenPixelSent() {
74+
verify(mockPixel).fire(Pixel.PixelName.SETTINGS_DO_NOT_SELL_SHOWN)
75+
}
76+
77+
@Test
78+
fun whenOnLearnMoreSelectedThenOpenLearnMoreCommandIssuedWithCorrectUrl() {
79+
testee.onLearnMoreSelected()
80+
81+
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
82+
assertTrue(commandCaptor.lastValue is GlobalPrivacyControlViewModel.Command.OpenLearnMore)
83+
val url = (commandCaptor.lastValue as GlobalPrivacyControlViewModel.Command.OpenLearnMore).url
84+
assertEquals(LEARN_MORE_URL, url)
85+
}
86+
87+
@Test
88+
fun whenOnUserToggleGlobalPrivacyControlThenDoNotSellOnPixelSent() {
89+
testee.onUserToggleGlobalPrivacyControl(true)
90+
91+
verify(mockPixel).fire(Pixel.PixelName.SETTINGS_DO_NOT_SELL_ON)
92+
}
93+
94+
@Test
95+
fun whenOnUserToggleGlobalPrivacyControlThenDoNotSellOffPixelSent() {
96+
testee.onUserToggleGlobalPrivacyControl(false)
97+
98+
verify(mockPixel).fire(Pixel.PixelName.SETTINGS_DO_NOT_SELL_OFF)
99+
}
100+
101+
@Test
102+
fun whenOnUserToggleGlobalPrivacyControlSwitchedOnThenValueStoredInSettings() {
103+
testee.onUserToggleGlobalPrivacyControl(true)
104+
105+
verify(mockSettingsStore).globalPrivacyControlEnabled = true
106+
}
107+
108+
@Test
109+
fun whenOnUserToggleGlobalPrivacyControlSwitchedOffThenValueStoredInSettings() {
110+
testee.onUserToggleGlobalPrivacyControl(false)
111+
112+
verify(mockSettingsStore).globalPrivacyControlEnabled = false
113+
}
114+
115+
@Test
116+
fun whenOnUserToggleGlobalPrivacyControlSwitchedOnThenViewStateUpdatedToTrue() {
117+
testee.onUserToggleGlobalPrivacyControl(true)
118+
119+
verify(mockViewStateObserver, atLeastOnce()).onChanged(viewStateCaptor.capture())
120+
assertTrue(viewStateCaptor.value.globalPrivacyControlEnabled)
121+
}
122+
123+
@Test
124+
fun whenOnUserToggleGlobalPrivacyControlSwitchedOnThenViewStateUpdatedToFalse() {
125+
testee.onUserToggleGlobalPrivacyControl(false)
126+
127+
verify(mockViewStateObserver, atLeastOnce()).onChanged(viewStateCaptor.capture())
128+
assertFalse(viewStateCaptor.value.globalPrivacyControlEnabled)
129+
}
130+
}

app/src/androidTest/java/com/duckduckgo/app/settings/SettingsViewModelTest.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,13 @@ class SettingsViewModelTest {
233233
assertEquals(Command.LaunchAppIcon, commandCaptor.firstValue)
234234
}
235235

236+
@Test
237+
fun whenOnGlobalPrivacyControlClickedThenCommandIsLaunchGlobalPrivacyControl() {
238+
testee.onGlobalPrivacyControlClicked()
239+
testee.command.blockingObserve()
240+
verify(commandObserver).onChanged(commandCaptor.capture())
241+
assertEquals(Command.LaunchGlobalPrivacyControl, commandCaptor.firstValue)
242+
}
243+
236244
private fun latestViewState() = testee.viewState.value!!
237245
}

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@
301301
android:name="com.duckduckgo.app.privacy.ui.WhitelistActivity"
302302
android:label="@string/whitelisetActivityTitle"
303303
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity" />
304+
<activity
305+
android:name="com.duckduckgo.app.globalprivacycontrol.ui.GlobalPrivacyControlActivity"
306+
android:label="@string/globalPrivacyControlActivityTitle"
307+
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity" />
304308

305309
<service
306310
android:name="com.duckduckgo.app.job.AppConfigurationJobService"

0 commit comments

Comments
 (0)
0