using System.Text; using System.Xml; using System.Xml.Linq; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Services.RssReader; using Microsoft.Data.Sqlite; using Xunit; namespace LanMountainDesktop.Tests; public sealed class RssReaderServiceTests : IDisposable { private readonly string _root = Path.Combine(Path.GetTempPath(), "LanMountainDesktop.RssTests", Guid.NewGuid().ToString("N")); [Fact] public void ComponentDefinition_UsesInfoCategoryAndEightByFourMinimum() { var registry = ComponentRegistry.CreateDefault(); Assert.True(registry.TryGetDefinition(BuiltInComponentIds.DesktopRssReader, out var definition)); Assert.Equal("Info", definition.Category); Assert.Equal(8, definition.MinWidthCells); Assert.Equal(4, definition.MinHeightCells); Assert.Equal(DesktopComponentResizeMode.Free, definition.ResizeMode); } [Theory] [InlineData("HTTPS://Example.COM:443/feed/#fragment", "https://example.com/feed")] [InlineData("http://Example.com:80/rss", "http://example.com/rss")] public void NormalizeFeedUrl_CanonicalizesAddress(string input, string expected) { Assert.Equal(expected, RssReaderService.NormalizeFeedUrl(input)); } [Fact] public void ParseProbe_ReadsRssAndAtom() { var rss = Encoding.UTF8.GetBytes("""Newshttps://example.comTestOne1"""); var atom = Encoding.UTF8.GetBytes("""Atom Newsx2026-01-01T00:00:00ZOne12026-01-01T00:00:00Z"""); Assert.Equal("News", RssReaderService.ParseProbe(rss, "https://example.com/rss").Title); Assert.Equal("Atom", RssReaderService.ParseProbe(atom, "https://example.com/atom").Format); } [Fact] public void ParseProbe_RejectsDtd() { var xml = Encoding.UTF8.GetBytes("""]>&xxe;xhttps://example.com"""); Assert.ThrowsAny(() => RssReaderService.ParseProbe(xml, "https://example.com/rss")); } [Fact] public void SanitizeHtml_RemovesExecutableContentAndRemoteImages() { var sanitized = RssReaderService.SanitizeHtml("

Hello

bad", false); Assert.DoesNotContain("script", sanitized, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("onclick", sanitized, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("