1 package net.pterodactylus.sone.core
3 import com.google.common.base.Ticker
4 import com.google.common.io.ByteStreams
5 import freenet.keys.FreenetURI
6 import net.pterodactylus.sone.core.FreenetInterface.BackgroundFetchCallback
7 import net.pterodactylus.sone.test.capture
8 import net.pterodactylus.sone.test.mock
9 import org.hamcrest.MatcherAssert.assertThat
10 import org.hamcrest.Matchers.`is`
12 import org.mockito.ArgumentMatchers.any
13 import org.mockito.ArgumentMatchers.eq
14 import org.mockito.Mockito.`when`
15 import org.mockito.Mockito.times
16 import org.mockito.Mockito.verify
17 import java.io.ByteArrayOutputStream
18 import java.util.concurrent.TimeUnit
21 * Unit test for [DefaultElementLoaderTest].
23 class DefaultElementLoaderTest {
26 private const val IMAGE_ID = "KSK@gpl.png"
27 private val freenetURI = FreenetURI(IMAGE_ID)
30 private val freenetInterface = mock<FreenetInterface>()
31 private val ticker = mock<Ticker>()
32 private val elementLoader = DefaultElementLoader(freenetInterface, ticker)
33 private val callback = capture<BackgroundFetchCallback>()
36 fun `image loader starts request for link that is not known`() {
37 elementLoader.loadElement(IMAGE_ID)
38 verify(freenetInterface).startFetch(eq(freenetURI), any<BackgroundFetchCallback>())
42 fun `element loader only starts request once`() {
43 elementLoader.loadElement(IMAGE_ID)
44 elementLoader.loadElement(IMAGE_ID)
45 verify(freenetInterface).startFetch(eq(freenetURI), any<BackgroundFetchCallback>())
49 fun `element loader returns loading element on first call`() {
50 assertThat(elementLoader.loadElement(IMAGE_ID).loading, `is`(true))
54 fun `element loader does not cancel on image mime type`() {
55 elementLoader.loadElement(IMAGE_ID)
56 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
57 assertThat(callback.value.cancelForMimeType(freenetURI, "image/png"), `is`(false))
61 fun `element loader does cancel on audio mime type`() {
62 elementLoader.loadElement(IMAGE_ID)
63 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
64 assertThat(callback.value.cancelForMimeType(freenetURI, "audio/mpeg"), `is`(true))
68 fun `element loader does not cancel on video mime type`() {
69 elementLoader.loadElement(IMAGE_ID)
70 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
71 assertThat(callback.value.cancelForMimeType(freenetURI, "video/mkv"), `is`(true))
75 fun `element loader does not cancel on text mime type`() {
76 elementLoader.loadElement(IMAGE_ID)
77 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
78 assertThat(callback.value.cancelForMimeType(freenetURI, "text/plain"), `is`(true))
82 fun `image loader can load image`() {
83 elementLoader.loadElement(IMAGE_ID)
84 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
85 callback.value.loaded(freenetURI, "image/png", read("/static/images/unknown-image-0.png"))
86 val linkedElement = elementLoader.loadElement(IMAGE_ID)
87 assertThat(linkedElement, `is`(LinkedElement(IMAGE_ID)))
91 fun `image is not loaded again after it failed`() {
92 elementLoader.loadElement(IMAGE_ID)
93 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
94 callback.value.failed(freenetURI)
95 assertThat(elementLoader.loadElement(IMAGE_ID).failed, `is`(true))
96 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
100 fun `image is loaded again after failure cache is expired`() {
101 elementLoader.loadElement(IMAGE_ID)
102 verify(freenetInterface).startFetch(eq(freenetURI), callback.capture())
103 callback.value.failed(freenetURI)
104 `when`(ticker.read()).thenReturn(TimeUnit.MINUTES.toNanos(31))
105 val linkedElement = elementLoader.loadElement(IMAGE_ID)
106 assertThat(linkedElement.failed, `is`(false))
107 assertThat(linkedElement.loading, `is`(true))
108 verify(freenetInterface, times(2)).startFetch(eq(freenetURI), callback.capture())
111 private fun read(resource: String): ByteArray =
112 javaClass.getResourceAsStream(resource)?.use { input ->
113 ByteArrayOutputStream().use {
114 ByteStreams.copy(input, it)