Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 9s
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 25s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m40s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m18s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Successful in 6m12s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m13s
probe742/combined-newest SECOND
Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be>
97 lines
3.7 KiB
C#
97 lines
3.7 KiB
C#
using System.IO.Abstractions;
|
|
using Testably.Abstractions.Testing;
|
|
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Infrastructure.Data;
|
|
using ErsatzTV.Infrastructure.Streaming.Graphics;
|
|
using ErsatzTV.Tests.Support;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NUnit.Framework;
|
|
using Shouldly;
|
|
using YamlDotNet.Serialization;
|
|
using YamlDotNet.Serialization.NamingConventions;
|
|
using ErsatzTV.Core.Graphics;
|
|
|
|
namespace ErsatzTV.Tests.Infrastructure;
|
|
|
|
[TestFixture]
|
|
public class GraphicsElementSeederTests
|
|
{
|
|
private InMemoryTvContext _db = null!;
|
|
private string _seededPath = null!;
|
|
|
|
[SetUp]
|
|
public async Task SetUp()
|
|
{
|
|
_db = await InMemoryTvContext.CreateAsync();
|
|
_seededPath = Path.Combine(FileSystemLayout.GraphicsElementsTextTemplatesFolder, "on-now-next.yml");
|
|
}
|
|
|
|
[TearDown]
|
|
public async Task TearDown() => await _db.DisposeAsync();
|
|
|
|
[Test]
|
|
public async Task Seeds_File_And_Marker_When_Absent()
|
|
{
|
|
var fs = new MockFileSystem();
|
|
await using TvContext context = _db.CreateContext();
|
|
|
|
await GraphicsElementSeeder.SeedOnNowNext(context, fs, NullLogger.Instance, CancellationToken.None);
|
|
|
|
fs.File.Exists(_seededPath).ShouldBeTrue();
|
|
fs.File.ReadAllText(_seededPath).ShouldContain("epg_entries: 2");
|
|
(await context.ConfigElements.AnyAsync(c => c.Key == ConfigElementKey.GraphicsOnNowNextSeeded.Key)).ShouldBeTrue();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Adopts_Existing_File_Untouched()
|
|
{
|
|
var fs = new MockFileSystem();
|
|
fs.Directory.CreateDirectory(FileSystemLayout.GraphicsElementsTextTemplatesFolder);
|
|
await fs.File.WriteAllTextAsync(_seededPath, "name: Operator Custom\nepg_entries: 2\n");
|
|
await using TvContext context = _db.CreateContext();
|
|
|
|
await GraphicsElementSeeder.SeedOnNowNext(context, fs, NullLogger.Instance, CancellationToken.None);
|
|
|
|
fs.File.ReadAllText(_seededPath).ShouldContain("Operator Custom");
|
|
}
|
|
|
|
[Test]
|
|
public async Task Does_Not_Resurrect_After_Delete()
|
|
{
|
|
var fs = new MockFileSystem();
|
|
await using TvContext context = _db.CreateContext();
|
|
|
|
await GraphicsElementSeeder.SeedOnNowNext(context, fs, NullLogger.Instance, CancellationToken.None);
|
|
fs.File.Delete(_seededPath);
|
|
await GraphicsElementSeeder.SeedOnNowNext(context, fs, NullLogger.Instance, CancellationToken.None);
|
|
|
|
fs.File.Exists(_seededPath).ShouldBeFalse();
|
|
}
|
|
|
|
// Guards the #570 render bugs: the seeded YAML must deserialize into a TextGraphicsElement whose
|
|
// base_style names a real style and whose every style sets a font_family — a null font_family
|
|
// crashes CustomFontMapper before its default-font fallback, so the overlay silently never renders.
|
|
[Test]
|
|
public async Task Seeded_Element_Deserializes_With_Resolvable_BaseStyle_And_Font_Families()
|
|
{
|
|
var fs = new MockFileSystem();
|
|
await using TvContext context = _db.CreateContext();
|
|
await GraphicsElementSeeder.SeedOnNowNext(context, fs, NullLogger.Instance, CancellationToken.None);
|
|
|
|
string yaml = await fs.File.ReadAllTextAsync(_seededPath);
|
|
IDeserializer deserializer = new DeserializerBuilder()
|
|
.WithNamingConvention(CamelCaseNamingConvention.Instance)
|
|
.IgnoreUnmatchedProperties()
|
|
.Build();
|
|
|
|
var element = deserializer.Deserialize<TextGraphicsElement>(yaml);
|
|
|
|
element.ShouldNotBeNull();
|
|
element.Styles.ShouldNotBeEmpty();
|
|
element.Styles.Select(s => s.Name).ShouldContain(element.BaseStyle);
|
|
element.Styles.ShouldAllBe(s => !string.IsNullOrWhiteSpace(s.FontFamily));
|
|
}
|
|
}
|