using System; using System.IO; using Jellyfin.Plugin.WatchedTogether.Configuration; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Serialization; using Moq; using Xunit; namespace Jellyfin.Plugin.WatchedTogether.Tests; /// /// Marks tests that read or write the process-wide , so xUnit runs /// them serially rather than letting parallel classes clobber each other's configuration. /// [CollectionDefinition(nameof(PluginTestContext))] public class PluginTestCollection : ICollectionFixture { } /// /// Constructs a real backed by a temporary directory so that services reading /// have configuration to work with, and cleans up afterwards. /// public sealed class PluginTestContext : IDisposable { private readonly string _configDirectory; private PluginTestContext(Plugin plugin, string configDirectory) { Plugin = plugin; _configDirectory = configDirectory; } public Plugin Plugin { get; } public PluginConfiguration Configuration => Plugin.Configuration; public static PluginTestContext Create() { var dir = Path.Combine(Path.GetTempPath(), "wt-tests-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(dir); // BasePlugin derives its data folder from PluginsPath and its config file from // PluginConfigurationsPath, so both must resolve to a real directory. var paths = new Mock(); paths.SetupGet(p => p.PluginConfigurationsPath).Returns(dir); paths.SetupGet(p => p.PluginsPath).Returns(dir); // BasePlugin persists configuration through the serializer; a stub keeps tests off disk // while still letting UpdateConfiguration succeed. var serializer = new Mock(); serializer.Setup(s => s.DeserializeFromFile(It.IsAny(), It.IsAny())) .Returns(new PluginConfiguration()); var plugin = new Plugin(paths.Object, serializer.Object); return new PluginTestContext(plugin, dir); } public void Dispose() { try { if (Directory.Exists(_configDirectory)) { Directory.Delete(_configDirectory, recursive: true); } } catch (IOException) { // A leftover temp directory is not worth failing a test over. } } }