diff --git a/src/OrchardCore/OrchardCore.DisplayManagement/Title/PageTitleBuilder.cs b/src/OrchardCore/OrchardCore.DisplayManagement/Title/PageTitleBuilder.cs index f1654b978cd..ebad663676b 100644 --- a/src/OrchardCore/OrchardCore.DisplayManagement/Title/PageTitleBuilder.cs +++ b/src/OrchardCore/OrchardCore.DisplayManagement/Title/PageTitleBuilder.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Microsoft.AspNetCore.Html; using OrchardCore.DisplayManagement.Zones; @@ -9,7 +10,7 @@ public class PageTitleBuilder : IPageTitleBuilder private readonly static HtmlString _defaultTitleSeparator = new(" - "); private readonly List _titleParts; - private IHtmlContent _title; + private HtmlContentBuilder _title; private IHtmlContent _fixedTitle; public PageTitleBuilder() @@ -48,7 +49,7 @@ public IHtmlContent GenerateTitle(IHtmlContent separator) return _fixedTitle; } - if (_title != null) + if (_title is { Count: > 0 }) { return _title; } @@ -57,13 +58,14 @@ public IHtmlContent GenerateTitle(IHtmlContent separator) _titleParts.Sort(FlatPositionComparer.Instance); - var htmlContentBuilder = new HtmlContentBuilder(); - if (_titleParts.Count == 0) { return HtmlString.Empty; } + // _titleParts.Count * 2 because we add a separator for each entry + var htmlContentBuilder = new HtmlContentBuilder(_titleParts.Count * 2); + for (var i = 0; i < _titleParts.Count; i++) { htmlContentBuilder.AppendHtml(_titleParts[i].Value); @@ -82,6 +84,7 @@ public IHtmlContent GenerateTitle(IHtmlContent separator) public void Clear() { _fixedTitle = null; + _title = null; _titleParts.Clear(); } } diff --git a/test/OrchardCore.Tests/DisplayManagement/Title/PageTitleBuilderTests.cs b/test/OrchardCore.Tests/DisplayManagement/Title/PageTitleBuilderTests.cs new file mode 100644 index 00000000000..6ec26ae27b8 --- /dev/null +++ b/test/OrchardCore.Tests/DisplayManagement/Title/PageTitleBuilderTests.cs @@ -0,0 +1,149 @@ +using Cysharp.Text; + +namespace OrchardCore.DisplayManagement.Title +{ + public class PageTitleBuilderTests + { + private const string Separator = " - "; + private const string SimpleTitle = "I'm a title"; + private const string FirstPartTitle = "first part"; + private const string SecondPartTitle = "second part"; + + private readonly IServiceProvider _serviceProvider; + + public PageTitleBuilderTests() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + [Fact] + public void GenerateTitleEmpty() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + + // Act & Assert + Assert.Equal(string.Empty, ToString(pageTitleBuilder.GenerateTitle())); + } + + [Fact] + public void FixedTitleSet() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.SetFixedTitle(new HtmlString(SimpleTitle)); + + // Act & Assert + Assert.Equal(SimpleTitle, ToString(pageTitleBuilder.GenerateTitle())); + } + + [Fact] + public void FixedTitleClearAndCheck() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.SetFixedTitle(new HtmlString(SimpleTitle)); + pageTitleBuilder.Clear(); + + // Act & Assert + Assert.Equal(string.Empty, ToString(pageTitleBuilder.GenerateTitle())); + } + + [Fact] + public void FixedTitleAddSegment() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.SetFixedTitle(new HtmlString(SimpleTitle)); + + // Act & Assert + pageTitleBuilder.AddSegment(new HtmlString("you don't see me")); + Assert.Equal(SimpleTitle, ToString(pageTitleBuilder.GenerateTitle())); + } + + [Fact] + public void TitleAddSegment() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.Clear(); + + // Act & Assert + pageTitleBuilder.AddSegment(new HtmlString(SimpleTitle), "after"); + Assert.Equal(SimpleTitle, ToString(pageTitleBuilder.GenerateTitle())); + } + + [Fact] + public void TitleMultiAddSegment() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.Clear(); + + // Act & Assert + pageTitleBuilder.AddSegment(new HtmlString(FirstPartTitle), "after"); + Assert.Equal(FirstPartTitle, ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + pageTitleBuilder.AddSegment(new HtmlString(SecondPartTitle), "after"); + Assert.Equal($"{FirstPartTitle}{Separator}{SecondPartTitle}", ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + } + + [Fact] + public void TitleAddAndClear() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.Clear(); + + // Act & Assert + pageTitleBuilder.AddSegment(new HtmlString(FirstPartTitle), "after"); + Assert.Equal(FirstPartTitle, ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + pageTitleBuilder.Clear(); + Assert.Equal(string.Empty, ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + } + + [Fact] + public void TitleMultiGenerateTitle() + { + // Arrange + var pageTitleBuilder = _serviceProvider.GetService(); + pageTitleBuilder.Clear(); + + // Act + pageTitleBuilder.AddSegment(new HtmlString(FirstPartTitle), "after"); + + // Assert + Assert.Equal(FirstPartTitle, ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + Assert.Equal(FirstPartTitle, ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + } + + [Fact] + public void TitleAddSegments() + { + // Arrange + var pageTitleBuilder = (PageTitleBuilder)_serviceProvider.GetService(); + pageTitleBuilder.Clear(); + + var elements = new IHtmlContent[] + { + new HtmlString(FirstPartTitle), + new HtmlString(SecondPartTitle) + }; + + pageTitleBuilder.AddSegments(elements, "after"); + + // Act & Assert + Assert.Equal($"{FirstPartTitle}{Separator}{SecondPartTitle}", ToString(pageTitleBuilder.GenerateTitle(new HtmlString(Separator)))); + } + + private static string ToString(IHtmlContent content) + { + using var writer = new ZStringWriter(); + content.WriteTo(writer, HtmlEncoder.Default); + + return writer.ToString(); + } + } +}