/* * Copyright (c) 2026 James Maes * SPDX-License-Identifier: MIT */ using MarkdownViewr.Windows.Core.Documents; namespace MarkdownViewr.Windows.Core.Tests; /// Proves literal nested folding and original-to-native selection offsets without mutating document data. public sealed class DocumentSourceTextTests { /// Setext and fenced pseudo-headings retain correct independent body boundaries across native line endings. [Theory] [InlineData("\n")] [InlineData("\r\n")] [InlineData("\r")] public void SetCollapsed_NestedSections_PreservesLiteralSyntaxAndChoices(string newline) { string original = string.Join(newline, "😀 Intro", "", "Parent", "======", "Parent body", "", "## Child", "Child body", "```md", "# Fake", "```", "", "> ## Peer", "> Peer body", "", "# Last", "Tail"); var source = new DocumentSourceText(original, new DocumentOutline(original)); Assert.Equal(original.ReplaceLineEndings("\r"), source.Text); Assert.Equal(4, source.Headings.Count); Assert.True(source.SetCollapsed([1])); Assert.Contains("Parent body", source.Text, StringComparison.Ordinal); Assert.Contains("## Child\r⋯\r> ## Peer", source.Text, StringComparison.Ordinal); Assert.DoesNotContain("# Fake", source.Text, StringComparison.Ordinal); Assert.Null(source.GetDisplayRange(original.IndexOf("Child body", StringComparison.Ordinal), 5)); Assert.True(source.SetCollapsed([0, 1])); Assert.Contains("Parent\r======\r⋯\r# Last", source.Text, StringComparison.Ordinal); Assert.DoesNotContain("Child", source.Text, StringComparison.Ordinal); Assert.Equal(new[] { 0, 3 }, source.Headings.Select(heading => heading.Index)); Assert.True(source.SetCollapsed([1])); Assert.Contains("> ## Peer", source.Text, StringComparison.Ordinal); Assert.DoesNotContain("Child body", source.Text, StringComparison.Ordinal); Assert.False(source.SetCollapsed([1, 1])); Assert.True(source.SetCollapsed([])); Assert.Equal(original.ReplaceLineEndings("\r"), source.Text); } /// Selections and heading anchors remain exact after omitted bodies and UTF-16/native newline conversion. [Fact] public void GetDisplayRange_MixedNewlinesAndFold_MapsLiteralOccurrence() { const string Original = "😀 Intro\r\n# One\nHidden\n# Two\rVisible\r\n# Three"; var source = new DocumentSourceText(Original, new DocumentOutline(Original)); source.SetCollapsed([0]); int start = Original.IndexOf("Visible", StringComparison.Ordinal); (int Start, int Length) range = source.GetDisplayRange(start, "Visible".Length)!.Value; Assert.Equal("Visible", source.Text.Substring(range.Start, range.Length)); Assert.Equal(source.Text.IndexOf("# Two", StringComparison.Ordinal), source.Headings.Single(heading => heading.Index == 1).Start); Assert.Equal("# Two", source.Text[source.Headings[1].Start..source.Headings[1].End]); Assert.Null(source.GetDisplayRange(Original.IndexOf("Hidden", StringComparison.Ordinal) - 1, 8)); Assert.Equal((source.Text.Length, 0), source.GetDisplayRange(Original.Length, 0)); Assert.Equal((0, 2), source.GetDisplayRange(0, 2)); Assert.Throws(() => source.GetDisplayRange(-1, 0)); Assert.Throws(() => source.GetDisplayRange(0, -1)); Assert.Throws(() => source.GetDisplayRange(Original.Length + 1, 0)); Assert.Throws(() => source.GetDisplayRange(0, Original.Length + 1)); } /// Empty bodies, ordinary content and invalid collapse indices cannot hide another section or manufacture headings. [Theory] [InlineData("")] [InlineData("ordinary literal \n")] [InlineData("# H\r\n**text**\r\n")] [InlineData("One\rTwo\nThree\r\n終 😀\r")] public void GetCopyText_OriginalLineEndings_RetainsExactSource(string original) { var source = new DocumentSourceText(original, new DocumentOutline(original)); Assert.Equal(original, source.GetCopyText(0, source.Text.Length)); Assert.Equal("", source.GetCopyText(source.Text.Length, 0)); Assert.Throws(() => source.GetCopyText(-1, 0)); Assert.Throws(() => source.GetCopyText(0, -1)); Assert.Throws(() => source.GetCopyText(source.Text.Length + 1, 0)); Assert.Throws(() => source.GetCopyText(0, source.Text.Length + 1)); } /// Selection boundaries include the LF only when the native CR is selected, preserving exact substrings. [Fact] public void GetCopyText_PartialNewlineAndUnicode_MapsActualSelection() { const string Original = "😀 A\r\nB\nC\rD\r\n終"; var source = new DocumentSourceText(Original, new DocumentOutline(Original)); Assert.Equal("😀", source.GetCopyText(0, 2)); Assert.Equal("\r\n", source.GetCopyText(4, 1)); Assert.Equal("B\nC\rD\r\n", source.GetCopyText(5, 6)); Assert.Equal("終", source.GetCopyText(source.Text.Length - 1, 1)); Assert.Equal("", source.GetCopyText(5, 0)); } /// Folds copy only visible original chunks and a literal ellipsis; reopening restores the exact original. [Fact] public void GetCopyText_MergedAndIndependentFolds_OmitsHiddenBodies() { const string Original = "# First\r\nHidden\r\n## Nested\nMore\n# Second\nKeep 😀\r\n# Last\rTail"; var source = new DocumentSourceText(Original, new DocumentOutline(Original)); source.SetCollapsed([0, 1]); Assert.Equal("# First\r\n⋯\r# Second\nKeep 😀\r\n# Last\rTail", source.GetCopyText(0, source.Text.Length)); int visible = source.Text.IndexOf("Keep", StringComparison.Ordinal); Assert.Equal("Keep 😀\r\n", source.GetCopyText(visible, 8)); source.SetCollapsed([1, 2]); Assert.Equal("# First\r\nHidden\r\n## Nested\n⋯\r# Second\n⋯\r# Last\rTail", source.GetCopyText(0, source.Text.Length)); source.SetCollapsed([]); Assert.Equal(Original, source.GetCopyText(0, source.Text.Length)); } }