tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AddonTest.kt (37388B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 package mozilla.components.feature.addons
      6 
      7 import androidx.test.ext.junit.runners.AndroidJUnit4
      8 import mozilla.components.browser.engine.gecko.webextension.GeckoWebExtension
      9 import mozilla.components.concept.engine.webextension.DisabledFlags
     10 import mozilla.components.concept.engine.webextension.Incognito
     11 import mozilla.components.concept.engine.webextension.Metadata
     12 import mozilla.components.concept.engine.webextension.WebExtension
     13 import mozilla.components.feature.addons.Addon.Companion.localizeOptionalPermissions
     14 import mozilla.components.support.test.mock
     15 import mozilla.components.support.test.robolectric.testContext
     16 import mozilla.components.support.test.whenever
     17 import org.junit.Assert.assertEquals
     18 import org.junit.Assert.assertFalse
     19 import org.junit.Assert.assertNotNull
     20 import org.junit.Assert.assertNull
     21 import org.junit.Assert.assertTrue
     22 import org.junit.Test
     23 import org.junit.runner.RunWith
     24 
     25 @RunWith(AndroidJUnit4::class)
     26 class AddonTest {
     27 
     28    @Test
     29    fun `translatePermissions - must return the expected string ids per permission category`() {
     30        val addon = Addon(
     31            id = "id",
     32            downloadUrl = "downloadUrl",
     33            version = "version",
     34            permissions = listOf(
     35                "bookmarks",
     36                "browserSettings",
     37                "browsingData",
     38                "clipboardRead",
     39                "clipboardWrite",
     40                "declarativeNetRequest",
     41                "declarativeNetRequestFeedback",
     42                "downloads",
     43                "downloads.open",
     44                "find",
     45                "geolocation",
     46                "history",
     47                "management",
     48                "nativeMessaging",
     49                "notifications",
     50                "pkcs11",
     51                "privacy",
     52                "proxy",
     53                "sessions",
     54                "tabHide",
     55                "tabs",
     56                "topSites",
     57                "trialML",
     58                "userScripts",
     59                "webNavigation",
     60                "devtools",
     61            ),
     62            createdAt = "",
     63            updatedAt = "",
     64        )
     65 
     66        val translatedPermissions = addon.translatePermissions(testContext)
     67        val expectedPermissions = listOf(
     68            R.string.mozac_feature_addons_permissions_bookmarks_description,
     69            R.string.mozac_feature_addons_permissions_browser_setting_description,
     70            R.string.mozac_feature_addons_permissions_browser_data_description,
     71            R.string.mozac_feature_addons_permissions_clipboard_read_description,
     72            R.string.mozac_feature_addons_permissions_clipboard_write_description,
     73            R.string.mozac_feature_addons_permissions_declarative_net_request_description,
     74            R.string.mozac_feature_addons_permissions_declarative_net_request_feedback_description,
     75            R.string.mozac_feature_addons_permissions_downloads_description,
     76            R.string.mozac_feature_addons_permissions_downloads_open_description,
     77            R.string.mozac_feature_addons_permissions_find_description,
     78            R.string.mozac_feature_addons_permissions_geolocation_description,
     79            R.string.mozac_feature_addons_permissions_history_description,
     80            R.string.mozac_feature_addons_permissions_management_description,
     81            R.string.mozac_feature_addons_permissions_native_messaging_description,
     82            R.string.mozac_feature_addons_permissions_notifications_description,
     83            R.string.mozac_feature_addons_permissions_pkcs11_description,
     84            R.string.mozac_feature_addons_permissions_privacy_description,
     85            R.string.mozac_feature_addons_permissions_proxy_description,
     86            R.string.mozac_feature_addons_permissions_sessions_description,
     87            R.string.mozac_feature_addons_permissions_tab_hide_description,
     88            R.string.mozac_feature_addons_permissions_tabs_description,
     89            R.string.mozac_feature_addons_permissions_top_sites_description,
     90            R.string.mozac_feature_addons_permissions_trial_ml_description,
     91            R.string.mozac_feature_addons_permissions_user_scripts_description,
     92            R.string.mozac_feature_addons_permissions_web_navigation_description,
     93            R.string.mozac_feature_addons_permissions_devtools_description,
     94        ).map { testContext.getString(it) }
     95        assertEquals(expectedPermissions, translatedPermissions)
     96    }
     97 
     98    @Test
     99    fun `isInstalled - true if installed state present and otherwise false`() {
    100        val addon = Addon(
    101            id = "id",
    102            downloadUrl = "downloadUrl",
    103            version = "version",
    104            permissions = emptyList(),
    105            createdAt = "",
    106            updatedAt = "",
    107        )
    108        assertFalse(addon.isInstalled())
    109 
    110        val installedAddon = addon.copy(installedState = Addon.InstalledState("id", "1.0", ""))
    111        assertTrue(installedAddon.isInstalled())
    112    }
    113 
    114    @Test
    115    fun `isEnabled - true if installed state enabled and otherwise false`() {
    116        val addon = Addon(
    117            id = "id",
    118            downloadUrl = "downloadUrl",
    119            version = "version",
    120            permissions = emptyList(),
    121            createdAt = "",
    122            updatedAt = "",
    123        )
    124        assertFalse(addon.isEnabled())
    125 
    126        val installedAddon = addon.copy(installedState = Addon.InstalledState("id", "1.0", ""))
    127        assertFalse(installedAddon.isEnabled())
    128 
    129        val enabledAddon = addon.copy(installedState = Addon.InstalledState("id", "1.0", "", enabled = true))
    130        assertTrue(enabledAddon.isEnabled())
    131    }
    132 
    133    @Test
    134    fun `classifyOriginPermissions - normalizes origins and returns HostPermissions`() {
    135        val origins = listOf(
    136            "https://developer.mozilla.org/",
    137            "*://*.developer.mozilla.org/*",
    138            "*://developer.mozilla.org/*",
    139            "https://wikipedia.org/",
    140            "*://*.wikipedia.org/*",
    141            "*://wikipedia.org/*",
    142        )
    143 
    144        val hostNormalizationResult = Addon.classifyOriginPermissions(origins)
    145        assertNotNull(hostNormalizationResult.getOrNull())
    146 
    147        val hostPermissions = hostNormalizationResult.getOrNull()!!
    148 
    149        assertEquals(hostPermissions.sites.size, 2)
    150        assertEquals(hostPermissions.wildcards.size, 2)
    151 
    152        val displayDomainList = hostPermissions.wildcards + hostPermissions.sites
    153 
    154        assertEquals(displayDomainList.size, 2)
    155 
    156        assertEquals(displayDomainList.first(), "developer.mozilla.org")
    157        assertTrue(displayDomainList.contains("wikipedia.org"))
    158    }
    159 
    160    @Test
    161    fun `permissionsListContainsAllUrls - true if any permission in the list maps to the All Urls permission`() {
    162        val permissionsWithoutAllUrls = listOf("privacy", "tabs")
    163        val permissionsWithAllUrls = listOf("privacy", "<all_urls>", "tabs")
    164 
    165        val domainsWithoutAllUrls = listOf(
    166            "https://www.mozilla.org",
    167            "http://testsite.com",
    168            "testing.com",
    169            "testing.com/*",
    170            "*.testing.com/*",
    171        )
    172 
    173        val domainsWithAllUrls = listOf(
    174            "testing.com",
    175            "*://*/*",
    176        )
    177 
    178        assertFalse(
    179            "Found all_urls permission when none exists",
    180            Addon.permissionsListContainsAllUrls(permissionsWithoutAllUrls),
    181        )
    182        assertTrue(
    183            "Did not find the all_urls permission in the list",
    184            Addon.permissionsListContainsAllUrls(permissionsWithAllUrls),
    185        )
    186 
    187        assertFalse(
    188            "Found all_urls permission when none exists",
    189            Addon.permissionsListContainsAllUrls(domainsWithoutAllUrls),
    190        )
    191        assertTrue(
    192            "Did not find the all_urls permission in the list",
    193            Addon.permissionsListContainsAllUrls(domainsWithAllUrls),
    194        )
    195    }
    196 
    197    @Test
    198    fun `filterTranslations - only keeps specified translations`() {
    199        val addon = Addon(
    200            id = "id",
    201            downloadUrl = "downloadUrl",
    202            version = "version",
    203            permissions = emptyList(),
    204            createdAt = "",
    205            updatedAt = "",
    206            translatableName = mapOf(Addon.DEFAULT_LOCALE to "name", "de" to "Name", "es" to "nombre"),
    207            translatableDescription = mapOf(
    208                Addon.DEFAULT_LOCALE to "description",
    209                "de" to "Beschreibung",
    210                "es" to "descripción",
    211            ),
    212            translatableSummary = mapOf(Addon.DEFAULT_LOCALE to "summary", "de" to "Kurzfassung", "es" to "resumen"),
    213        )
    214 
    215        val addonEn = addon.filterTranslations(listOf())
    216        assertEquals(1, addonEn.translatableName.size)
    217        assertTrue(addonEn.translatableName.contains(addonEn.defaultLocale))
    218 
    219        val addonEs = addon.filterTranslations(listOf("es"))
    220        assertEquals(2, addonEs.translatableName.size)
    221        assertTrue(addonEs.translatableName.contains(addonEn.defaultLocale))
    222        assertTrue(addonEs.translatableName.contains("es"))
    223    }
    224 
    225    @Test
    226    fun `localizeURLAccessPermissions - must translate all_urls access permission`() {
    227        val expectedString = testContext.getString(R.string.mozac_feature_addons_permissions_all_urls_description)
    228        val permissions = listOf(
    229            "webRequest",
    230            "webRequestBlocking",
    231            "<all_urls>",
    232        )
    233 
    234        val result = Addon.localizeURLAccessPermissions(testContext, permissions).first()
    235 
    236        assertEquals(expectedString, result)
    237    }
    238 
    239    @Test
    240    fun `localizeURLAccessPermissions - must translate all urls access permission`() {
    241        val expectedString = testContext.getString(R.string.mozac_feature_addons_permissions_all_urls_description)
    242        val permissions = listOf(
    243            "webRequest",
    244            "webRequestBlocking",
    245            "*://*/*",
    246        )
    247 
    248        val result = Addon.localizeURLAccessPermissions(testContext, permissions).first()
    249 
    250        assertEquals(expectedString, result)
    251    }
    252 
    253    @Test
    254    fun `localizeURLAccessPermissions - must translate domain access permissions`() {
    255        val expectedString = listOf("tweetdeck.twitter.com", "twitter.com").map {
    256            testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description, it)
    257        }
    258        val permissions = listOf(
    259            "webRequest",
    260            "webRequestBlocking",
    261            "*://tweetdeck.twitter.com/*",
    262            "*://twitter.com/*",
    263        )
    264 
    265        val result = Addon.localizeURLAccessPermissions(testContext, permissions)
    266 
    267        assertEquals(expectedString, result)
    268    }
    269 
    270    @Test
    271    fun `localizeURLAccessPermissions - must translate one site access permissions`() {
    272        val expectedString = listOf("youtube.com", "youtube-nocookie.com", "vimeo.com").map {
    273            testContext.getString(R.string.mozac_feature_addons_permissions_sites_in_domain_description, it)
    274        }
    275        val permissions = listOf(
    276            "webRequest",
    277            "*://*.youtube.com/*",
    278            "*://*.youtube-nocookie.com/*",
    279            "*://*.vimeo.com/*",
    280        )
    281 
    282        val result = Addon.localizeURLAccessPermissions(testContext, permissions)
    283 
    284        assertEquals(expectedString, result)
    285    }
    286 
    287    @Test
    288    fun `localizeURLAccessPermissions - must collapse host permissions`() {
    289        var expectedString = listOf("youtube.com", "youtube-nocookie.com", "vimeo.com", "google.co.ao").map {
    290            testContext.getString(R.string.mozac_feature_addons_permissions_sites_in_domain_description, it)
    291        } + testContext.getString(R.string.mozac_feature_addons_permissions_one_extra_domain_description_2)
    292 
    293        var permissions = listOf(
    294            "webRequest",
    295            "*://*.youtube.com/*",
    296            "*://*.youtube-nocookie.com/*",
    297            "*://*.vimeo.com/*",
    298            "*://*.google.co.ao/*",
    299            "*://*.google.com.do/*",
    300        )
    301 
    302        var result = Addon.localizeURLAccessPermissions(testContext, permissions)
    303 
    304        // 1 domain permissions must be collapsed
    305        assertEquals(expectedString, result)
    306 
    307        expectedString = listOf("youtube.com", "youtube-nocookie.com", "vimeo.com", "google.co.ao").map {
    308            testContext.getString(R.string.mozac_feature_addons_permissions_sites_in_domain_description, it)
    309        } + testContext.getString(R.string.mozac_feature_addons_permissions_extra_domains_description_plural_2)
    310 
    311        permissions = listOf(
    312            "webRequest",
    313            "*://*.youtube.com/*",
    314            "*://*.youtube-nocookie.com/*",
    315            "*://*.vimeo.com/*",
    316            "*://*.google.co.ao/*",
    317            "*://*.google.com.do/*",
    318            "*://*.google.co.ar/*",
    319        )
    320 
    321        result = Addon.localizeURLAccessPermissions(testContext, permissions)
    322 
    323        // 2 domain permissions must be collapsed
    324        assertEquals(expectedString, result)
    325 
    326        permissions = listOf(
    327            "webRequest",
    328            "*://www.youtube.com/*",
    329            "*://www.youtube-nocookie.com/*",
    330            "*://www.vimeo.com/*",
    331            "https://mozilla.org/a/b/c/",
    332            "*://www.google.com.do/*",
    333        )
    334 
    335        expectedString = listOf("www.youtube.com", "www.youtube-nocookie.com", "www.vimeo.com", "mozilla.org").map {
    336            testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description, it)
    337        } + testContext.getString(R.string.mozac_feature_addons_permissions_one_extra_site_description_2)
    338 
    339        result = Addon.localizeURLAccessPermissions(testContext, permissions)
    340 
    341        // 1 site permissions must be Collapsed
    342        assertEquals(expectedString, result)
    343 
    344        permissions = listOf(
    345            "webRequest",
    346            "*://www.youtube.com/*",
    347            "*://www.youtube-nocookie.com/*",
    348            "*://www.vimeo.com/*",
    349            "https://mozilla.org/a/b/c/",
    350            "*://www.google.com.do/*",
    351            "*://www.google.co.ar/*",
    352        )
    353 
    354        expectedString = listOf("www.youtube.com", "www.youtube-nocookie.com", "www.vimeo.com", "mozilla.org").map {
    355            testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description, it)
    356        } + testContext.getString(R.string.mozac_feature_addons_permissions_extra_sites_description_2)
    357 
    358        result = Addon.localizeURLAccessPermissions(testContext, permissions)
    359 
    360        // 2 site permissions must be Collapsed
    361        assertEquals(expectedString, result)
    362 
    363        permissions = listOf(
    364            "webRequest",
    365            "*://www.youtube.com/*",
    366            "*://www.youtube-nocookie.com/*",
    367            "*://www.vimeo.com/*",
    368            "https://mozilla.org/a/b/c/",
    369        )
    370 
    371        expectedString = listOf("www.youtube.com", "www.youtube-nocookie.com", "www.vimeo.com", "mozilla.org").map {
    372            testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description, it)
    373        }
    374 
    375        result = Addon.localizeURLAccessPermissions(testContext, permissions)
    376 
    377        // None permissions must be collapsed
    378        assertEquals(expectedString, result)
    379    }
    380 
    381    @Test
    382    fun `localizeURLAccessPermission - must provide the correct localized string`() {
    383        val siteAccess = listOf(
    384            "*://twitter.com/*",
    385            "*://tweetdeck.twitter.com/*",
    386            "https://mozilla.org/a/b/c/",
    387            "https://www.google.com.ag/*",
    388            "https://www.google.co.ck/*",
    389        )
    390 
    391        siteAccess.forEach {
    392            val stringId = Addon.getStringIdForHostPermission(it)
    393            assertEquals(R.string.mozac_feature_addons_permissions_one_site_description, stringId)
    394        }
    395 
    396        val domainAccess = listOf(
    397            "*://*.youtube.com/*",
    398            "*://*.youtube.com/*",
    399            "*://*.youtube-nocookie.com/*",
    400            "*://*.vimeo.com/*",
    401            "*://*.facebookcorewwwi.onion/*",
    402        )
    403 
    404        domainAccess.forEach {
    405            val stringId = Addon.getStringIdForHostPermission(it)
    406            assertEquals(R.string.mozac_feature_addons_permissions_sites_in_domain_description, stringId)
    407        }
    408 
    409        val allUrlsAccess = listOf(
    410            "*://*/*",
    411            "http://*/*",
    412            "https://*/*",
    413            "file://*/*",
    414            "<all_urls>",
    415        )
    416 
    417        allUrlsAccess.forEach {
    418            val stringId = Addon.getStringIdForHostPermission(it)
    419            assertEquals(R.string.mozac_feature_addons_permissions_all_urls_description, stringId)
    420        }
    421    }
    422 
    423    @Test
    424    fun `localizeOptionalPermissions - should provide LocalizedPermission list`() {
    425        val expectedLocalizedPermissions = listOf(
    426            Addon.LocalizedPermission(
    427                testContext.getString(R.string.mozac_feature_addons_permissions_all_urls_description),
    428                Addon.Permission("<all_urls>", false),
    429            ),
    430            Addon.LocalizedPermission(
    431                testContext.getString(R.string.mozac_feature_addons_permissions_web_navigation_description),
    432                Addon.Permission("webNavigation", false),
    433            ),
    434            Addon.LocalizedPermission(
    435                testContext.getString(R.string.mozac_feature_addons_permissions_clipboard_read_description),
    436                Addon.Permission("clipboardRead", false),
    437            ),
    438            Addon.LocalizedPermission(
    439                testContext.getString(R.string.mozac_feature_addons_permissions_clipboard_write_description),
    440                Addon.Permission("clipboardWrite", false),
    441            ),
    442        )
    443 
    444        val permissions = listOf(
    445            Addon.Permission("<all_urls>", false),
    446            Addon.Permission("webNavigation", false),
    447            Addon.Permission("clipboardRead", false),
    448            Addon.Permission("clipboardWrite", false),
    449        )
    450 
    451        val localizedResult = localizeOptionalPermissions(permissions, testContext)
    452        assertEquals(expectedLocalizedPermissions, localizedResult)
    453    }
    454 
    455    @Test
    456    fun `newFromWebExtension - must return an Addon instance`() {
    457        val version = "1.2.3"
    458        val permissions = listOf("scripting", "activeTab")
    459        val origins = listOf("https://example.org/")
    460        val name = "some name"
    461        val description = "some description"
    462        val extension: WebExtension = mock()
    463        val metadata: Metadata = mock()
    464        whenever(extension.id).thenReturn("some-id")
    465        whenever(extension.url).thenReturn("some-url")
    466        whenever(extension.getMetadata()).thenReturn(metadata)
    467        whenever(metadata.version).thenReturn(version)
    468        whenever(metadata.requiredPermissions).thenReturn(permissions)
    469        whenever(metadata.optionalPermissions).thenReturn(listOf("clipboardRead"))
    470        whenever(metadata.grantedOptionalPermissions).thenReturn(listOf("clipboardRead"))
    471        whenever(metadata.optionalOrigins).thenReturn(listOf("*://*.example.com/*", "*://opt-host-perm.example.com/*"))
    472        // NOTE: in grantedOptionalOrigins we are including one host permission that isn't part of the optionaOrigins list
    473        // and so it wasn't explicitly listed in the extension manifest.json but  something granted by the user on
    474        // an extension call to browser.permissions.request (allowed on the Gecko side because "*://sub.example.com" is a
    475        // subset of the "*://*.example.com" host permission, which was explicitly included in the manifest).
    476        whenever(metadata.grantedOptionalOrigins).thenReturn(listOf("*://*.example.com/*", "*://sub.example.com/*"))
    477        whenever(metadata.requiredOrigins).thenReturn(origins)
    478        whenever(metadata.name).thenReturn(name)
    479        whenever(metadata.description).thenReturn(description)
    480        whenever(metadata.disabledFlags).thenReturn(DisabledFlags.select(0))
    481        whenever(metadata.baseUrl).thenReturn("some-base-url")
    482        whenever(metadata.developerName).thenReturn("developer-name")
    483        whenever(metadata.developerUrl).thenReturn("developer-url")
    484        whenever(metadata.fullDescription).thenReturn("fullDescription")
    485        whenever(metadata.homepageUrl).thenReturn("some-url")
    486        whenever(metadata.downloadUrl).thenReturn("some-download-url")
    487        whenever(metadata.updateDate).thenReturn("1970-01-01T00:00:00Z")
    488        whenever(metadata.reviewUrl).thenReturn("some-review-url")
    489        whenever(metadata.reviewCount).thenReturn(0)
    490        whenever(metadata.averageRating).thenReturn(0f)
    491        whenever(metadata.detailUrl).thenReturn("detail-url")
    492        whenever(metadata.incognito).thenReturn(Incognito.NOT_ALLOWED)
    493 
    494        val addon = Addon.newFromWebExtension(extension)
    495        assertEquals("some-id", addon.id)
    496        assertEquals("some-url", addon.homepageUrl)
    497        assertEquals("some-download-url", addon.downloadUrl)
    498        assertEquals(permissions + origins, addon.permissions)
    499        assertEquals(
    500            listOf(Addon.Permission(name = "clipboardRead", granted = true)),
    501            addon.optionalPermissions,
    502        )
    503        assertEquals(
    504            listOf(
    505                Addon.Permission(name = "*://*.example.com/*", granted = true),
    506                Addon.Permission(name = "*://opt-host-perm.example.com/*", granted = false),
    507                Addon.Permission(name = "*://sub.example.com/*", granted = true),
    508            ),
    509            addon.optionalOrigins,
    510        )
    511        assertEquals("", addon.updatedAt)
    512        assertEquals("some name", addon.translatableName[Addon.DEFAULT_LOCALE])
    513        assertEquals("fullDescription", addon.translatableDescription[Addon.DEFAULT_LOCALE])
    514        assertEquals("some description", addon.translatableSummary[Addon.DEFAULT_LOCALE])
    515        assertEquals("developer-name", addon.author?.name)
    516        assertEquals("developer-url", addon.author?.url)
    517        assertEquals("some-download-url", addon.downloadUrl)
    518        assertEquals("some-review-url", addon.ratingUrl)
    519        assertEquals(0, addon.rating!!.reviews)
    520        assertEquals("detail-url", addon.detailUrl)
    521        assertEquals(Addon.Incognito.NOT_ALLOWED, addon.incognito)
    522    }
    523 
    524    @Test
    525    fun `fromMetadataToAddonDate - must return an valid addon formatted date`() {
    526        val expectedDate = "2023-09-28T00:37:43Z"
    527        val inputDate = "2023-09-28T00:37:43.983Z"
    528 
    529        val result = Addon.fromMetadataToAddonDate(inputDate)
    530 
    531        assertEquals(expectedDate, result)
    532    }
    533 
    534    @Test
    535    fun `fromMetadataToAddonDate - must return  handle invalid date formats`() {
    536        val expectedDate = ""
    537        val inputDate = "202xd3-09-28T00:37:43.98993Z"
    538 
    539        val result = Addon.fromMetadataToAddonDate(inputDate)
    540 
    541        assertEquals(expectedDate, result)
    542    }
    543 
    544    @Test
    545    fun `fromMetadataToAddonDate - must return empty strings`() {
    546        val expectedDate = ""
    547        val inputDate = ""
    548 
    549        val result = Addon.fromMetadataToAddonDate(inputDate)
    550 
    551        assertEquals(expectedDate, result)
    552    }
    553 
    554    @Test
    555    fun `isDisabledAsBlocklisted - true if installed state disabled status equals to BLOCKLISTED and otherwise false`() {
    556        val addon = Addon(id = "id")
    557        val blockListedAddon = addon.copy(
    558            installedState = Addon.InstalledState(
    559                id = "id",
    560                version = "1.0",
    561                optionsPageUrl = "",
    562                disabledReason = Addon.DisabledReason.BLOCKLISTED,
    563            ),
    564        )
    565 
    566        assertFalse(addon.isDisabledAsBlocklisted())
    567        assertTrue(blockListedAddon.isDisabledAsBlocklisted())
    568    }
    569 
    570    @Test
    571    fun `isDisabledAsNotCorrectlySigned - true if installed state disabled status equals to NOT_CORRECTLY_SIGNED and otherwise false`() {
    572        val addon = Addon(id = "id")
    573        val blockListedAddon = addon.copy(
    574            installedState = Addon.InstalledState(
    575                id = "id",
    576                version = "1.0",
    577                optionsPageUrl = "",
    578                disabledReason = Addon.DisabledReason.NOT_CORRECTLY_SIGNED,
    579            ),
    580        )
    581 
    582        assertFalse(addon.isDisabledAsNotCorrectlySigned())
    583        assertTrue(blockListedAddon.isDisabledAsNotCorrectlySigned())
    584    }
    585 
    586    @Test
    587    fun `isDisabledAsIncompatible - true if installed state disabled status equals to INCOMPATIBLE and otherwise false`() {
    588        val addon = Addon(id = "id")
    589        val blockListedAddon = addon.copy(
    590            installedState = Addon.InstalledState(
    591                id = "id",
    592                version = "1.0",
    593                optionsPageUrl = "",
    594                disabledReason = Addon.DisabledReason.INCOMPATIBLE,
    595            ),
    596        )
    597 
    598        assertFalse(addon.isDisabledAsIncompatible())
    599        assertTrue(blockListedAddon.isDisabledAsIncompatible())
    600    }
    601 
    602    @Test
    603    fun `provideIcon - should provide the icon from either addon or installedState`() {
    604        val addonWithoutIcon = Addon(id = "id")
    605 
    606        assertNull(addonWithoutIcon.icon)
    607        assertNull(addonWithoutIcon.installedState?.icon)
    608        assertNull(addonWithoutIcon.provideIcon())
    609 
    610        val addonWithIcon = addonWithoutIcon.copy(icon = mock())
    611 
    612        assertNotNull(addonWithIcon.icon)
    613        assertNull(addonWithIcon.installedState?.icon)
    614        assertNotNull(addonWithIcon.provideIcon())
    615 
    616        val addonWithInstalledStateIcon = addonWithoutIcon.copy(
    617            installedState = Addon.InstalledState("id", "1.0", "", icon = mock()),
    618        )
    619 
    620        assertNull(addonWithInstalledStateIcon.icon)
    621        assertNotNull(addonWithInstalledStateIcon.installedState?.icon)
    622        assertNotNull(addonWithInstalledStateIcon.provideIcon())
    623    }
    624 
    625    @Test
    626    fun `isSoftBlocked - true if installed state disabled status equals to SOFT_BLOCKED and otherwise false`() {
    627        val addon = Addon(id = "id")
    628        val softBlockedAddon = addon.copy(
    629            installedState = Addon.InstalledState(
    630                id = "id",
    631                version = "1.0",
    632                optionsPageUrl = "",
    633                disabledReason = Addon.DisabledReason.SOFT_BLOCKED,
    634            ),
    635        )
    636 
    637        assertFalse(addon.isSoftBlocked())
    638        assertTrue(softBlockedAddon.isSoftBlocked())
    639    }
    640 
    641    @Test
    642    fun `localizeDataCollectionPermissions - should return a localized string for each data collection permission`() {
    643        // The "none" permission is special and it doesn't get localized strings like the other data permissions.
    644        GeckoWebExtension.DATA_COLLECTION_PERMISSIONS.filter { permission -> permission != "none" }.map { permission ->
    645            val list = Addon.localizeDataCollectionPermissions(listOf(permission), testContext)
    646            assertTrue("expected a localized string for $permission", list.size == 1)
    647        }
    648 
    649        assertTrue(
    650            "expected non existing entries to be filtered out",
    651            Addon.localizeDataCollectionPermissions(
    652                listOf("nonExisting", "healthInfo", "locationInfo"),
    653                testContext,
    654            ).size == 2,
    655        )
    656    }
    657 
    658    @Test
    659    fun `translateRequiredDataCollectionPermissions - should return localized strings for the required data collection permissions`() {
    660        val addon = Addon(
    661            id = "addon-id",
    662            requiredDataCollectionPermissions = listOf("bookmarksInfo", "browsingActivity"),
    663        )
    664 
    665        assertEquals(
    666            listOf(
    667                R.string.mozac_feature_addons_permissions_data_collection_bookmarksInfo_short_description,
    668                R.string.mozac_feature_addons_permissions_data_collection_browsingActivity_short_description,
    669            ).map { testContext.getString(it) },
    670            addon.translateRequiredDataCollectionPermissions(testContext),
    671        )
    672    }
    673 
    674    @Test
    675    fun `localizeOptionalDataCollectionPermissions - should return a LocalizedPermission for each data collection permission`() {
    676        // The "none" permission is special and it doesn't get localized strings like the other data permissions.
    677        GeckoWebExtension.DATA_COLLECTION_PERMISSIONS.filter { permission -> permission != "none" }.map { permission ->
    678            val list = Addon.localizeOptionalDataCollectionPermissions(
    679                listOf(Addon.Permission(permission, false)),
    680                testContext,
    681            )
    682            assertTrue("expected a localized string for $permission", list.size == 1)
    683        }
    684    }
    685 
    686    @Test
    687    fun `translateOptionalDataCollectionPermissions - should return localized permissions for the optional data collection permissions`() {
    688        val addon = Addon(
    689            id = "addon-id",
    690            optionalDataCollectionPermissions = listOf(
    691                Addon.Permission("bookmarksInfo", false),
    692                Addon.Permission("browsingActivity", false),
    693            ),
    694        )
    695 
    696        assertEquals(
    697            listOf(
    698                R.string.mozac_feature_addons_permissions_data_collection_bookmarksInfo_long_description,
    699                R.string.mozac_feature_addons_permissions_data_collection_browsingActivity_long_description,
    700            ).map { testContext.getString(it) },
    701            // Only return the localized name for each LocalizedPermission.
    702            addon.translateOptionalDataCollectionPermissions(testContext).map { it.localizedName },
    703        )
    704    }
    705 
    706    @Test
    707    fun `localizeURLAccessPermission - must provide the correct localized string for the update notification`() {
    708        val siteAccess = listOf(
    709            "*://twitter.com/*",
    710            "*://tweetdeck.twitter.com/*",
    711            "https://mozilla.org/a/b/c/",
    712            "https://www.google.com.ag/*",
    713            "https://www.google.co.ck/*",
    714        )
    715 
    716        siteAccess.forEach {
    717            val stringId = Addon.getStringIdForHostPermission(it, forUpdate = true)
    718            assertEquals(R.string.mozac_feature_addons_permissions_one_site_description_for_update, stringId)
    719        }
    720 
    721        val domainAccess = listOf(
    722            "*://*.youtube.com/*",
    723            "*://*.youtube.com/*",
    724            "*://*.youtube-nocookie.com/*",
    725            "*://*.vimeo.com/*",
    726            "*://*.facebookcorewwwi.onion/*",
    727        )
    728 
    729        domainAccess.forEach {
    730            val stringId = Addon.getStringIdForHostPermission(it, forUpdate = true)
    731            assertEquals(R.string.mozac_feature_addons_permissions_sites_in_domain_description_for_update, stringId)
    732        }
    733 
    734        val allUrlsAccess = listOf(
    735            "*://*/*",
    736            "http://*/*",
    737            "https://*/*",
    738            "file://*/*",
    739            "<all_urls>",
    740        )
    741 
    742        allUrlsAccess.forEach {
    743            val stringId = Addon.getStringIdForHostPermission(it, forUpdate = true)
    744            assertEquals(R.string.mozac_feature_addons_permissions_all_urls_description_for_update, stringId)
    745        }
    746    }
    747 
    748    @Test
    749    fun `localizeURLAccessPermissions - must collapse host permissions for the update notification`() {
    750        var permissions = listOf(
    751            "*://*.youtube.com/*",
    752            "*://*.google.com.do/*",
    753        )
    754        var result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    755        assertEquals(
    756            "expected no domain collapsed",
    757            listOf("youtube.com", "google.com.do").map {
    758                testContext.getString(
    759                    R.string.mozac_feature_addons_permissions_sites_in_domain_description_for_update,
    760                    it,
    761                )
    762            },
    763            result,
    764        )
    765 
    766        permissions = listOf(
    767            "webRequest",
    768            "*://www.youtube.com/*",
    769            "*://www.youtube-nocookie.com/*",
    770        )
    771        result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    772        assertEquals(
    773            "expected no site collapsed",
    774            listOf("www.youtube.com", "www.youtube-nocookie.com").map {
    775                testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description_for_update, it)
    776            },
    777            result,
    778        )
    779 
    780        permissions = listOf(
    781            "webRequest",
    782            "*://*.youtube.com/*",
    783            "*://*.vimeo.com/*",
    784            "*://*.google.com.do/*",
    785        )
    786        result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    787        assertEquals(
    788            "expected a single domain collapsed",
    789            listOf("youtube.com", "vimeo.com").map {
    790                testContext.getString(
    791                    R.string.mozac_feature_addons_permissions_sites_in_domain_description_for_update,
    792                    it,
    793                )
    794            } + testContext.getString(R.string.mozac_feature_addons_permissions_one_extra_domain_description_for_update),
    795            result,
    796        )
    797 
    798        permissions = listOf(
    799            "webRequest",
    800            "*://*.youtube.com/*",
    801            "*://*.vimeo.com/*",
    802            "*://*.google.com.do/*",
    803            "*://*.google.co.ao/*",
    804        )
    805        result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    806        assertEquals(
    807            "expected 2 domains collapsed",
    808            listOf("youtube.com", "vimeo.com").map {
    809                testContext.getString(
    810                    R.string.mozac_feature_addons_permissions_sites_in_domain_description_for_update,
    811                    it,
    812                )
    813            } + testContext.getString(
    814                R.string.mozac_feature_addons_permissions_extra_domains_description_plural_for_update,
    815                2,
    816            ),
    817            result,
    818        )
    819 
    820        permissions = listOf(
    821            "webRequest",
    822            "*://www.youtube.com/*",
    823            "*://www.youtube-nocookie.com/*",
    824            "https://mozilla.org/a/b/c/",
    825        )
    826        result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    827        assertEquals(
    828            "Expected 1 site collapsed",
    829            listOf("www.youtube.com", "www.youtube-nocookie.com").map {
    830                testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description_for_update, it)
    831            } + testContext.getString(R.string.mozac_feature_addons_permissions_one_extra_site_description_for_update),
    832            result,
    833        )
    834 
    835        permissions = listOf(
    836            "webRequest",
    837            "*://www.youtube.com/*",
    838            "*://www.youtube-nocookie.com/*",
    839            "https://mozilla.org/a/b/c/",
    840            "*://www.google.co.ar/*",
    841        )
    842        result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    843        assertEquals(
    844            "Expected 2 sites collapsed",
    845            listOf("www.youtube.com", "www.youtube-nocookie.com").map {
    846                testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description_for_update, it)
    847            } + testContext.getString(
    848                R.string.mozac_feature_addons_permissions_extra_sites_description_for_update,
    849                2,
    850            ),
    851            result,
    852        )
    853    }
    854 
    855    @Test
    856    fun `localizeURLAccessPermissions - must translate all urls access permission for the update notification`() {
    857        val permissions = listOf(
    858            "webRequest",
    859            "webRequestBlocking",
    860            "*://*/*",
    861        )
    862 
    863        val result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true).first()
    864        assertEquals(
    865            testContext.getString(R.string.mozac_feature_addons_permissions_all_urls_description_for_update),
    866            result,
    867        )
    868    }
    869 
    870    @Test
    871    fun `localizeURLAccessPermissions - must translate all_urls access permission for the update notification`() {
    872        val permissions = listOf(
    873            "webRequest",
    874            "webRequestBlocking",
    875            "<all_urls>",
    876        )
    877 
    878        val result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true).first()
    879        assertEquals(
    880            testContext.getString(R.string.mozac_feature_addons_permissions_all_urls_description_for_update),
    881            result,
    882        )
    883    }
    884 
    885    @Test
    886    fun `localizeURLAccessPermissions - must translate domain access permissions for the update notification`() {
    887        val expectedString = listOf("tweetdeck.twitter.com", "twitter.com").map {
    888            testContext.getString(R.string.mozac_feature_addons_permissions_one_site_description_for_update, it)
    889        }
    890        val permissions = listOf(
    891            "webRequest",
    892            "webRequestBlocking",
    893            "*://tweetdeck.twitter.com/*",
    894            "*://twitter.com/*",
    895        )
    896 
    897        val result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    898        assertEquals(expectedString, result)
    899    }
    900 
    901    @Test
    902    fun `localizeURLAccessPermissions - must translate one site access permissions for the update notification`() {
    903        val expectedString = listOf("youtube.com", "vimeo.com").map {
    904            testContext.getString(R.string.mozac_feature_addons_permissions_sites_in_domain_description_for_update, it)
    905        }
    906        val permissions = listOf(
    907            "webRequest",
    908            "*://*.youtube.com/*",
    909            "*://*.vimeo.com/*",
    910        )
    911 
    912        val result = Addon.localizeURLAccessPermissions(testContext, permissions, forUpdate = true)
    913        assertEquals(expectedString, result)
    914    }
    915 }