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)));
}
}
}