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 54 ico[18] = 22 55 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}