File: Text\CompositeTextTests.cs
Web Access
Project: src\src\Compilers\Core\CodeAnalysisTest\Microsoft.CodeAnalysis.UnitTests.csproj (Microsoft.CodeAnalysis.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Xunit;
 
namespace Microsoft.CodeAnalysis.UnitTests.Text;
 
public sealed class CompositeTextTests
{
    [Theory]
    [InlineData("abcdefghijkl")]
    [InlineData(["\r\r\r\r\r\r\r\r\r\r\r\r"])]
    [InlineData(["\n\n\n\n\n\n\n\n\n\n\n\n"])]
    [InlineData(["\r\n\r\n\r\n\r\n\r\n\r\n"])]
    [InlineData(["\n\r\n\r\n\r\n\r\n\r\n\r"])]
    [InlineData(["a\r\nb\r\nc\r\nd\r\n"])]
    [InlineData(["\ra\n\rb\n\rc\n\rd\n"])]
    [InlineData(["\na\r\nb\r\nc\r\nd\r"])]
    [InlineData(["ab\r\ncd\r\nef\r\n"])]
    [InlineData(["ab\r\r\ncd\r\r\nef"])]
    [InlineData(["ab\n\n\rcd\n\n\ref"])]
    [InlineData(["ab\u0085cdef\u2028ijkl\u2029op"])]
    [InlineData(["\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029"])]
    public void CompositeTextLinesEqualSourceTextLinesPermutations(string contents)
    {
        // Please try to limit the inputs to this method to around 12 chars or less, as much longer than that
        // will blow up the number of potential permutations.
        foreach (var (sourceText, compositeText) in CreateSourceAndCompositeTexts(contents))
        {
            var sourceLinesText = GetLinesTexts(sourceText.Lines);
            var compositeLinesText = GetLinesTexts(compositeText.Lines);
 
            Assert.True(sourceLinesText.SequenceEqual(compositeLinesText));
 
            for (var i = 0; i < sourceText.Length; i++)
            {
                Assert.Equal(sourceText.Lines.IndexOf(i), compositeText.Lines.IndexOf(i));
            }
        }
    }
 
    private static IEnumerable<string> GetLinesTexts(TextLineCollection textLines)
    {
        return textLines.Select(l => l.Text!.ToString(l.SpanIncludingLineBreak));
    }
 
    // Returns all possible permutations of contents into SourceText arrays of length between minSourceTextCount and maxSourceTextCount
    private static IEnumerable<(SourceText, CompositeText)> CreateSourceAndCompositeTexts(string contents, int minSourceTextCount = 2, int maxSourceTextCount = 4)
    {
        var sourceText = SourceText.From(contents);
 
        for (var sourceTextCount = minSourceTextCount; sourceTextCount <= Math.Min(maxSourceTextCount, contents.Length); sourceTextCount++)
        {
            foreach (var sourceTexts in CreateSourceTextPermutations(contents, sourceTextCount))
            {
                var sourceTextsBuilder = ArrayBuilder<SourceText>.GetInstance();
                sourceTextsBuilder.AddRange(sourceTexts);
 
                var compositeText = (CompositeText)CompositeText.ToSourceText(sourceTextsBuilder, sourceText, adjustSegments: false);
                yield return (sourceText, compositeText);
            }
        }
    }
 
    private static IEnumerable<SourceText[]> CreateSourceTextPermutations(string contents, int requestedSourceTextCount)
    {
        if (requestedSourceTextCount == 1)
        {
            yield return [SourceText.From(contents)];
        }
        else
        {
            var maximalSourceTextLength = (contents.Length - requestedSourceTextCount) + 1;
            for (int i = 1; i <= maximalSourceTextLength; i++)
            {
                var sourceText = SourceText.From(contents[..i]);
                foreach (var otherSourceTexts in CreateSourceTextPermutations(contents.Substring(i), requestedSourceTextCount - 1))
                {
                    yield return [sourceText, .. otherSourceTexts];
                }
            }
        }
    }
}