FaviconsTest.kt

2.6 KB · raw

1package com.peachpasswords.ui.components23import org.junit.Assert.assertArrayEquals4import org.junit.Assert.assertEquals5import org.junit.Assert.assertNull6import org.junit.Test78class FaviconsTest {910    @Test fun finds_rel_icon_href() {11        val html = """<html><head><link rel="icon" href="/static/icon.png"></head></html>"""12        assertEquals("/static/icon.png", extractIconHref(html))13    }1415    @Test fun finds_shortcut_icon_and_apple_touch_icon() {16        assertEquals(17            "/favicon-32.png",18            extractIconHref("""<link rel="shortcut icon" href="/favicon-32.png">"""),19        )20        assertEquals(21            "/apple.png",22            extractIconHref("""<LINK REL="apple-touch-icon" HREF="/apple.png">"""),23        )24    }2526    @Test fun skips_non_icon_links_and_returns_null_when_absent() {27        val html = """28            <link rel="stylesheet" href="/a.css">29            <link rel="canonical" href="https://x.test/">30            <link rel="preconnect" href="https://cdn.x.test">31        """.trimIndent()32        assertNull(extractIconHref(html))33        assertNull(extractIconHref("<html><body>no head tags</body></html>"))34    }3536    @Test fun resolves_relative_absolute_and_protocol_relative_hrefs() {37        assertEquals("https://x.test/img/icon.png", resolveIconUrl("/img/icon.png", "x.test"))38        assertEquals("https://x.test/icon.png", resolveIconUrl("icon.png", "x.test"))39        assertEquals("https://cdn.x.test/i.ico", resolveIconUrl("//cdn.x.test/i.ico", "x.test"))40        assertEquals("https://x.test/a.ico", resolveIconUrl("http://x.test/a.ico", "x.test"))41        assertEquals("https://y.test/b.ico", resolveIconUrl("https://y.test/b.ico", "x.test"))42    }4344    @Test fun rejects_data_and_javascript_hrefs() {45        assertNull(resolveIconUrl("data:image/png;base64,AAAA", "x.test"))46        assertNull(resolveIconUrl("javascript:void(0)", "x.test"))47        assertNull(resolveIconUrl("   ", "x.test"))48    }4950    @Test fun unwraps_png_inside_ico_container() {51        val png = byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 1, 2, 3)52        val ico = ByteArray(22 + png.size)53        ico[2] = 1 // ICO type54        ico[18] = 22 // data offset, little-endian55        png.copyInto(ico, 22)56        assertArrayEquals(png, decodeOrUnwrapIco(ico))57    }5859    @Test fun passes_non_ico_bytes_through_and_rejects_ico_without_png() {60        val png = byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47, 1, 2, 3)61        assertArrayEquals(png, decodeOrUnwrapIco(png))6263        val icoBmp = ByteArray(22 + 4)64        icoBmp[2] = 165        icoBmp[18] = 2266        assertNull(decodeOrUnwrapIco(icoBmp))67    }68}