diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj index 2099edcd5..c4e69d2eb 100644 --- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj +++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj @@ -27,6 +27,7 @@ + diff --git a/ErsatzTV.Core.Tests/FFmpeg/CustomStreamSelectorTests.cs b/ErsatzTV.Core.Tests/FFmpeg/CustomStreamSelectorTests.cs index 5eb6c7458..dc58bc84e 100644 --- a/ErsatzTV.Core.Tests/FFmpeg/CustomStreamSelectorTests.cs +++ b/ErsatzTV.Core.Tests/FFmpeg/CustomStreamSelectorTests.cs @@ -2,11 +2,11 @@ using Destructurama; using ErsatzTV.Core.Domain; using ErsatzTV.Core.FFmpeg; using ErsatzTV.Core.Interfaces.FFmpeg; -using ErsatzTV.Core.Tests.Fakes; using Microsoft.Extensions.Logging; using NUnit.Framework; using Serilog; using Shouldly; +using Testably.Abstractions.Testing; namespace ErsatzTV.Core.Tests.FFmpeg; @@ -94,9 +94,10 @@ public class CustomStreamSelectorTests - "eng" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -123,9 +124,10 @@ public class CustomStreamSelectorTests - audio_language: ["und"] """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -152,9 +154,10 @@ public class CustomStreamSelectorTests - audio_language: ["en", "eng"] """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -187,9 +190,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -217,9 +221,10 @@ public class CustomStreamSelectorTests - "en*" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -248,9 +253,10 @@ public class CustomStreamSelectorTests """; _audioVersion = GetTestAudioVersion("en"); - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -279,9 +285,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -305,9 +312,10 @@ public class CustomStreamSelectorTests - "eng" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -337,9 +345,10 @@ public class CustomStreamSelectorTests - "en*" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -378,9 +387,10 @@ public class CustomStreamSelectorTests } ]; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -413,9 +423,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -450,9 +461,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -492,9 +504,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -528,9 +541,10 @@ public class CustomStreamSelectorTests disable_subtitles: true """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -568,9 +582,10 @@ public class CustomStreamSelectorTests - "riff" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -600,9 +615,10 @@ public class CustomStreamSelectorTests - "movie" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -634,9 +650,10 @@ public class CustomStreamSelectorTests - "signs" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -668,9 +685,10 @@ public class CustomStreamSelectorTests - "songs" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -699,9 +717,10 @@ public class CustomStreamSelectorTests subtitle_condition: "forced" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -730,9 +749,10 @@ public class CustomStreamSelectorTests subtitle_condition: "lang like 'en%' and external" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -761,9 +781,10 @@ public class CustomStreamSelectorTests audio_condition: "title like '%movie%'" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -792,9 +813,10 @@ public class CustomStreamSelectorTests audio_condition: "channels > 2" """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -822,9 +844,10 @@ public class CustomStreamSelectorTests audio_title_blocklist: ["riff"] """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -853,9 +876,10 @@ public class CustomStreamSelectorTests subtitle_language: ["jp","en*"] """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, @@ -885,9 +909,10 @@ public class CustomStreamSelectorTests subtitle_language: ["es*","de*"] """; - var streamSelector = new CustomStreamSelector( - new FakeLocalFileSystem([new FakeFileEntry(TestFileName) { Contents = YAML }]), - _logger); + var fileSystem = new MockFileSystem(); + fileSystem.Initialize() + .WithFile(TestFileName).Which(f => f.HasStringContent(YAML)); + var streamSelector = new CustomStreamSelector(fileSystem, _logger); StreamSelectorResult result = await streamSelector.SelectStreams( _channel, diff --git a/ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs b/ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs index 02874a635..9f358f1fa 100644 --- a/ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs +++ b/ErsatzTV.Core.Tests/Fakes/FakeLocalFileSystem.cs @@ -58,12 +58,6 @@ public class FakeLocalFileSystem : ILocalFileSystem public Unit EmptyFolder(string folder) => Unit.Default; - public async Task ReadAllText(string path) => await _files - .Filter(f => f.Path == path) - .HeadOrNone() - .Select(f => f.Contents) - .IfNoneAsync(string.Empty); - public async Task ReadAllLines(string path) => await _files .Filter(f => f.Path == path) .HeadOrNone() diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj index 14d26a497..db6f919c7 100644 --- a/ErsatzTV.Core/ErsatzTV.Core.csproj +++ b/ErsatzTV.Core/ErsatzTV.Core.csproj @@ -32,6 +32,7 @@ + diff --git a/ErsatzTV.Core/FFmpeg/CustomStreamSelector.cs b/ErsatzTV.Core/FFmpeg/CustomStreamSelector.cs index 04cdde1e6..150d183f3 100644 --- a/ErsatzTV.Core/FFmpeg/CustomStreamSelector.cs +++ b/ErsatzTV.Core/FFmpeg/CustomStreamSelector.cs @@ -1,8 +1,8 @@ +using System.IO.Abstractions; using System.IO.Enumeration; using ErsatzTV.Core.Domain; using ErsatzTV.Core.FFmpeg.Selector; using ErsatzTV.Core.Interfaces.FFmpeg; -using ErsatzTV.Core.Interfaces.Metadata; using Microsoft.Extensions.Logging; using NCalc; using YamlDotNet.Serialization; @@ -10,7 +10,7 @@ using YamlDotNet.Serialization.NamingConventions; namespace ErsatzTV.Core.FFmpeg; -public class CustomStreamSelector(ILocalFileSystem localFileSystem, ILogger logger) +public class CustomStreamSelector(IFileSystem fileSystem, ILogger logger) : ICustomStreamSelector { public async Task SelectStreams( @@ -25,7 +25,7 @@ public class CustomStreamSelector(ILocalFileSystem localFileSystem, ILogger> CopyFile(string source, string destination); Unit EmptyFolder(string folder); - Task ReadAllText(string path); Task ReadAllLines(string path); Task GetHash(string path); string GetCustomOrDefaultFile(string folder, string file); diff --git a/ErsatzTV.Core/Metadata/LocalFileSystem.cs b/ErsatzTV.Core/Metadata/LocalFileSystem.cs index d57d239c5..eeeafdbfc 100644 --- a/ErsatzTV.Core/Metadata/LocalFileSystem.cs +++ b/ErsatzTV.Core/Metadata/LocalFileSystem.cs @@ -184,7 +184,6 @@ public class LocalFileSystem(IClient client, ILogger logger) : return Unit.Default; } - public Task ReadAllText(string path) => File.ReadAllTextAsync(path); public Task ReadAllLines(string path) => File.ReadAllLinesAsync(path); [SuppressMessage("Security", "CA5351:Do Not Use Broken Cryptographic Algorithms")] diff --git a/ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs b/ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs index f17a67efd..da00dd699 100644 --- a/ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs +++ b/ErsatzTV.Infrastructure/FFmpeg/MpegTsScriptService.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.IO.Abstractions; using System.Runtime.InteropServices; using CliWrap; using ErsatzTV.Core; @@ -15,6 +16,7 @@ using YamlDotNet.Serialization.NamingConventions; namespace ErsatzTV.Infrastructure.FFmpeg; public class MpegTsScriptService( + IFileSystem fileSystem, ILocalFileSystem localFileSystem, ITempFilePool tempFilePool, ILogger logger) : IMpegTsScriptService @@ -28,7 +30,7 @@ public class MpegTsScriptService( string definition = Path.Combine(folder, "mpegts.yml"); if (!Scripts.ContainsKey(folder) && localFileSystem.FileExists(definition)) { - Option maybeScript = FromYaml(await localFileSystem.ReadAllText(definition)); + Option maybeScript = FromYaml(await fileSystem.File.ReadAllTextAsync(definition)); foreach (var script in maybeScript) { script.Id = Path.GetFileName(folder); @@ -94,7 +96,7 @@ public class MpegTsScriptService( string channelName, string ffmpegPath) { - string script = await localFileSystem.ReadAllText(fileName); + string script = await fileSystem.File.ReadAllTextAsync(fileName); try { var data = new Dictionary diff --git a/ErsatzTV.Infrastructure/Streaming/Graphics/GraphicsElementLoader.cs b/ErsatzTV.Infrastructure/Streaming/Graphics/GraphicsElementLoader.cs index a82585294..2a1b57167 100644 --- a/ErsatzTV.Infrastructure/Streaming/Graphics/GraphicsElementLoader.cs +++ b/ErsatzTV.Infrastructure/Streaming/Graphics/GraphicsElementLoader.cs @@ -1,3 +1,4 @@ +using System.IO.Abstractions; using System.Text; using System.Text.RegularExpressions; using ErsatzTV.Core.Domain; @@ -18,6 +19,7 @@ namespace ErsatzTV.Infrastructure.Streaming.Graphics; public partial class GraphicsElementLoader( TemplateFunctions templateFunctions, + IFileSystem fileSystem, ILocalFileSystem localFileSystem, ITemplateDataRepository templateDataRepository, ILogger logger) @@ -147,7 +149,7 @@ public partial class GraphicsElementLoader( { try { - string yaml = await localFileSystem.ReadAllText(fileName); + string yaml = await fileSystem.File.ReadAllTextAsync(fileName, cancellationToken); var template = Template.Parse(yaml); var builder = new StringBuilder(); @@ -257,7 +259,7 @@ public partial class GraphicsElementLoader( private async Task> GetTemplatedYaml(string fileName, Dictionary variables) { - string yaml = await localFileSystem.ReadAllText(fileName); + string yaml = await fileSystem.File.ReadAllTextAsync(fileName); try { var scriptObject = new ScriptObject(); diff --git a/ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs b/ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs index c6a216816..2b9a706ff 100644 --- a/ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs +++ b/ErsatzTV.Scanner.Tests/Core/Fakes/FakeLocalFileSystem.cs @@ -58,7 +58,6 @@ public class FakeLocalFileSystem : ILocalFileSystem Task.FromResult(Right(Unit.Default)); public Unit EmptyFolder(string folder) => Unit.Default; - public Task ReadAllText(string path) => throw new NotImplementedException(); public Task ReadAllLines(string path) => throw new NotImplementedException(); public Task GetHash(string path) => throw new NotImplementedException(); diff --git a/ErsatzTV.Scanner/Program.cs b/ErsatzTV.Scanner/Program.cs index febbb37c1..478b83173 100644 --- a/ErsatzTV.Scanner/Program.cs +++ b/ErsatzTV.Scanner/Program.cs @@ -1,3 +1,4 @@ +using System.IO.Abstractions; using Bugsnag; using Bugsnag.Payload; using Dapper; @@ -47,6 +48,7 @@ using Microsoft.IO; using Serilog; using Serilog.Events; using Serilog.Formatting.Compact; +using Testably.Abstractions; using Exception = System.Exception; using IConfiguration = Bugsnag.IConfiguration; @@ -252,6 +254,8 @@ public class Program services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddMediatR(config => config.RegisterServicesFromAssemblyContaining()); services.AddMemoryCache(); diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index ec20b6643..3544118a5 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.IO.Abstractions; using System.Reflection; using System.Runtime.InteropServices; using System.Text; @@ -99,6 +100,7 @@ using Refit; using Scalar.AspNetCore; using Serilog; using Serilog.Events; +using Testably.Abstractions; namespace ErsatzTV; @@ -692,6 +694,8 @@ public class Startup { services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // TODO: does this need to be singleton?