mirror of
https://github.com/Athou/commafeed.git
synced 2026-10-23 21:49:05 +00:00
add support for declared icons in feeds (#2048)
This commit is contained in:
@@ -75,33 +75,4 @@ class FacebookFaviconFetcherTest {
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithInvalidIconResponse() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://www.facebook.com/something?id=validUserId");
|
||||
|
||||
// Create a byte array that's too small
|
||||
byte[] iconBytes = new byte[50];
|
||||
String contentType = "image/png";
|
||||
|
||||
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://graph.facebook.com/validUserId/picture?type=square&height=16")).thenReturn(httpResult);
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithBlacklistedContentType() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://www.facebook.com/something?id=validUserId");
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "application/xml"; // Blacklisted content type
|
||||
|
||||
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://graph.facebook.com/validUserId/picture?type=square&height=16")).thenReturn(httpResult);
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FeedFaviconFetcherTest {
|
||||
|
||||
@Mock
|
||||
private HttpGetter httpGetter;
|
||||
|
||||
private FeedFaviconFetcher faviconFetcher;
|
||||
|
||||
@BeforeEach
|
||||
void init() {
|
||||
faviconFetcher = new FeedFaviconFetcher(httpGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithNullIconUrl() {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
Mockito.verifyNoInteractions(httpGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithValidIconUrl() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setIconUrl("https://example.com/icon.png");
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "image/png";
|
||||
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(httpResult);
|
||||
|
||||
Favicon result = faviconFetcher.fetch(feed);
|
||||
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(iconBytes, result.icon());
|
||||
Assertions.assertTrue(result.mediaType().isCompatible(MediaType.valueOf(contentType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithHttpGetterException() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setIconUrl("https://example.com/icon.png");
|
||||
|
||||
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenThrow(new RuntimeException("Network error"));
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class HtmlFaviconFetcherTest {
|
||||
|
||||
@Mock
|
||||
private HttpGetter httpGetter;
|
||||
|
||||
private HtmlFaviconFetcher faviconFetcher;
|
||||
|
||||
@BeforeEach
|
||||
void init() {
|
||||
faviconFetcher = new HtmlFaviconFetcher(httpGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithNullLink() {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
Mockito.verifyNoInteractions(httpGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithValidIconLink() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
String html = "<html><head><link rel=\"icon\" href=\"/favicon.png\" /></head><body></body></html>";
|
||||
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "image/png";
|
||||
HttpResult iconResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com/favicon.png")).thenReturn(iconResult);
|
||||
|
||||
Favicon result = faviconFetcher.fetch(feed);
|
||||
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(iconBytes, result.icon());
|
||||
Assertions.assertTrue(result.mediaType().isCompatible(MediaType.valueOf(contentType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithShortcutIconLink() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
String html = "<html><head><link rel=\"shortcut icon\" href=\"https://example.com/shortcut-favicon.ico\" /></head><body></body></html>";
|
||||
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "image/x-icon";
|
||||
HttpResult iconResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com/shortcut-favicon.ico")).thenReturn(iconResult);
|
||||
|
||||
Favicon result = faviconFetcher.fetch(feed);
|
||||
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(iconBytes, result.icon());
|
||||
Assertions.assertTrue(result.mediaType().isCompatible(MediaType.valueOf(contentType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithNoIconInPage() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
String html = "<html><head></head><body></body></html>";
|
||||
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithPageFetchException() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
Mockito.when(httpGetter.get("https://example.com")).thenThrow(new RuntimeException("Network error"));
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithIconFetchException() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
String html = "<html><head><link rel=\"icon\" href=\"https://example.com/favicon.png\" /></head><body></body></html>";
|
||||
HttpResult pageResult = new HttpResult(html.getBytes(), "text/html", null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com")).thenReturn(pageResult);
|
||||
Mockito.when(httpGetter.get("https://example.com/favicon.png")).thenThrow(new RuntimeException("Network error"));
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.commafeed.backend.favicon;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RootFaviconFetcherTest {
|
||||
|
||||
@Mock
|
||||
private HttpGetter httpGetter;
|
||||
|
||||
private RootFaviconFetcher faviconFetcher;
|
||||
|
||||
@BeforeEach
|
||||
void init() {
|
||||
faviconFetcher = new RootFaviconFetcher(httpGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchUsesLinkWhenAvailable() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://feeds.example.com/feed");
|
||||
feed.setLink("https://www.example.com/blog");
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "image/x-icon";
|
||||
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://www.example.com/favicon.ico")).thenReturn(httpResult);
|
||||
|
||||
Favicon result = faviconFetcher.fetch(feed);
|
||||
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(iconBytes, result.icon());
|
||||
Assertions.assertTrue(result.mediaType().isCompatible(MediaType.valueOf(contentType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchFallsBackToUrlWhenLinkIsNull() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed.xml");
|
||||
|
||||
byte[] iconBytes = new byte[1000];
|
||||
String contentType = "image/x-icon";
|
||||
HttpResult httpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com/favicon.ico")).thenReturn(httpResult);
|
||||
|
||||
Favicon result = faviconFetcher.fetch(feed);
|
||||
|
||||
Assertions.assertNotNull(result);
|
||||
Assertions.assertEquals(iconBytes, result.icon());
|
||||
Assertions.assertTrue(result.mediaType().isCompatible(MediaType.valueOf(contentType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithHttpGetterException() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://example.com/feed.xml");
|
||||
feed.setLink("https://example.com");
|
||||
|
||||
Mockito.when(httpGetter.get("https://example.com/favicon.ico")).thenThrow(new RuntimeException("Network error"));
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
}
|
||||
@@ -168,31 +168,6 @@ class YoutubeFaviconFetcherTest {
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithInvalidIconResponse() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
feed.setUrl("https://youtube.com/feeds/videos.xml?user=testUser");
|
||||
|
||||
Mockito.when(config.googleAuthKey()).thenReturn(Optional.of("test-api-key"));
|
||||
|
||||
byte[] apiResponse = """
|
||||
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}""".getBytes();
|
||||
HttpResult apiHttpResult = new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://www.googleapis.com/youtube/v3/channels?part=snippet&key=test-api-key&forUsername=testUser"))
|
||||
.thenReturn(apiHttpResult);
|
||||
|
||||
JsonNode jsonNode = new ObjectMapper().readTree(apiResponse);
|
||||
Mockito.when(objectMapper.readTree(apiResponse)).thenReturn(jsonNode);
|
||||
|
||||
// Create a byte array that's too small
|
||||
byte[] iconBytes = new byte[50];
|
||||
String contentType = "image/png";
|
||||
HttpResult iconHttpResult = new HttpResult(iconBytes, contentType, null, null, null, Duration.ZERO);
|
||||
Mockito.when(httpGetter.get("https://example.com/icon.png")).thenReturn(iconHttpResult);
|
||||
|
||||
Assertions.assertNull(faviconFetcher.fetch(feed));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFetchWithEmptyApiResponse() throws Exception {
|
||||
Feed feed = new Feed();
|
||||
|
||||
Reference in New Issue
Block a user