using System; using System.Collections.Generic; using Jellyfin.Plugin.JRay.Models; using Jellyfin.Plugin.JRay.Services; using Microsoft.Extensions.Logging; using Xunit; namespace Jellyfin.Plugin.JRay.Tests; /// /// JR-023 — absent the File Transformation plugin, disable *only* the overlay /// and say so. There is no on-disk fallback (JR-021), so the failure path is /// the one an admin will actually meet, and it has to be legible: silently /// serving no overlay is indistinguishable from a broken install. /// /// The File Transformation assembly is not loaded in the test host, so /// TryRegister exercises its not-found branch for real rather than through a /// seam invented for the test. /// /// TRACES: UT-012, UT-013, UT-014, UT-015 | JR-023 /// public class FileTransformationRegistrationTests { // UT-012 [Fact] public void TryRegister_WithPluginAbsent_ReturnsFalse() { Assert.False(FileTransformationRegistration.TryRegister(new CapturingLogger())); } // UT-013 [Fact] public void TryRegister_WithPluginAbsent_WarnsNamingThePluginAndHowToInstallIt() { var logger = new CapturingLogger(); FileTransformationRegistration.TryRegister(logger); var entry = Assert.Single(logger.Entries); // Warning, not Information: the overlay is a headline feature and it is // off. Logging this at Information buries it among startup chatter. Assert.Equal(LogLevel.Warning, entry.Level); // The message has to carry the install URL, and must not promise the // on-disk fallback that JR-021 removed. Assert.Contains(FileTransformationRegistration.ManifestUrl, entry.Message, StringComparison.Ordinal); Assert.DoesNotContain("falling back", entry.Message, StringComparison.OrdinalIgnoreCase); } // UT-014 [Fact] public void TransformIndexHtml_WithOverlayDisabled_ReturnsContentsUnchanged() { // No Plugin instance exists in the test host, so OverlayEnabled is // false — the same branch taken when an admin switches the overlay off. var html = "
x
\n"; var result = FileTransformationRegistration.TransformIndexHtml( new TransformationPayload { Contents = html }); Assert.Equal(html, result); } // UT-015 [Fact] public void TransformIndexHtml_WithNullContents_ReturnsEmptyRatherThanThrowing() { // This callback is invoked by another plugin's code on every page // served. Throwing here would break the web client itself, not just // JRay's overlay. var result = FileTransformationRegistration.TransformIndexHtml(new TransformationPayload()); Assert.Equal(string.Empty, result); } private sealed class CapturingLogger : ILogger { public List<(LogLevel Level, string Message)> Entries { get; } = new(); public IDisposable? BeginScope(TState state) where TState : notnull => null; public bool IsEnabled(LogLevel logLevel) => true; public void Log( LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { Entries.Add((logLevel, formatter(state, exception))); } } }