зеркало из https://github.com/dotnet/razor.git
Change RazorSyntaxTree.Diagnostics from an IReadOnlyList<RazorDiagnostic> to an ImmutableArray<RazorDiagnostic> (#10797)
This pull request represents several changes with the ultimate goal of exposing `RazorSyntaxTree.Diagnostics` as an `ImmutableArray<RazorDiagnostic>` rather than an `IReadOnlyList<RazorDiagnostic>`: - Clean up `RazorSyntaxTree` and get rid of `DefaultRazorSyntaxTree`. - Add `(Drain)ToImmutableOrdered*` methods to `PooledArrayBuilder<T>`. Note that this change also includes a refactoring to the various unit tests for ordering to share test data that I've isolated to a single commit. - Clean up and improve `ErrorSink` to no longer greedily create a new `List<T>` before any errors are encountered. - Clean up `ParserContext` and make it used pooled collections. - Use pooled collections when computing and caching the result of `RazorSyntaxTree.Diagnostics`.
This commit is contained in:
Коммит
90b1855f86
|
@ -52,7 +52,7 @@ public class TagHelperParseTreeRewriterTest : TagHelperRewritingTestBase
|
|||
IEnumerable<KeyValuePair<string, string>> expectedPairs)
|
||||
{
|
||||
// Arrange
|
||||
var errorSink = new ErrorSink();
|
||||
using var errorSink = new ErrorSink();
|
||||
var parseResult = ParseDocument(documentContent);
|
||||
var document = parseResult.Root;
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class TagHelperParseTreeRewriterTest : TagHelperRewritingTestBase
|
|||
var rootMarkup = Assert.IsType<MarkupBlockSyntax>(rootBlock.Document);
|
||||
var childBlock = Assert.Single(rootMarkup.Children);
|
||||
var element = Assert.IsType<MarkupElementSyntax>(childBlock);
|
||||
Assert.Empty(errorSink.Errors);
|
||||
Assert.Empty(errorSink.GetErrorsAndClear());
|
||||
|
||||
// Act
|
||||
var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.StartTag);
|
||||
|
|
|
@ -32,7 +32,7 @@ public class WhiteSpaceRewriterTest() : ParserTestBase(layer: TestProject.Layer.
|
|||
var rewritten = rewriter.Visit(parsed.Root);
|
||||
|
||||
// Assert
|
||||
var rewrittenTree = RazorSyntaxTree.Create(rewritten, parsed.Source, parsed.Diagnostics, parsed.Options);
|
||||
var rewrittenTree = new RazorSyntaxTree(rewritten, parsed.Source, parsed.Diagnostics, parsed.Options);
|
||||
BaselineTest(rewrittenTree);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -604,7 +604,7 @@ public class DefaultRazorTagHelperContextDiscoveryPhaseTest : RazorProjectEngine
|
|||
var expectedRewritingError = RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(
|
||||
new SourceSpan(new SourceLocation((Environment.NewLine.Length * 2) + 30, 2, 1), contentLength: 4), "form");
|
||||
|
||||
var erroredOriginalTree = RazorSyntaxTree.Create(originalTree.Root, originalTree.Source, [initialError], originalTree.Options);
|
||||
var erroredOriginalTree = new RazorSyntaxTree(originalTree.Root, originalTree.Source, [initialError], originalTree.Options);
|
||||
codeDocument.SetSyntaxTree(erroredOriginalTree);
|
||||
|
||||
// Act
|
||||
|
@ -615,7 +615,7 @@ public class DefaultRazorTagHelperContextDiscoveryPhaseTest : RazorProjectEngine
|
|||
var outputTree = codeDocument.GetSyntaxTree();
|
||||
Assert.Empty(originalTree.Diagnostics);
|
||||
Assert.NotSame(erroredOriginalTree, outputTree);
|
||||
Assert.Equal([initialError, expectedRewritingError], outputTree.Diagnostics);
|
||||
Assert.Equal<RazorDiagnostic>([initialError, expectedRewritingError], outputTree.Diagnostics);
|
||||
}
|
||||
|
||||
private static string AssemblyA => "TestAssembly";
|
||||
|
|
|
@ -215,13 +215,15 @@ public class CSharpCodeParserTest
|
|||
// Arrange
|
||||
var source = TestRazorSourceDocument.Create();
|
||||
var options = RazorParserOptions.CreateDefault();
|
||||
var context = new ParserContext(source, options);
|
||||
using var context = new ParserContext(source, options);
|
||||
|
||||
// Act & Assert (Does not throw)
|
||||
var directiveDescriptors = new[] {
|
||||
var directiveDescriptors = new[]
|
||||
{
|
||||
DirectiveDescriptor.CreateDirective("test", DirectiveKind.SingleLine),
|
||||
DirectiveDescriptor.CreateDirective("test", DirectiveKind.SingleLine),
|
||||
};
|
||||
|
||||
_ = new CSharpCodeParser(directiveDescriptors, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class HtmlMarkupParserTests
|
|||
public void AcceptAllButLastDoubleHypens_ReturnsTheOnlyDoubleHyphenToken()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("-->");
|
||||
using var sut = CreateTestParserForContent("-->");
|
||||
|
||||
// Act
|
||||
var token = sut.AcceptAllButLastDoubleHyphens();
|
||||
|
@ -68,7 +68,7 @@ public class HtmlMarkupParserTests
|
|||
public void AcceptAllButLastDoubleHypens_ReturnsTheDoubleHyphenTokenAfterAcceptingTheDash()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("--->");
|
||||
using var sut = CreateTestParserForContent("--->");
|
||||
|
||||
// Act
|
||||
var token = sut.AcceptAllButLastDoubleHyphens();
|
||||
|
@ -83,7 +83,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsTrueForEmptyCommentTag()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!---->");
|
||||
using var sut = CreateTestParserForContent("<!---->");
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(sut.IsHtmlCommentAhead());
|
||||
|
@ -93,7 +93,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTag()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- Some comment content in here -->");
|
||||
using var sut = CreateTestParserForContent("<!-- Some comment content in here -->");
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(sut.IsHtmlCommentAhead());
|
||||
|
@ -103,7 +103,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTagWithExtraDashesAtClosingTag()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- Some comment content in here ----->");
|
||||
using var sut = CreateTestParserForContent("<!-- Some comment content in here ----->");
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(sut.IsHtmlCommentAhead());
|
||||
|
@ -113,7 +113,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsFalseForContentWithBadEndingAndExtraDash()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- Some comment content in here <!--->");
|
||||
using var sut = CreateTestParserForContent("<!-- Some comment content in here <!--->");
|
||||
|
||||
// Act & Assert
|
||||
Assert.False(sut.IsHtmlCommentAhead());
|
||||
|
@ -123,7 +123,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsTrueForValidCommentTagWithExtraInfoAfter()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- comment --> the first part is a valid comment without the Open angle and bang tokens");
|
||||
using var sut = CreateTestParserForContent("<!-- comment --> the first part is a valid comment without the Open angle and bang tokens");
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(sut.IsHtmlCommentAhead());
|
||||
|
@ -133,7 +133,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsFalseForNotClosedComment()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- not closed comment");
|
||||
using var sut = CreateTestParserForContent("<!-- not closed comment");
|
||||
|
||||
// Act & Assert
|
||||
Assert.False(sut.IsHtmlCommentAhead());
|
||||
|
@ -143,7 +143,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsFalseForCommentWithoutLastClosingAngle()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- not closed comment--");
|
||||
using var sut = CreateTestParserForContent("<!-- not closed comment--");
|
||||
|
||||
// Act & Assert
|
||||
Assert.False(sut.IsHtmlCommentAhead());
|
||||
|
@ -153,7 +153,7 @@ public class HtmlMarkupParserTests
|
|||
public void IsHtmlCommentAhead_ReturnsTrueForCommentWithCodeInside()
|
||||
{
|
||||
// Arrange
|
||||
var sut = CreateTestParserForContent("<!-- not closed @DateTime.Now comment-->");
|
||||
using var sut = CreateTestParserForContent("<!-- not closed @DateTime.Now comment-->");
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(sut.IsHtmlCommentAhead());
|
||||
|
@ -195,8 +195,19 @@ public class HtmlMarkupParserTests
|
|||
Assert.False(HtmlMarkupParser.IsCommentContentEndingInvalid(sequence));
|
||||
}
|
||||
|
||||
private class TestHtmlMarkupParser : HtmlMarkupParser
|
||||
private class TestHtmlMarkupParser : HtmlMarkupParser, IDisposable
|
||||
{
|
||||
public TestHtmlMarkupParser(ParserContext context)
|
||||
: base(context)
|
||||
{
|
||||
EnsureCurrent();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
public new SyntaxToken PreviousToken
|
||||
{
|
||||
get => base.PreviousToken;
|
||||
|
@ -207,11 +218,6 @@ public class HtmlMarkupParserTests
|
|||
return base.IsHtmlCommentAhead();
|
||||
}
|
||||
|
||||
public TestHtmlMarkupParser(ParserContext context) : base(context)
|
||||
{
|
||||
EnsureCurrent();
|
||||
}
|
||||
|
||||
public new SyntaxToken AcceptAllButLastDoubleHyphens()
|
||||
{
|
||||
return base.AcceptAllButLastDoubleHyphens();
|
||||
|
|
|
@ -52,7 +52,7 @@ public class TagHelperParseTreeRewriterTest : TagHelperRewritingTestBase
|
|||
IEnumerable<KeyValuePair<string, string>> expectedPairs)
|
||||
{
|
||||
// Arrange
|
||||
var errorSink = new ErrorSink();
|
||||
using var errorSink = new ErrorSink();
|
||||
var parseResult = ParseDocument(documentContent);
|
||||
var document = parseResult.Root;
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class TagHelperParseTreeRewriterTest : TagHelperRewritingTestBase
|
|||
var rootMarkup = Assert.IsType<MarkupBlockSyntax>(rootBlock.Document);
|
||||
var childBlock = Assert.Single(rootMarkup.Children);
|
||||
var element = Assert.IsType<MarkupElementSyntax>(childBlock);
|
||||
Assert.Empty(errorSink.Errors);
|
||||
Assert.Empty(errorSink.GetErrorsAndClear());
|
||||
|
||||
// Act
|
||||
var pairs = TagHelperParseTreeRewriter.Rewriter.GetAttributeNameValuePairs(element.StartTag);
|
||||
|
|
|
@ -63,7 +63,7 @@ public class TokenizerLookaheadTest : HtmlTokenizerTestBase
|
|||
public void LookaheadUntil_PassesThePreviousTokensInTheSameOrder()
|
||||
{
|
||||
// Arrange
|
||||
var tokenizer = CreateContentTokenizer("asdf--fvd--<");
|
||||
using var tokenizer = CreateContentTokenizer("asdf--fvd--<");
|
||||
|
||||
// Act
|
||||
var i = 3;
|
||||
|
@ -89,7 +89,7 @@ public class TokenizerLookaheadTest : HtmlTokenizerTestBase
|
|||
public void LookaheadUntil_ReturnsFalseAfterIteratingOverAllTokensIfConditionIsNotMet()
|
||||
{
|
||||
// Arrange
|
||||
var tokenizer = CreateContentTokenizer("asdf--fvd");
|
||||
using var tokenizer = CreateContentTokenizer("asdf--fvd");
|
||||
|
||||
// Act
|
||||
var tokens = new Stack<SyntaxToken>();
|
||||
|
@ -111,7 +111,7 @@ public class TokenizerLookaheadTest : HtmlTokenizerTestBase
|
|||
public void LookaheadUntil_ReturnsTrueAndBreaksIteration()
|
||||
{
|
||||
// Arrange
|
||||
var tokenizer = CreateContentTokenizer("asdf--fvd");
|
||||
using var tokenizer = CreateContentTokenizer("asdf--fvd");
|
||||
|
||||
// Act
|
||||
var tokens = new Stack<SyntaxToken>();
|
||||
|
@ -134,8 +134,7 @@ public class TokenizerLookaheadTest : HtmlTokenizerTestBase
|
|||
var options = RazorParserOptions.CreateDefault();
|
||||
var context = new ParserContext(source, options);
|
||||
|
||||
var tokenizer = new TestTokenizerBackedParser(HtmlLanguageCharacteristics.Instance, context);
|
||||
return tokenizer;
|
||||
return new TestTokenizerBackedParser(HtmlLanguageCharacteristics.Instance, context);
|
||||
}
|
||||
|
||||
private static void AssertTokenEqual(SyntaxToken expected, SyntaxToken actual)
|
||||
|
@ -204,12 +203,18 @@ public class TokenizerLookaheadTest : HtmlTokenizerTestBase
|
|||
}
|
||||
}
|
||||
|
||||
private class TestTokenizerBackedParser : TokenizerBackedParser<HtmlTokenizer>
|
||||
private class TestTokenizerBackedParser : TokenizerBackedParser<HtmlTokenizer>, IDisposable
|
||||
{
|
||||
internal TestTokenizerBackedParser(LanguageCharacteristics<HtmlTokenizer> language, ParserContext context) : base(language, context)
|
||||
internal TestTokenizerBackedParser(LanguageCharacteristics<HtmlTokenizer> language, ParserContext context)
|
||||
: base(language, context)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
internal new bool LookaheadUntil(Func<SyntaxToken, IEnumerable<SyntaxToken>, bool> condition)
|
||||
{
|
||||
return base.LookaheadUntil(condition);
|
||||
|
|
|
@ -32,7 +32,7 @@ public class WhiteSpaceRewriterTest() : ParserTestBase(layer: TestProject.Layer.
|
|||
var rewritten = rewriter.Visit(parsed.Root);
|
||||
|
||||
// Assert
|
||||
var rewrittenTree = RazorSyntaxTree.Create(rewritten, parsed.Source, parsed.Diagnostics, parsed.Options);
|
||||
var rewrittenTree = new RazorSyntaxTree(rewritten, parsed.Source, parsed.Diagnostics, parsed.Options);
|
||||
BaselineTest(rewrittenTree);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Razor.Language.Extensions;
|
||||
using Microsoft.AspNetCore.Razor.Language.Syntax;
|
||||
|
||||
|
@ -26,23 +24,19 @@ internal class DefaultDirectiveSyntaxTreePass : RazorEngineFeatureBase, IRazorSy
|
|||
return sectionVerifier.Verify();
|
||||
}
|
||||
|
||||
private class NestedSectionVerifier : SyntaxRewriter
|
||||
private sealed class NestedSectionVerifier(RazorSyntaxTree syntaxTree) : SyntaxRewriter
|
||||
{
|
||||
private int _nestedLevel;
|
||||
private readonly RazorSyntaxTree _syntaxTree;
|
||||
private readonly List<RazorDiagnostic> _diagnostics;
|
||||
private readonly RazorSyntaxTree _syntaxTree = syntaxTree;
|
||||
|
||||
public NestedSectionVerifier(RazorSyntaxTree syntaxTree)
|
||||
{
|
||||
_syntaxTree = syntaxTree;
|
||||
_diagnostics = new List<RazorDiagnostic>(syntaxTree.Diagnostics);
|
||||
}
|
||||
private ImmutableArray<RazorDiagnostic>.Builder? _diagnostics;
|
||||
private int _nestedLevel;
|
||||
|
||||
public RazorSyntaxTree Verify()
|
||||
{
|
||||
var root = Visit(_syntaxTree.Root);
|
||||
var rewrittenTree = new DefaultRazorSyntaxTree(root, _syntaxTree.Source, _diagnostics, _syntaxTree.Options);
|
||||
return rewrittenTree;
|
||||
var diagnostics = _diagnostics?.DrainToImmutable() ?? _syntaxTree.Diagnostics;
|
||||
|
||||
return new RazorSyntaxTree(root, _syntaxTree.Source, diagnostics, _syntaxTree.Options);
|
||||
}
|
||||
|
||||
public override SyntaxNode Visit(SyntaxNode node)
|
||||
|
@ -55,6 +49,7 @@ internal class DefaultDirectiveSyntaxTreePass : RazorEngineFeatureBase, IRazorSy
|
|||
{
|
||||
// We're very close to reaching the stack limit. Let's not go any deeper.
|
||||
// It's okay to not show nested section errors in deeply nested cases instead of crashing.
|
||||
_diagnostics ??= _syntaxTree.Diagnostics.ToBuilder();
|
||||
_diagnostics.Add(RazorDiagnosticFactory.CreateRewriter_InsufficientStack());
|
||||
|
||||
return node;
|
||||
|
|
|
@ -130,18 +130,18 @@ internal class DefaultRazorIntermediateNodeLoweringPhase : RazorEnginePhaseBase,
|
|||
|
||||
// The document should contain all errors that currently exist in the system. This involves
|
||||
// adding the errors from the primary and imported syntax trees.
|
||||
for (var i = 0; i < syntaxTree.Diagnostics.Count; i++)
|
||||
foreach (var diagnostic in syntaxTree.Diagnostics)
|
||||
{
|
||||
document.Diagnostics.Add(syntaxTree.Diagnostics[i]);
|
||||
document.Diagnostics.Add(diagnostic);
|
||||
}
|
||||
|
||||
if (imports is { IsDefault: false } importsArray)
|
||||
{
|
||||
foreach (var import in importsArray)
|
||||
{
|
||||
for (var j = 0; j < import.Diagnostics.Count; j++)
|
||||
foreach (var diagnostic in import.Diagnostics)
|
||||
{
|
||||
document.Diagnostics.Add(import.Diagnostics[j]);
|
||||
document.Diagnostics.Add(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Language.Syntax;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language;
|
||||
|
||||
internal class DefaultRazorSyntaxTree : RazorSyntaxTree
|
||||
{
|
||||
private readonly IReadOnlyList<RazorDiagnostic> _diagnostics;
|
||||
private IReadOnlyList<RazorDiagnostic> _allDiagnostics;
|
||||
|
||||
public DefaultRazorSyntaxTree(
|
||||
SyntaxNode root,
|
||||
RazorSourceDocument source,
|
||||
IReadOnlyList<RazorDiagnostic> diagnostics,
|
||||
RazorParserOptions options)
|
||||
{
|
||||
Root = root;
|
||||
Source = source;
|
||||
_diagnostics = diagnostics;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public override IReadOnlyList<RazorDiagnostic> Diagnostics
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_allDiagnostics == null)
|
||||
{
|
||||
var allDiagnostics = new HashSet<RazorDiagnostic>();
|
||||
for (var i = 0; i < _diagnostics.Count; i++)
|
||||
{
|
||||
allDiagnostics.Add(_diagnostics[i]);
|
||||
}
|
||||
|
||||
var rootDiagnostics = Root.GetAllDiagnostics();
|
||||
for (var i = 0; i < rootDiagnostics.Count; i++)
|
||||
{
|
||||
allDiagnostics.Add(rootDiagnostics[i]);
|
||||
}
|
||||
|
||||
var allOrderedDiagnostics = allDiagnostics.OrderBy(diagnostic => diagnostic.Span.AbsoluteIndex);
|
||||
_allDiagnostics = allOrderedDiagnostics.ToArray();
|
||||
}
|
||||
|
||||
return _allDiagnostics;
|
||||
}
|
||||
}
|
||||
|
||||
public override RazorParserOptions Options { get; }
|
||||
|
||||
internal override SyntaxNode Root { get; }
|
||||
|
||||
public override RazorSourceDocument Source { get; }
|
||||
}
|
|
@ -27,7 +27,6 @@ internal class HtmlNodeOptimizationPass : RazorEngineFeatureBase, IRazorSyntaxTr
|
|||
var whitespaceRewriter = new WhitespaceRewriter();
|
||||
var rewritten = whitespaceRewriter.Visit(syntaxTree.Root);
|
||||
|
||||
var rewrittenSyntaxTree = RazorSyntaxTree.Create(rewritten, syntaxTree.Source, syntaxTree.Diagnostics, syntaxTree.Options);
|
||||
return rewrittenSyntaxTree;
|
||||
return new RazorSyntaxTree(rewritten, syntaxTree.Source, syntaxTree.Diagnostics, syntaxTree.Options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using static Microsoft.AspNetCore.Razor.Language.Syntax.GreenNodeExtensions;
|
||||
|
||||
using CSharpSyntaxFacts = Microsoft.CodeAnalysis.CSharp.SyntaxFacts;
|
||||
using CSharpSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
|
||||
|
@ -84,22 +85,15 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
private readonly ImmutableDictionary<string, Action<SyntaxListBuilder<RazorSyntaxNode>, CSharpTransitionSyntax>> _directiveParserMap;
|
||||
|
||||
public CSharpCodeParser(ParserContext context)
|
||||
: this(directives: Enumerable.Empty<DirectiveDescriptor>(), context: context)
|
||||
: this(directives: [], context)
|
||||
{
|
||||
}
|
||||
|
||||
public CSharpCodeParser(IEnumerable<DirectiveDescriptor> directives, ParserContext context)
|
||||
: base(context.ParseLeadingDirectives ? FirstDirectiveCSharpLanguageCharacteristics.Instance : CSharpLanguageCharacteristics.Instance, context)
|
||||
{
|
||||
if (directives == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directives));
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
ArgHelper.ThrowIfNull(directives);
|
||||
ArgHelper.ThrowIfNull(context);
|
||||
|
||||
var keywordsBuilder = ImmutableHashSet<string>.Empty.ToBuilder();
|
||||
var keywordParserMapBuilder = ImmutableDictionary<CSharpSyntaxKind, Action<SyntaxListBuilder<RazorSyntaxNode>, CSharpTransitionSyntax?>>.Empty.ToBuilder();
|
||||
|
@ -298,7 +292,7 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
{
|
||||
var diagnostic = RazorDiagnosticFactory.CreateParsing_HelperDirectiveNotAvailable(
|
||||
new SourceSpan(CurrentStart, CurrentToken.Content.Length));
|
||||
CurrentToken.SetDiagnostics(new[] { diagnostic });
|
||||
CurrentToken.SetDiagnostics([diagnostic]);
|
||||
Context.ErrorSink.OnError(diagnostic);
|
||||
}
|
||||
|
||||
|
@ -1213,14 +1207,13 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
{
|
||||
AssertDirective(keyword);
|
||||
|
||||
var savedErrorSink = Context.ErrorSink;
|
||||
var directiveErrorSink = new ErrorSink();
|
||||
RazorMetaCodeSyntax? keywordBlock = null;
|
||||
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
|
||||
{
|
||||
var directiveBuilder = pooledResult.Builder;
|
||||
Context.ErrorSink = directiveErrorSink;
|
||||
using var pooledResult = Pool.Allocate<RazorSyntaxNode>();
|
||||
var directiveBuilder = pooledResult.Builder;
|
||||
|
||||
using var directiveErrorSink = new ErrorSink();
|
||||
using (Context.PushNewErrorScope(directiveErrorSink))
|
||||
{
|
||||
string? directiveValue = null;
|
||||
SourceLocation? valueStartLocation = null;
|
||||
EnsureDirectiveIsAtStartOfLine();
|
||||
|
@ -1278,19 +1271,18 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
|
||||
chunkGenerator = chunkGeneratorFactory(
|
||||
directiveValue,
|
||||
directiveErrorSink.Errors.ToList(),
|
||||
[.. directiveErrorSink.GetErrorsAndClear()],
|
||||
valueStartLocation ?? CurrentStart);
|
||||
Context.ErrorSink = savedErrorSink;
|
||||
|
||||
// Finish the block and output the tokens
|
||||
CompleteBlock();
|
||||
SetAcceptedCharacters(AcceptedCharactersInternal.AnyExceptNewline);
|
||||
|
||||
directiveBuilder.Add(OutputTokensAsStatementLiteral());
|
||||
var directiveCodeBlock = SyntaxFactory.CSharpCodeBlock(directiveBuilder.ToList());
|
||||
|
||||
return SyntaxFactory.RazorDirectiveBody(keywordBlock, directiveCodeBlock);
|
||||
}
|
||||
|
||||
// Finish the block and output the tokens
|
||||
CompleteBlock();
|
||||
SetAcceptedCharacters(AcceptedCharactersInternal.AnyExceptNewline);
|
||||
|
||||
directiveBuilder.Add(OutputTokensAsStatementLiteral());
|
||||
var directiveCodeBlock = SyntaxFactory.CSharpCodeBlock(directiveBuilder.ToList());
|
||||
|
||||
return SyntaxFactory.RazorDirectiveBody(keywordBlock, directiveCodeBlock);
|
||||
}
|
||||
|
||||
private ParsedDirective ParseDirective(
|
||||
|
@ -1430,17 +1422,14 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
{
|
||||
AssertDirective(descriptor.Directive);
|
||||
|
||||
var directiveErrorSink = new ErrorSink();
|
||||
var savedErrorSink = Context.ErrorSink;
|
||||
Context.ErrorSink = directiveErrorSink;
|
||||
|
||||
using (var pooledResult = Pool.Allocate<RazorSyntaxNode>())
|
||||
{
|
||||
var directiveBuilder = pooledResult.Builder;
|
||||
RazorMetaCodeSyntax? keywordBlock = null;
|
||||
bool shouldCaptureWhitespaceToEndOfLine = false;
|
||||
|
||||
try
|
||||
using var directiveErrorSink = new ErrorSink();
|
||||
using (Context.PushNewErrorScope(directiveErrorSink))
|
||||
{
|
||||
EnsureDirectiveIsAtStartOfLine();
|
||||
var directiveStart = CurrentStart;
|
||||
|
@ -1742,7 +1731,6 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
Resources.ErrorComponent_Newline));
|
||||
}
|
||||
|
||||
|
||||
// This should contain the optional whitespace after the optional semicolon and the new line.
|
||||
// Output as Markup as we want intellisense here.
|
||||
chunkGenerator = SpanChunkGenerator.Null;
|
||||
|
@ -1811,10 +1799,6 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
break;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Context.ErrorSink = savedErrorSink;
|
||||
}
|
||||
|
||||
builder.Add(BuildDirective(SyntaxKind.Identifier));
|
||||
|
||||
|
@ -1836,7 +1820,9 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
|
||||
var directiveBody = SyntaxFactory.RazorDirectiveBody(keywordBlock, directiveCodeBlock);
|
||||
var directive = SyntaxFactory.RazorDirective(transition, directiveBody);
|
||||
directive = (RazorDirectiveSyntax)directive.SetDiagnostics(directiveErrorSink.Errors.ToArray());
|
||||
|
||||
var diagnostics = directiveErrorSink.GetErrorsAndClear();
|
||||
directive = directive.WithDiagnosticsGreen(diagnostics);
|
||||
directive = directive.WithDirectiveDescriptor(descriptor);
|
||||
return directive;
|
||||
}
|
||||
|
@ -2210,7 +2196,7 @@ internal class CSharpCodeParser : TokenizerBackedParser<CSharpTokenizer>
|
|||
if (At(CSharpSyntaxKind.ElseKeyword))
|
||||
{
|
||||
Accept(in whitespace);
|
||||
Assert(CSharpSyntaxKind.ElseKeyword);
|
||||
Assert(CSharpSyntaxKind.ElseKeyword);
|
||||
ParseElseClause(builder);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1,35 +1,52 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
|
||||
/// <summary>
|
||||
/// Used to manage <see cref="RazorDiagnostic"/>s encountered during the Razor parsing phase.
|
||||
/// Used to manage <see cref="RazorDiagnostic">RazorDiagnostics</see> encountered during the Razor parsing phase.
|
||||
/// </summary>
|
||||
internal class ErrorSink
|
||||
internal sealed class ErrorSink : IDisposable
|
||||
{
|
||||
private readonly List<RazorDiagnostic> _errors;
|
||||
private ImmutableArray<RazorDiagnostic>.Builder? _errors;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new instance of <see cref="ErrorSink"/>.
|
||||
/// </summary>
|
||||
public ErrorSink()
|
||||
public void Dispose()
|
||||
{
|
||||
_errors = new List<RazorDiagnostic>();
|
||||
var errors = _errors;
|
||||
|
||||
if (errors is not null)
|
||||
{
|
||||
ArrayBuilderPool<RazorDiagnostic>.Default.Return(errors);
|
||||
_errors = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="RazorDiagnostic"/>s collected.
|
||||
/// </summary>
|
||||
public IReadOnlyList<RazorDiagnostic> Errors => _errors;
|
||||
public ImmutableArray<RazorDiagnostic> GetErrorsAndClear()
|
||||
{
|
||||
var errors = _errors;
|
||||
if (errors is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var result = errors.DrainToImmutable();
|
||||
ArrayBuilderPool<RazorDiagnostic>.Default.Return(errors);
|
||||
_errors = null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the given <paramref name="error"/>.
|
||||
/// </summary>
|
||||
/// <param name="error">The <see cref="RazorDiagnostic"/> to track.</param>
|
||||
public void OnError(RazorDiagnostic error) => _errors.Add(error);
|
||||
public void OnError(RazorDiagnostic error)
|
||||
{
|
||||
var errors = _errors ??= ArrayBuilderPool<RazorDiagnostic>.Default.Get();
|
||||
errors.Add(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ internal class HtmlMarkupParser : TokenizerBackedParser<HtmlTokenizer>
|
|||
private static readonly char[] ValidAfterTypeAttributeNameCharacters = { ' ', '\t', '\r', '\n', '\f', '=' };
|
||||
private static readonly SyntaxToken[] nonAllowedHtmlCommentEnding = new[]
|
||||
{
|
||||
SyntaxFactory.Token(SyntaxKind.Text, "-"),
|
||||
SyntaxFactory.Token(SyntaxKind.Bang, "!"),
|
||||
SyntaxFactory.Token(SyntaxKind.OpenAngle, "<"),
|
||||
};
|
||||
SyntaxFactory.Token(SyntaxKind.Text, "-"),
|
||||
SyntaxFactory.Token(SyntaxKind.Bang, "!"),
|
||||
SyntaxFactory.Token(SyntaxKind.OpenAngle, "<"),
|
||||
};
|
||||
|
||||
private Stack<TagTracker> _tagTracker = new Stack<TagTracker>();
|
||||
|
||||
|
|
|
@ -3,12 +3,7 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
|
||||
internal abstract class ParserBase
|
||||
internal abstract class ParserBase(ParserContext context)
|
||||
{
|
||||
public ParserBase(ParserContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public ParserContext Context { get; }
|
||||
public ParserContext Context { get; } = context;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
|
||||
internal partial class ParserContext
|
||||
{
|
||||
public readonly ref struct ErrorScope(ParserContext context)
|
||||
{
|
||||
private readonly ParserContext _context = context;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context._errorSinkStack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,60 +4,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
|
||||
internal partial class ParserContext
|
||||
internal sealed partial class ParserContext : IDisposable
|
||||
{
|
||||
public ParserContext(RazorSourceDocument source, RazorParserOptions options)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
SourceDocument = source;
|
||||
|
||||
Source = new SeekableTextReader(SourceDocument);
|
||||
DesignTimeMode = options.DesignTime;
|
||||
FeatureFlags = options.FeatureFlags;
|
||||
ParseLeadingDirectives = options.ParseLeadingDirectives;
|
||||
ErrorSink = new ErrorSink();
|
||||
SeenDirectives = new HashSet<string>(StringComparer.Ordinal);
|
||||
EnableSpanEditHandlers = options.EnableSpanEditHandlers;
|
||||
}
|
||||
|
||||
public ErrorSink ErrorSink { get; set; }
|
||||
|
||||
public RazorParserFeatureFlags FeatureFlags { get; }
|
||||
|
||||
public HashSet<string> SeenDirectives { get; }
|
||||
|
||||
public SeekableTextReader Source { get; }
|
||||
private readonly RazorParserOptions _options;
|
||||
private readonly Stack<ErrorSink> _errorSinkStack;
|
||||
private readonly HashSet<string> _seenDirectivesSet;
|
||||
|
||||
public RazorSourceDocument SourceDocument { get; }
|
||||
|
||||
public bool DesignTimeMode { get; }
|
||||
|
||||
public bool ParseLeadingDirectives { get; }
|
||||
|
||||
public bool EnableSpanEditHandlers { get; }
|
||||
public SeekableTextReader Source { get; }
|
||||
|
||||
public bool WhiteSpaceIsSignificantToAncestorBlock { get; set; }
|
||||
|
||||
public bool NullGenerateWhitespaceAndNewLine { get; set; }
|
||||
|
||||
public bool InTemplateContext { get; set; }
|
||||
|
||||
public bool StartOfLine { get; set; } = true;
|
||||
|
||||
public bool MakeMarkerNode { get; set; } = true;
|
||||
|
||||
public AcceptedCharactersInternal CurrentAcceptedCharacters { get; set; } = AcceptedCharactersInternal.Any;
|
||||
|
||||
public bool EndOfFile
|
||||
public ParserContext(RazorSourceDocument source, RazorParserOptions options)
|
||||
{
|
||||
get { return Source.Peek() == -1; }
|
||||
ArgHelper.ThrowIfNull(source);
|
||||
ArgHelper.ThrowIfNull(options);
|
||||
|
||||
SourceDocument = source;
|
||||
_options = options;
|
||||
|
||||
_errorSinkStack = StackPool<ErrorSink>.Default.Get();
|
||||
_errorSinkStack.Push(new ErrorSink());
|
||||
|
||||
_seenDirectivesSet = StringHashSetPool.Ordinal.Get();
|
||||
|
||||
Source = new SeekableTextReader(SourceDocument);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
while (_errorSinkStack.Count > 0)
|
||||
{
|
||||
var errorSink = _errorSinkStack.Pop();
|
||||
errorSink.Dispose();
|
||||
}
|
||||
|
||||
StackPool<ErrorSink>.Default.Return(_errorSinkStack);
|
||||
StringHashSetPool.Ordinal.Return(_seenDirectivesSet);
|
||||
}
|
||||
|
||||
public ErrorSink ErrorSink => _errorSinkStack.Peek();
|
||||
|
||||
public RazorParserFeatureFlags FeatureFlags => _options.FeatureFlags;
|
||||
|
||||
public HashSet<string> SeenDirectives => _seenDirectivesSet;
|
||||
|
||||
public bool DesignTimeMode => _options.DesignTime;
|
||||
|
||||
public bool ParseLeadingDirectives => _options.ParseLeadingDirectives;
|
||||
|
||||
public bool EnableSpanEditHandlers => _options.EnableSpanEditHandlers;
|
||||
|
||||
public bool IsEndOfFile
|
||||
=> Source.Peek() == -1;
|
||||
|
||||
public ErrorScope PushNewErrorScope(ErrorSink errorSink)
|
||||
{
|
||||
_errorSinkStack.Push(errorSink);
|
||||
return new(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
|
||||
internal class RazorParser
|
||||
|
@ -16,10 +12,7 @@ internal class RazorParser
|
|||
|
||||
public RazorParser(RazorParserOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
ArgHelper.ThrowIfNull(options);
|
||||
|
||||
Options = options;
|
||||
}
|
||||
|
@ -28,23 +21,18 @@ internal class RazorParser
|
|||
|
||||
public virtual RazorSyntaxTree Parse(RazorSourceDocument source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
ArgHelper.ThrowIfNull(source);
|
||||
|
||||
var context = new ParserContext(source, Options);
|
||||
using var context = new ParserContext(source, Options);
|
||||
var codeParser = new CSharpCodeParser(Options.Directives, context);
|
||||
var markupParser = new HtmlMarkupParser(context);
|
||||
|
||||
codeParser.HtmlParser = markupParser;
|
||||
markupParser.CodeParser = codeParser;
|
||||
|
||||
var diagnostics = context.ErrorSink.Errors;
|
||||
|
||||
var root = markupParser.ParseDocument().CreateRed();
|
||||
var diagnostics = context.ErrorSink.GetErrorsAndClear();
|
||||
|
||||
var syntaxTree = RazorSyntaxTree.Create(root, source, diagnostics, Options);
|
||||
return syntaxTree;
|
||||
return new RazorSyntaxTree(root, source, diagnostics, Options);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,7 +292,6 @@ internal static class TagHelperBlockRewriter
|
|||
rewritten = rewritten.WithTagHelperAttributeInfo(
|
||||
new TagHelperAttributeInfo(result.AttributeName, parameterName: null, result.AttributeStructure, result.IsBoundAttribute, isDirectiveAttribute: false));
|
||||
|
||||
|
||||
result.RewrittenAttribute = rewritten;
|
||||
|
||||
return result;
|
||||
|
|
|
@ -16,7 +16,7 @@ internal static class TagHelperParseTreeRewriter
|
|||
{
|
||||
public static RazorSyntaxTree Rewrite(RazorSyntaxTree syntaxTree, TagHelperBinder binder, out ISet<TagHelperDescriptor> usedDescriptors)
|
||||
{
|
||||
var errorSink = new ErrorSink();
|
||||
using var errorSink = new ErrorSink();
|
||||
|
||||
var rewriter = new Rewriter(
|
||||
syntaxTree.Source,
|
||||
|
@ -26,25 +26,26 @@ internal static class TagHelperParseTreeRewriter
|
|||
|
||||
var rewritten = rewriter.Visit(syntaxTree.Root);
|
||||
|
||||
var errorList = new List<RazorDiagnostic>();
|
||||
errorList.AddRange(errorSink.Errors);
|
||||
errorList.AddRange(binder.TagHelpers.SelectMany(d => d.GetAllDiagnostics()));
|
||||
var treeDiagnostics = syntaxTree.Diagnostics;
|
||||
var sinkDiagnostics = errorSink.GetErrorsAndClear();
|
||||
|
||||
var diagnostics = CombineErrors(syntaxTree.Diagnostics, errorList).OrderBy(error => error.Span.AbsoluteIndex);
|
||||
using var builder = new PooledArrayBuilder<RazorDiagnostic>(capacity: treeDiagnostics.Length + sinkDiagnostics.Length);
|
||||
|
||||
builder.AddRange(treeDiagnostics);
|
||||
builder.AddRange(sinkDiagnostics);
|
||||
|
||||
foreach (var tagHelper in binder.TagHelpers)
|
||||
{
|
||||
foreach (var diagnostic in tagHelper.GetAllDiagnostics())
|
||||
{
|
||||
builder.Add(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
var diagnostics = builder.ToImmutableOrderedBy(static d => d.Span.AbsoluteIndex);
|
||||
|
||||
usedDescriptors = rewriter.UsedDescriptors;
|
||||
|
||||
var newSyntaxTree = RazorSyntaxTree.Create(rewritten, syntaxTree.Source, diagnostics, syntaxTree.Options);
|
||||
return newSyntaxTree;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<RazorDiagnostic> CombineErrors(IReadOnlyList<RazorDiagnostic> errors1, IReadOnlyList<RazorDiagnostic> errors2)
|
||||
{
|
||||
var combinedErrors = new List<RazorDiagnostic>(errors1.Count + errors2.Count);
|
||||
combinedErrors.AddRange(errors1);
|
||||
combinedErrors.AddRange(errors2);
|
||||
|
||||
return combinedErrors;
|
||||
return new RazorSyntaxTree(rewritten, syntaxTree.Source, diagnostics, syntaxTree.Options);
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
|
|
|
@ -1,72 +1,80 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||
using Microsoft.AspNetCore.Razor.Language.Syntax;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language;
|
||||
|
||||
public abstract class RazorSyntaxTree
|
||||
public sealed class RazorSyntaxTree
|
||||
{
|
||||
internal static RazorSyntaxTree Create(
|
||||
internal SyntaxNode Root { get; }
|
||||
public RazorParserOptions Options { get; }
|
||||
public RazorSourceDocument Source { get; }
|
||||
|
||||
private readonly ImmutableArray<RazorDiagnostic> _diagnostics;
|
||||
private ImmutableArray<RazorDiagnostic> _allDiagnostics;
|
||||
|
||||
internal RazorSyntaxTree(
|
||||
SyntaxNode root,
|
||||
RazorSourceDocument source,
|
||||
IEnumerable<RazorDiagnostic> diagnostics,
|
||||
ImmutableArray<RazorDiagnostic> diagnostics,
|
||||
RazorParserOptions options)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(root));
|
||||
}
|
||||
ArgHelper.ThrowIfNull(root);
|
||||
ArgHelper.ThrowIfNull(source);
|
||||
ArgHelper.ThrowIfNull(options);
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
if (diagnostics == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(diagnostics));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return new DefaultRazorSyntaxTree(root, source, new List<RazorDiagnostic>(diagnostics), options);
|
||||
Root = root;
|
||||
Source = source;
|
||||
_diagnostics = diagnostics.NullToEmpty();
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public static RazorSyntaxTree Parse(RazorSourceDocument source)
|
||||
public ImmutableArray<RazorDiagnostic> Diagnostics
|
||||
{
|
||||
if (source == null)
|
||||
get
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
if (_allDiagnostics.IsDefault)
|
||||
{
|
||||
ImmutableInterlocked.InterlockedInitialize(ref _allDiagnostics, ComputeAllDiagnostics(_diagnostics, Root));
|
||||
}
|
||||
|
||||
return Parse(source, options: null);
|
||||
return _allDiagnostics;
|
||||
|
||||
static ImmutableArray<RazorDiagnostic> ComputeAllDiagnostics(ImmutableArray<RazorDiagnostic> treeDiagnostics, SyntaxNode root)
|
||||
{
|
||||
using var pooledList = ListPool<RazorDiagnostic>.GetPooledObject(out var rootDiagnostics);
|
||||
using var diagnosticSet = new PooledHashSet<RazorDiagnostic>();
|
||||
|
||||
foreach (var diagnostic in treeDiagnostics)
|
||||
{
|
||||
diagnosticSet.Add(diagnostic);
|
||||
}
|
||||
|
||||
root.CollectAllDiagnostics(rootDiagnostics);
|
||||
|
||||
if (rootDiagnostics.Count > 0)
|
||||
{
|
||||
foreach (var diagnostic in rootDiagnostics)
|
||||
{
|
||||
diagnosticSet.Add(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
return diagnosticSet.OrderByAsArray(static d => d.Span.AbsoluteIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static RazorSyntaxTree Parse(RazorSourceDocument source, RazorParserOptions options)
|
||||
public static RazorSyntaxTree Parse(RazorSourceDocument source, RazorParserOptions? options = null)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
ArgHelper.ThrowIfNull(source);
|
||||
|
||||
var parser = new RazorParser(options ?? RazorParserOptions.CreateDefault());
|
||||
options ??= RazorParserOptions.CreateDefault();
|
||||
var parser = new RazorParser(options);
|
||||
return parser.Parse(source);
|
||||
}
|
||||
|
||||
public abstract IReadOnlyList<RazorDiagnostic> Diagnostics { get; }
|
||||
|
||||
public abstract RazorParserOptions Options { get; }
|
||||
|
||||
internal abstract SyntaxNode Root { get; }
|
||||
|
||||
public abstract RazorSourceDocument Source { get; }
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Immutable;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Syntax;
|
||||
|
||||
|
@ -52,8 +52,16 @@ internal static class GreenNodeExtensions
|
|||
}
|
||||
}
|
||||
|
||||
public static TNode WithDiagnosticsGreen<TNode>(this TNode node, params RazorDiagnostic[] diagnostics) where TNode : GreenNode
|
||||
public static TNode WithDiagnosticsGreen<TNode>(this TNode node, RazorDiagnostic[] diagnostics)
|
||||
where TNode : GreenNode
|
||||
{
|
||||
return (TNode)node.SetDiagnostics(diagnostics);
|
||||
}
|
||||
|
||||
public static TNode WithDiagnosticsGreen<TNode>(this TNode node, params ImmutableArray<RazorDiagnostic> diagnostics)
|
||||
where TNode : GreenNode
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(diagnostics);
|
||||
return node.WithDiagnosticsGreen(array);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,14 +42,13 @@ internal static class SyntaxNodeExtensions
|
|||
return (TNode)node.Green.SetDiagnostics(diagnostics).CreateRed(node.Parent, node.Position);
|
||||
}
|
||||
|
||||
public static TNode AppendDiagnostic<TNode>(this TNode node, params RazorDiagnostic[] diagnostics) where TNode : SyntaxNode
|
||||
public static TNode AppendDiagnostic<TNode>(this TNode node, params ReadOnlySpan<RazorDiagnostic> diagnostics) where TNode : SyntaxNode
|
||||
{
|
||||
var existingDiagnostics = node.GetDiagnostics();
|
||||
var allDiagnostics = new RazorDiagnostic[diagnostics.Length + existingDiagnostics.Length];
|
||||
Array.Copy(existingDiagnostics, allDiagnostics, existingDiagnostics.Length);
|
||||
Array.Copy(diagnostics, 0, allDiagnostics, existingDiagnostics.Length, diagnostics.Length);
|
||||
RazorDiagnostic[] allDiagnostics = [
|
||||
.. node.GetDiagnostics(),
|
||||
.. diagnostics];
|
||||
|
||||
return (TNode)node.WithDiagnostics(allDiagnostics);
|
||||
return node.WithDiagnostics(allDiagnostics);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -57,13 +56,13 @@ internal static class SyntaxNodeExtensions
|
|||
/// </summary>
|
||||
/// <typeparam name="TNode">The type of syntax node.</typeparam>
|
||||
/// <param name="node">The syntax node.</param>
|
||||
/// <returns>The list of <see cref="RazorDiagnostic"/>s.</returns>
|
||||
public static IReadOnlyList<RazorDiagnostic> GetAllDiagnostics<TNode>(this TNode node) where TNode : SyntaxNode
|
||||
/// <param name="list"></param>
|
||||
/// <returns>The list of <see cref="RazorDiagnostic">RazorDiagnostics</see>.</returns>
|
||||
public static void CollectAllDiagnostics<TNode>(this TNode node, List<RazorDiagnostic> list)
|
||||
where TNode : SyntaxNode
|
||||
{
|
||||
var walker = new DiagnosticSyntaxWalker();
|
||||
var walker = new DiagnosticSyntaxWalker(list);
|
||||
walker.Visit(node);
|
||||
|
||||
return walker.Diagnostics;
|
||||
}
|
||||
|
||||
public static SourceLocation GetSourceLocation(this SyntaxNode node, RazorSourceDocument source)
|
||||
|
@ -211,16 +210,9 @@ internal static class SyntaxNodeExtensions
|
|||
return writer.ToString();
|
||||
}
|
||||
|
||||
private class DiagnosticSyntaxWalker : SyntaxWalker
|
||||
private sealed class DiagnosticSyntaxWalker(List<RazorDiagnostic> diagnostics) : SyntaxWalker
|
||||
{
|
||||
private readonly List<RazorDiagnostic> _diagnostics;
|
||||
|
||||
public DiagnosticSyntaxWalker()
|
||||
{
|
||||
_diagnostics = new List<RazorDiagnostic>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<RazorDiagnostic> Diagnostics => _diagnostics;
|
||||
private readonly List<RazorDiagnostic> _diagnostics = diagnostics ?? [];
|
||||
|
||||
public override void Visit(SyntaxNode node)
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ public class SyntaxTreeGenerationBenchmark
|
|||
});
|
||||
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
|
||||
|
||||
if (syntaxTree.Diagnostics.Count != 0)
|
||||
if (syntaxTree.Diagnostics.Length != 0)
|
||||
{
|
||||
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public class SyntaxTreeGenerationBenchmark
|
|||
});
|
||||
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
|
||||
|
||||
if (syntaxTree.Diagnostics.Count != 0)
|
||||
if (syntaxTree.Diagnostics.Length != 0)
|
||||
{
|
||||
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
|
||||
}
|
||||
|
|
|
@ -437,7 +437,7 @@ internal class RazorTranslateDiagnosticsService(IDocumentMappingService document
|
|||
|
||||
private static bool CheckIfDocumentHasRazorDiagnostic(RazorCodeDocument codeDocument, string razorDiagnosticCode)
|
||||
{
|
||||
return codeDocument.GetSyntaxTree().Diagnostics.Any(d => d.Id.Equals(razorDiagnosticCode, StringComparison.Ordinal));
|
||||
return codeDocument.GetSyntaxTree().Diagnostics.Any(razorDiagnosticCode, static (d, code) => d.Id == code);
|
||||
}
|
||||
|
||||
private bool TryGetOriginalDiagnosticRange(Diagnostic diagnostic, RazorCodeDocument codeDocument, [NotNullWhen(true)] out Range? originalRange)
|
||||
|
|
|
@ -44,7 +44,7 @@ internal class RazorSyntaxTreePartialParser
|
|||
|
||||
// Remember if this was provisionally accepted for next partial parse.
|
||||
_lastResultProvisional = (result & PartialParseResultInternal.Provisional) == PartialParseResultInternal.Provisional;
|
||||
var newSyntaxTree = RazorSyntaxTree.Create(ModifiedSyntaxTreeRoot, OriginalSyntaxTree.Source, OriginalSyntaxTree.Diagnostics, OriginalSyntaxTree.Options);
|
||||
var newSyntaxTree = new RazorSyntaxTree(ModifiedSyntaxTreeRoot, OriginalSyntaxTree.Source, OriginalSyntaxTree.Diagnostics, OriginalSyntaxTree.Options);
|
||||
|
||||
return (result, newSyntaxTree);
|
||||
}
|
||||
|
|
|
@ -180,13 +180,13 @@ public abstract class ToolingParserTestBase : ToolingTestBase, IParserTest
|
|||
|
||||
internal virtual RazorSyntaxTree ParseDocument(RazorLanguageVersion version, string document, IEnumerable<DirectiveDescriptor> directives, bool designTime = false, RazorParserFeatureFlags featureFlags = null, string fileKind = null)
|
||||
{
|
||||
directives ??= Array.Empty<DirectiveDescriptor>();
|
||||
directives ??= [];
|
||||
|
||||
var source = TestRazorSourceDocument.Create(document, filePath: null, relativePath: null, normalizeNewLines: true);
|
||||
|
||||
var options = CreateParserOptions(version, directives, designTime, EnableSpanEditHandlers, featureFlags, fileKind);
|
||||
var context = new ParserContext(source, options);
|
||||
|
||||
using var context = new ParserContext(source, options);
|
||||
var codeParser = new CSharpCodeParser(directives, context);
|
||||
var markupParser = new HtmlMarkupParser(context);
|
||||
|
||||
|
@ -195,11 +195,11 @@ public abstract class ToolingParserTestBase : ToolingTestBase, IParserTest
|
|||
|
||||
var root = markupParser.ParseDocument().CreateRed();
|
||||
|
||||
var diagnostics = context.ErrorSink.Errors;
|
||||
var diagnostics = context.ErrorSink.GetErrorsAndClear();
|
||||
|
||||
var codeDocument = RazorCodeDocument.Create(source);
|
||||
|
||||
var syntaxTree = RazorSyntaxTree.Create(root, source, diagnostics, options);
|
||||
var syntaxTree = new RazorSyntaxTree(root, source, diagnostics, options);
|
||||
codeDocument.SetSyntaxTree(syntaxTree);
|
||||
|
||||
var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass();
|
||||
|
|
|
@ -378,7 +378,7 @@ public class RazorSyntaxTreePartialParserTest(ITestOutputHelper testOutput) : To
|
|||
Assert.Equal(PartialParseResultInternal.Accepted | additionalFlags, result);
|
||||
|
||||
var newSource = TestRazorSourceDocument.Create(edit.NewSnapshot.GetText());
|
||||
var newSyntaxTree = RazorSyntaxTree.Create(parser.ModifiedSyntaxTreeRoot, newSource, parser.OriginalSyntaxTree.Diagnostics, parser.OriginalSyntaxTree.Options);
|
||||
var newSyntaxTree = new RazorSyntaxTree(parser.ModifiedSyntaxTreeRoot, newSource, parser.OriginalSyntaxTree.Diagnostics, parser.OriginalSyntaxTree.Options);
|
||||
BaselineTest(newSyntaxTree);
|
||||
}
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ public class VisualStudioRazorParserIntegrationTest : VisualStudioTestBase
|
|||
}
|
||||
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content);
|
||||
var syntaxTree = RazorSyntaxTree.Create(manager.PartialParsingSyntaxTreeRoot, sourceDocument, manager.CurrentSyntaxTree!.Diagnostics, manager.CurrentSyntaxTree.Options);
|
||||
var syntaxTree = new RazorSyntaxTree(manager.PartialParsingSyntaxTreeRoot, sourceDocument, manager.CurrentSyntaxTree!.Diagnostics, manager.CurrentSyntaxTree.Options);
|
||||
BaselineTest(syntaxTree);
|
||||
}
|
||||
|
||||
|
|
|
@ -192,13 +192,13 @@ public abstract class ParserTestBase : IParserTest
|
|||
|
||||
internal virtual RazorSyntaxTree ParseDocument(RazorLanguageVersion version, string document, IEnumerable<DirectiveDescriptor> directives, bool designTime = false, RazorParserFeatureFlags featureFlags = null, string fileKind = null)
|
||||
{
|
||||
directives = directives ?? Array.Empty<DirectiveDescriptor>();
|
||||
directives = directives ?? [];
|
||||
|
||||
var source = TestRazorSourceDocument.Create(document, filePath: null, relativePath: null, normalizeNewLines: true);
|
||||
|
||||
var options = CreateParserOptions(version, directives, designTime, _validateSpanEditHandlers, featureFlags, fileKind);
|
||||
var context = new ParserContext(source, options);
|
||||
|
||||
using var context = new ParserContext(source, options);
|
||||
var codeParser = new CSharpCodeParser(directives, context);
|
||||
var markupParser = new HtmlMarkupParser(context);
|
||||
|
||||
|
@ -207,11 +207,11 @@ public abstract class ParserTestBase : IParserTest
|
|||
|
||||
var root = markupParser.ParseDocument().CreateRed();
|
||||
|
||||
var diagnostics = context.ErrorSink.Errors;
|
||||
var diagnostics = context.ErrorSink.GetErrorsAndClear();
|
||||
|
||||
var codeDocument = RazorCodeDocument.Create(source);
|
||||
|
||||
var syntaxTree = RazorSyntaxTree.Create(root, source, diagnostics, options);
|
||||
var syntaxTree = new RazorSyntaxTree(root, source, diagnostics, options);
|
||||
codeDocument.SetSyntaxTree(syntaxTree);
|
||||
|
||||
var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass();
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
using SR = Microsoft.AspNetCore.Razor.Utilities.Shared.Resources.SR;
|
||||
|
@ -141,260 +140,4 @@ public class EnumerableExtensionsTests
|
|||
public static CustomReadOnlyCollection Create(ReadOnlySpan<int> span)
|
||||
=> new(span);
|
||||
}
|
||||
|
||||
private static Comparison<int> OddBeforeEven
|
||||
=> (x, y) => (x % 2 != 0, y % 2 != 0) switch
|
||||
{
|
||||
(true, false) => -1,
|
||||
(false, true) => 1,
|
||||
_ => x.CompareTo(y)
|
||||
};
|
||||
|
||||
public readonly record struct ValueHolder(int Value)
|
||||
{
|
||||
public static implicit operator ValueHolder(int value)
|
||||
=> new(value);
|
||||
}
|
||||
|
||||
public static TheoryData<IEnumerable<int>, ImmutableArray<int>> OrderTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<int>, ImmutableArray<int>> OrderTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<int>, ImmutableArray<int>> OrderDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<int>, ImmutableArray<int>> OrderDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IEnumerable<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(IEnumerable<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(IEnumerable<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(IEnumerable<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(IEnumerable<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<IEnumerable<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<IEnumerable<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
IEnumerable<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
|
||||
|
||||
public class EnumerableOrderingTests : EnumerableOrderingTestBase
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(IEnumerable<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(IEnumerable<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(IEnumerable<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(IEnumerable<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(IEnumerable<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<IEnumerable<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<IEnumerable<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
IEnumerable<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,7 @@
|
|||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
|
||||
|
@ -39,748 +36,4 @@ public class ImmutableArrayExtensionsTests
|
|||
},
|
||||
s => Assert.Equal("WoRlD", s));
|
||||
}
|
||||
|
||||
private static Comparison<int> OddBeforeEven
|
||||
=> (x, y) => (x % 2 != 0, y % 2 != 0) switch
|
||||
{
|
||||
(true, false) => -1,
|
||||
(false, true) => 1,
|
||||
_ => x.CompareTo(y)
|
||||
};
|
||||
|
||||
public readonly record struct ValueHolder(int Value)
|
||||
{
|
||||
public static implicit operator ValueHolder(int value)
|
||||
=> new(value);
|
||||
}
|
||||
|
||||
public static TheoryData<ImmutableArray<int>, ImmutableArray<int>> OrderTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<int>, ImmutableArray<int>> OrderTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<int>, ImmutableArray<int>> OrderDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<int>, ImmutableArray<int>> OrderDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<ImmutableArray<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_ReadOnlyList(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_ReadOnlyList(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_ReadOnlyList(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder>)data;
|
||||
var sorted = readOnlyList.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder>)data;
|
||||
var sorted = readOnlyList.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_ReadOnlyList(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder>)data;
|
||||
var sorted = readOnlyList.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder>)data;
|
||||
var sorted = readOnlyList.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_Enumerable(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_Enumerable_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_Enumerable(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_Enumerable(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_Enumerable_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_Enumerable(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void ToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrdered();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrdered(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void ToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedDescending();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedDescending(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void ToImmutableOrderedBy(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void ToImmutableOrderedByDescending(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void DrainToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrdered();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrdered(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void DrainToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedDescending();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedDescending(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void DrainToImmutableOrderedBy(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void DrainToImmutableOrderedByDescending(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<int>.Empty);
|
||||
var immutableArray = ImmutableArray<int>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new int[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<int>.Empty);
|
||||
var immutableArray = ImmutableArray<int>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderDescendingAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new int[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderDescendingAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderDescendingAsArray();
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<ValueHolder>.Empty);
|
||||
var immutableArray = ImmutableArray<ValueHolder>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new ValueHolder[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new ValueHolder[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<ValueHolder>.Empty);
|
||||
var immutableArray = ImmutableArray<ValueHolder>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new ValueHolder[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new ValueHolder[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void UnsafeOrder(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().Order();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void UnsafeOrder_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().Order(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void UnsafeOrderDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderDescending();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderDescending(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void UnsafeOrderBy(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderBy(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderBy_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderBy(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void UnsafeOrderByDescending(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderByDescending(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderByDescending_OddBeforeEven(ImmutableArray<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderByDescending(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<ImmutableArray<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<ImmutableArray<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
ImmutableArray<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,665 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
|
||||
|
||||
public class ImmutableArrayOrderingTests : ImmutableArrayOrderingTestBase
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_ReadOnlyList(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_ReadOnlyList(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderDescendingAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<int>)data;
|
||||
var sorted = readOnlyList.OrderDescendingAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_ReadOnlyList(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder<int>>)data;
|
||||
var sorted = readOnlyList.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder<int>>)data;
|
||||
var sorted = readOnlyList.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_ReadOnlyList(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder<int>>)data;
|
||||
var sorted = readOnlyList.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var readOnlyList = (IReadOnlyList<ValueHolder<int>>)data;
|
||||
var sorted = readOnlyList.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_Enumerable(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_Enumerable_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_Enumerable(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_Enumerable(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_Enumerable_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_Enumerable(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void ToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrdered();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrdered(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void ToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedDescending();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedDescending(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void ToImmutableOrderedBy(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void ToImmutableOrderedByDescending(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void DrainToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrdered();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrdered(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void DrainToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedDescending();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedDescending(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void DrainToImmutableOrderedBy(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void DrainToImmutableOrderedByDescending(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builder = data.ToBuilder();
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<int>.Empty);
|
||||
var immutableArray = ImmutableArray<int>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new int[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
immutableArray = immutableArray.OrderAsArray();
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<int>.Empty);
|
||||
var immutableArray = ImmutableArray<int>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderDescendingAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new int[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderDescendingAsArray();
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderDescendingAsArray();
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<ValueHolder<int>>.Empty);
|
||||
var immutableArray = ImmutableArray<ValueHolder<int>>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new ValueHolder<int>[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new ValueHolder<int>[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderByAsArray(static x => x.Value);
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_EmptyArrayReturnsSameArray()
|
||||
{
|
||||
var array = ImmutableCollectionsMarshal.AsArray(ImmutableArray<ValueHolder<int>>.Empty);
|
||||
var immutableArray = ImmutableArray<ValueHolder<int>>.Empty;
|
||||
|
||||
immutableArray = immutableArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_SingleElementArrayReturnsSameArray()
|
||||
{
|
||||
var array = new ValueHolder<int>[] { 42 };
|
||||
var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array);
|
||||
|
||||
immutableArray = immutableArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(array, ImmutableCollectionsMarshal.AsArray(immutableArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_SortedArrayReturnsSameArray()
|
||||
{
|
||||
var values = new ValueHolder<int>[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
var presortedArray = ImmutableCollectionsMarshal.AsImmutableArray(values);
|
||||
|
||||
presortedArray = presortedArray.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Same(values, ImmutableCollectionsMarshal.AsArray(presortedArray));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void UnsafeOrder(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().Order();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void UnsafeOrder_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().Order(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void UnsafeOrderDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderDescending();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderDescending(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void UnsafeOrderBy(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderBy(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderBy_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderBy(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void UnsafeOrderByDescending(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderByDescending(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void UnsafeOrderByDescending_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
// Clone array, since we're modifying it in-place.
|
||||
var sorted = ImmutableArray.Create(data.AsSpan());
|
||||
sorted.Unsafe().OrderByDescending(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<ImmutableArray<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<ImmutableArray<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
ImmutableArray<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
<TargetFrameworks>$(DefaultNetCoreTargetFrameworks)</TargetFrameworks>
|
||||
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);$(DefaultNetFxTargetFramework)</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<IsShipping>false</IsShipping>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.PooledObjects;
|
||||
|
||||
internal static class Extensions
|
||||
{
|
||||
public static void Validate<T>(this ref readonly PooledArrayBuilder<T> builder, Action<PooledArrayBuilder<T>.TestAccessor> validator)
|
||||
{
|
||||
validator(builder.GetTestAccessor());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.PooledObjects;
|
||||
|
||||
public class PooledArrayBuilderOrderingTests : ImmutableArrayOrderingTestBase
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void ToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrdered();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrdered(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void ToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedDescending();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedDescending(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void ToImmutableOrderedBy(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void ToImmutableOrderedByDescending(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void ToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.ToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void DrainToImmutableOrdered(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<int>.Create();
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrdered();
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrdered_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<int>.Create();
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrdered(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void DrainToImmutableOrderedDescending(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<int>.Create();
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedDescending();
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedDescending_OddBeforeEven(ImmutableArray<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<int>.Create();
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedDescending(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void DrainToImmutableOrderedBy(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<ValueHolder<int>>.Create();
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedBy_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<ValueHolder<int>>.Create();
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedBy(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void DrainToImmutableOrderedByDescending(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<ValueHolder<int>>.Create();
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void DrainToImmutableOrderedByDescending_OddBeforeEven(ImmutableArray<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<ValueHolder<int>>.Create();
|
||||
using var builder = new PooledArrayBuilder<ValueHolder<int>>(capacity: data.Length, builderPool);
|
||||
builder.AddRange(data);
|
||||
|
||||
var sorted = builder.DrainToImmutableOrderedByDescending(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
AssertIsDrained(in builder);
|
||||
}
|
||||
|
||||
private static void AssertIsDrained<T>(ref readonly PooledArrayBuilder<T> builder)
|
||||
{
|
||||
builder.Validate(static t =>
|
||||
{
|
||||
Assert.NotNull(t.InnerArrayBuilder);
|
||||
Assert.Empty(t.InnerArrayBuilder);
|
||||
|
||||
// After draining, the capacity of the inner array builder should be 0.
|
||||
Assert.Equal(0, t.InnerArrayBuilder.Capacity);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -86,6 +86,61 @@ public class PooledArrayBuilderTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UseDrainAndReuse()
|
||||
{
|
||||
var builderPool = TestArrayBuilderPool<int>.Create();
|
||||
using var builder = new PooledArrayBuilder<int>(capacity: 10, builderPool);
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
builder.Add(i);
|
||||
}
|
||||
|
||||
// Verify that the builder contains 10 items within its inner array builder.
|
||||
builder.Validate(static t =>
|
||||
{
|
||||
Assert.Equal(0, t.InlineItemCount);
|
||||
Assert.Equal(10, t.Capacity);
|
||||
Assert.NotNull(t.InnerArrayBuilder);
|
||||
|
||||
Assert.Equal(10, t.InnerArrayBuilder.Count);
|
||||
Assert.Equal(10, t.InnerArrayBuilder.Capacity);
|
||||
});
|
||||
|
||||
var result = builder.DrainToImmutable();
|
||||
|
||||
// After draining, the builder should contain 0 items in its inner array builder
|
||||
// and the capacity should have been set to 0.
|
||||
builder.Validate(static t =>
|
||||
{
|
||||
Assert.Equal(0, t.InlineItemCount);
|
||||
Assert.Equal(10, t.Capacity);
|
||||
Assert.NotNull(t.InnerArrayBuilder);
|
||||
|
||||
Assert.Empty(t.InnerArrayBuilder);
|
||||
Assert.Equal(0, t.InnerArrayBuilder.Capacity);
|
||||
});
|
||||
|
||||
// Add another 10 items to the builder. At the end, the inner array builder
|
||||
// should hold 10 items with a capacity of 10.
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
builder.Add(i);
|
||||
}
|
||||
|
||||
// Verify that the builder contains 10 items within its inner array builder.
|
||||
builder.Validate(static t =>
|
||||
{
|
||||
Assert.Equal(0, t.InlineItemCount);
|
||||
Assert.Equal(10, t.Capacity);
|
||||
Assert.NotNull(t.InnerArrayBuilder);
|
||||
|
||||
Assert.Equal(10, t.InnerArrayBuilder.Count);
|
||||
Assert.Equal(10, t.InnerArrayBuilder.Capacity);
|
||||
});
|
||||
}
|
||||
|
||||
private static Func<int, bool> IsEven => x => x % 2 == 0;
|
||||
private static Func<int, bool> IsOdd => x => x % 2 != 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.PooledObjects;
|
||||
|
||||
internal static class TestArrayBuilderPool<T>
|
||||
{
|
||||
public static ObjectPool<ImmutableArray<T>.Builder> Create(
|
||||
IPooledObjectPolicy<ImmutableArray<T>.Builder>? policy = null, int size = 1)
|
||||
=> DefaultPool.Create(policy ?? NoReturnPolicy.Instance, size);
|
||||
|
||||
public sealed class NoReturnPolicy : IPooledObjectPolicy<ImmutableArray<T>.Builder>
|
||||
{
|
||||
public static readonly NoReturnPolicy Instance = new();
|
||||
|
||||
private NoReturnPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
public ImmutableArray<T>.Builder Create()
|
||||
=> ImmutableArray.CreateBuilder<T>();
|
||||
|
||||
public bool Return(ImmutableArray<T>.Builder obj)
|
||||
=> false;
|
||||
}
|
||||
}
|
|
@ -278,332 +278,4 @@ public class ReadOnlyListExtensionsTest
|
|||
public static CustomReadOnlyList Create(ReadOnlySpan<int> span)
|
||||
=> new(span);
|
||||
}
|
||||
|
||||
private static Comparison<int> OddBeforeEven
|
||||
=> (x, y) => (x % 2 != 0, y % 2 != 0) switch
|
||||
{
|
||||
(true, false) => -1,
|
||||
(false, true) => 1,
|
||||
_ => x.CompareTo(y)
|
||||
};
|
||||
|
||||
public readonly record struct ValueHolder(int Value)
|
||||
{
|
||||
public static implicit operator ValueHolder(int value)
|
||||
=> new(value);
|
||||
}
|
||||
|
||||
public static TheoryData<IReadOnlyList<int>, ImmutableArray<int>> OrderTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<int>, ImmutableArray<int>> OrderTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<int>, ImmutableArray<int>> OrderDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<int>, ImmutableArray<int>> OrderDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<ValueHolder>, ImmutableArray<ValueHolder>> OrderByTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] },
|
||||
};
|
||||
|
||||
public static TheoryData<IReadOnlyList<ValueHolder>, ImmutableArray<ValueHolder>> OrderByDescendingTestData_OddBeforeEven
|
||||
=> new()
|
||||
{
|
||||
{ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [1, 3, 5, 7, 9, 2, 4, 6, 8, 10], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [2, 5, 8, 1, 3, 9, 7, 4, 10, 6], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
{ [6, 10, 4, 7, 9, 3, 1, 8, 5, 2], [10, 8, 6, 4, 2, 9, 7, 5, 3, 1] },
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_Enumerable(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_Enumerable_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_Enumerable(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray();
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray(OddBeforeEven);
|
||||
Assert.Equal<int>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_Enumerable(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_Enumerable_OddBeforeEven(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_Enumerable(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList<ValueHolder> data, ImmutableArray<ValueHolder> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
Assert.Equal<ValueHolder>(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<IReadOnlyList<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<IReadOnlyList<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
IReadOnlyList<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
|
||||
|
||||
public class ReadOnlyListOrderingTests : ReadOnlyListOrderingTestBase
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var sorted = data.OrderDescendingAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_OddBeforeEven(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_OddBeforeEven(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var sorted = data.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData))]
|
||||
public void OrderAsArray_Enumerable(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderTestData_OddBeforeEven))]
|
||||
public void OrderAsArray_Enumerable_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData))]
|
||||
public void OrderDescendingAsArray_Enumerable(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray();
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderDescendingTestData_OddBeforeEven))]
|
||||
public void OrderDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList<int> data, ImmutableArray<int> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<int>)data;
|
||||
var sorted = enumerable.OrderDescendingAsArray(OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData))]
|
||||
public void OrderByAsArray_Enumerable(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByTestData_OddBeforeEven))]
|
||||
public void OrderByAsArray_Enumerable_OddBeforeEven(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData))]
|
||||
public void OrderByDescendingAsArray_Enumerable(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OrderByDescendingTestData_OddBeforeEven))]
|
||||
public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList<ValueHolder<int>> data, ImmutableArray<ValueHolder<int>> expected)
|
||||
{
|
||||
var enumerable = (IEnumerable<ValueHolder<int>>)data;
|
||||
var sorted = enumerable.OrderByDescendingAsArray(static x => x.Value, OddBeforeEven);
|
||||
AssertEqual(expected, sorted);
|
||||
}
|
||||
|
||||
#if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(),
|
||||
testFunction: data => data.OrderAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.Order(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(),
|
||||
testFunction: data => data.OrderDescendingAsArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.Ordinal),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.Ordinal));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderDescending(StringHolder.Comparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderDescendingAsArray(StringHolder.Comparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderBy(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderByDescendingAsArray_Comparer_IsStable()
|
||||
{
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
OrderAndAssertStableSort(
|
||||
linqFunction: data => data.OrderByDescending(static x => x?.Text, StringComparer.OrdinalIgnoreCase),
|
||||
testFunction: data => data.OrderByDescendingAsArray(static x => x?.Text, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static void OrderAndAssertStableSort(
|
||||
Func<IReadOnlyList<StringHolder?>, IEnumerable<StringHolder?>> linqFunction,
|
||||
Func<IReadOnlyList<StringHolder?>, ImmutableArray<StringHolder?>> testFunction)
|
||||
{
|
||||
IReadOnlyList<StringHolder?> data = [
|
||||
"All", "Your", "Base", "Are", "belong", null, "To", "Us",
|
||||
"all", "your", null, "Base", "are", "belong", "to", "us"];
|
||||
|
||||
var expected = linqFunction(data);
|
||||
var actual = testFunction(data);
|
||||
|
||||
Assert.Equal<StringHolder?>(expected, actual, ReferenceEquals);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public abstract class EnumerableOrderingTestBase : OrderingTestBase<IEnumerable<int>, IEnumerable<ValueHolder<int>>, OrderingCaseConverters.Enumerable>
|
||||
{
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public abstract class ImmutableArrayOrderingTestBase : OrderingTestBase<ImmutableArray<int>, ImmutableArray<ValueHolder<int>>, OrderingCaseConverters.ImmutableArray>
|
||||
{
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public interface IOrderingCaseConverter<TOrderCollection, TOrderByCollection>
|
||||
where TOrderCollection : IEnumerable<int>
|
||||
where TOrderByCollection : IEnumerable<ValueHolder<int>>
|
||||
{
|
||||
TOrderCollection ConvertOrderCase(ImmutableArray<int> data);
|
||||
TOrderByCollection ConvertOrderByCase(ImmutableArray<ValueHolder<int>> data);
|
||||
}
|
||||
|
||||
public static class OrderingCaseConverters
|
||||
{
|
||||
public sealed class Enumerable : IOrderingCaseConverter<IEnumerable<int>, IEnumerable<ValueHolder<int>>>
|
||||
{
|
||||
public IEnumerable<int> ConvertOrderCase(ImmutableArray<int> data) => data;
|
||||
public IEnumerable<ValueHolder<int>> ConvertOrderByCase(ImmutableArray<ValueHolder<int>> data) => data;
|
||||
}
|
||||
|
||||
public sealed class ImmutableArray : IOrderingCaseConverter<ImmutableArray<int>, ImmutableArray<ValueHolder<int>>>
|
||||
{
|
||||
public ImmutableArray<int> ConvertOrderCase(ImmutableArray<int> data) => data;
|
||||
public ImmutableArray<ValueHolder<int>> ConvertOrderByCase(ImmutableArray<ValueHolder<int>> data) => data;
|
||||
}
|
||||
|
||||
public sealed class ReadOnlyList : IOrderingCaseConverter<IReadOnlyList<int>, IReadOnlyList<ValueHolder<int>>>
|
||||
{
|
||||
public IReadOnlyList<int> ConvertOrderCase(ImmutableArray<int> data) => data;
|
||||
public IReadOnlyList<ValueHolder<int>> ConvertOrderByCase(ImmutableArray<ValueHolder<int>> data) => data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public abstract class OrderingTestBase<TOrderCollection, TOrderByCollection, TCaseConverter>
|
||||
where TOrderCollection : IEnumerable<int>
|
||||
where TOrderByCollection : IEnumerable<ValueHolder<int>>
|
||||
where TCaseConverter : IOrderingCaseConverter<TOrderCollection, TOrderByCollection>, new()
|
||||
{
|
||||
private static readonly TheoryData<TOrderCollection, ImmutableArray<int>> s_orderTestData = [];
|
||||
private static readonly TheoryData<TOrderCollection, ImmutableArray<int>> s_orderTestData_OddBeforeEven = [];
|
||||
private static readonly TheoryData<TOrderCollection, ImmutableArray<int>> s_orderDescendingTestData = [];
|
||||
private static readonly TheoryData<TOrderCollection, ImmutableArray<int>> s_orderDescendingTestData_OddBeforeEven = [];
|
||||
private static readonly TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> s_orderByTestData = [];
|
||||
private static readonly TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> s_orderByTestData_OddBeforeEven = [];
|
||||
private static readonly TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> s_orderByDescendingTestData = [];
|
||||
private static readonly TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> s_orderByDescendingTestData_OddBeforeEven = [];
|
||||
|
||||
protected static void AddCase(TOrderCollection collection)
|
||||
{
|
||||
s_orderTestData.Add(collection, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
s_orderTestData_OddBeforeEven.Add(collection, [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]);
|
||||
s_orderDescendingTestData.Add(collection, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
|
||||
s_orderDescendingTestData_OddBeforeEven.Add(collection, [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]);
|
||||
}
|
||||
|
||||
protected static void AddCase(TOrderByCollection collection)
|
||||
{
|
||||
s_orderByTestData.Add(collection, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
s_orderByTestData_OddBeforeEven.Add(collection, [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]);
|
||||
s_orderByDescendingTestData.Add(collection, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
|
||||
s_orderByDescendingTestData_OddBeforeEven.Add(collection, [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]);
|
||||
}
|
||||
|
||||
static OrderingTestBase()
|
||||
{
|
||||
var converter = new TCaseConverter();
|
||||
|
||||
AddCase(converter.ConvertOrderCase([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
|
||||
AddCase(converter.ConvertOrderCase([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]));
|
||||
AddCase(converter.ConvertOrderCase([1, 3, 5, 7, 9, 2, 4, 6, 8, 10]));
|
||||
AddCase(converter.ConvertOrderCase([2, 5, 8, 1, 3, 9, 7, 4, 10, 6]));
|
||||
AddCase(converter.ConvertOrderCase([6, 10, 4, 7, 9, 3, 1, 8, 5, 2]));
|
||||
|
||||
AddCase(converter.ConvertOrderByCase([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
|
||||
AddCase(converter.ConvertOrderByCase([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]));
|
||||
AddCase(converter.ConvertOrderByCase([1, 3, 5, 7, 9, 2, 4, 6, 8, 10]));
|
||||
AddCase(converter.ConvertOrderByCase([2, 5, 8, 1, 3, 9, 7, 4, 10, 6]));
|
||||
AddCase(converter.ConvertOrderByCase([6, 10, 4, 7, 9, 3, 1, 8, 5, 2]));
|
||||
}
|
||||
|
||||
protected static Comparison<int> OddBeforeEven
|
||||
=> (x, y) => (x % 2 != 0, y % 2 != 0) switch
|
||||
{
|
||||
(true, false) => -1,
|
||||
(false, true) => 1,
|
||||
_ => x.CompareTo(y)
|
||||
};
|
||||
|
||||
public static TheoryData<TOrderCollection, ImmutableArray<int>> OrderTestData => s_orderTestData;
|
||||
public static TheoryData<TOrderCollection, ImmutableArray<int>> OrderTestData_OddBeforeEven => s_orderTestData_OddBeforeEven;
|
||||
public static TheoryData<TOrderCollection, ImmutableArray<int>> OrderDescendingTestData => s_orderDescendingTestData;
|
||||
public static TheoryData<TOrderCollection, ImmutableArray<int>> OrderDescendingTestData_OddBeforeEven => s_orderDescendingTestData_OddBeforeEven;
|
||||
public static TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> OrderByTestData => s_orderByTestData;
|
||||
public static TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> OrderByTestData_OddBeforeEven => s_orderByTestData_OddBeforeEven;
|
||||
public static TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> OrderByDescendingTestData => s_orderByDescendingTestData;
|
||||
public static TheoryData<TOrderByCollection, ImmutableArray<ValueHolder<int>>> OrderByDescendingTestData_OddBeforeEven => s_orderByDescendingTestData_OddBeforeEven;
|
||||
|
||||
protected void AssertEqual<T>(ImmutableArray<T> result, ImmutableArray<T> expected)
|
||||
{
|
||||
Assert.Equal<T>(result, expected);
|
||||
}
|
||||
|
||||
protected void AssertEqual<T>(ImmutableArray<T> result, ImmutableArray<T> expected, IEqualityComparer<T> comparer)
|
||||
{
|
||||
Assert.Equal(result, expected, comparer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public abstract class ReadOnlyListOrderingTestBase : OrderingTestBase<IReadOnlyList<int>, IReadOnlyList<ValueHolder<int>>, OrderingCaseConverters.ReadOnlyList>
|
||||
{
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public sealed class StringHolder(string? text) : IComparable<StringHolder>
|
||||
{
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test.TestData;
|
||||
|
||||
public readonly record struct ValueHolder<T>(T Value)
|
||||
{
|
||||
public static implicit operator ValueHolder<T>(T value)
|
||||
=> new(value);
|
||||
}
|
|
@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.AspNetCore.Razor;
|
||||
using Microsoft.AspNetCore.Razor.Utilities;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.PooledObjects;
|
||||
|
||||
|
@ -33,6 +34,8 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
/// </summary>
|
||||
private const int InlineCapacity = 4;
|
||||
|
||||
private ObjectPool<ImmutableArray<T>.Builder>? _builderPool;
|
||||
|
||||
/// <summary>
|
||||
/// A builder to be used as storage after the first time that the number
|
||||
/// of items exceeds <see cref="InlineCapacity"/>. Once the builder is used,
|
||||
|
@ -56,9 +59,10 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
/// </summary>
|
||||
private int _inlineCount;
|
||||
|
||||
public PooledArrayBuilder(int? capacity = null)
|
||||
public PooledArrayBuilder(int? capacity = null, ObjectPool<ImmutableArray<T>.Builder>? builderPool = null)
|
||||
{
|
||||
_capacity = capacity is > InlineCapacity ? capacity : null;
|
||||
_builderPool = builderPool;
|
||||
_element0 = default!;
|
||||
_element1 = default!;
|
||||
_element2 = default!;
|
||||
|
@ -79,13 +83,50 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
// Return _builder to the pool if necessary. Note that we don't need to clear the inline elements here
|
||||
// because this type is intended to be allocated on the stack and the GC can reclaim objects from the
|
||||
// stack after the last use of a reference to them.
|
||||
if (_builder is { } builder)
|
||||
if (_builder is { } innerBuilder)
|
||||
{
|
||||
ArrayBuilderPool<T>.Default.Return(builder);
|
||||
_builderPool?.Return(innerBuilder);
|
||||
_builder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the inner <see cref="_builder"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns <see langword="true"/> if <see cref="_builder"/> is available; otherwise <see langword="false"/>
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This should only be used by methods that will not add to the inner <see cref="_builder"/>.
|
||||
/// </remarks>
|
||||
private readonly bool TryGetBuilder([NotNullWhen(true)] out ImmutableArray<T>.Builder? builder)
|
||||
{
|
||||
builder = _builder;
|
||||
return builder is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the inner <see cref="_builder"/> and resets its capacity if necessary.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns <see langword="true"/> if <see cref="_builder"/> is available; otherwise <see langword="false"/>
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This should only be used by methods that will add to the inner <see cref="_builder"/>.
|
||||
/// </remarks>
|
||||
private readonly bool TryGetBuilderAndEnsureCapacity([NotNullWhen(true)] out ImmutableArray<T>.Builder? builder)
|
||||
{
|
||||
if (TryGetBuilder(out builder))
|
||||
{
|
||||
if (builder.Capacity == 0 && _capacity is int capacity)
|
||||
{
|
||||
builder.Capacity = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
return builder is not null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ClearInlineElement(int index)
|
||||
{
|
||||
|
@ -108,7 +149,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
readonly get
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
return builder[index];
|
||||
}
|
||||
|
@ -124,7 +165,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
builder[index] = value;
|
||||
return;
|
||||
|
@ -194,7 +235,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilderAndEnsureCapacity(out var builder))
|
||||
{
|
||||
builder.Add(item);
|
||||
}
|
||||
|
@ -229,7 +270,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilderAndEnsureCapacity(out var builder))
|
||||
{
|
||||
builder.AddRange(items);
|
||||
}
|
||||
|
@ -250,7 +291,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public void AddRange(IEnumerable<T> items)
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilderAndEnsureCapacity(out var builder))
|
||||
{
|
||||
builder.AddRange(items);
|
||||
return;
|
||||
|
@ -292,7 +333,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public void Clear()
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
// Keep using a real builder to avoid churn in the object pool.
|
||||
builder.Clear();
|
||||
|
@ -310,7 +351,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilderAndEnsureCapacity(out var builder))
|
||||
{
|
||||
builder.RemoveAt(index);
|
||||
return;
|
||||
|
@ -380,7 +421,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
/// <returns>An immutable array.</returns>
|
||||
public ImmutableArray<T> DrainToImmutable()
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
return builder.DrainToImmutable();
|
||||
}
|
||||
|
@ -396,7 +437,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public readonly ImmutableArray<T> ToImmutable()
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
return builder.ToImmutable();
|
||||
}
|
||||
|
@ -420,7 +461,7 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
|
||||
public readonly T[] ToArray()
|
||||
{
|
||||
if (_builder is { } builder)
|
||||
if (TryGetBuilder(out var builder))
|
||||
{
|
||||
return builder.ToArray();
|
||||
}
|
||||
|
@ -1314,7 +1355,8 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
{
|
||||
Debug.Assert(_builder is null);
|
||||
|
||||
var builder = ArrayBuilderPool<T>.Default.Get();
|
||||
_builderPool ??= ArrayBuilderPool<T>.Default;
|
||||
var builder = _builderPool.Get();
|
||||
|
||||
if (_capacity is int capacity)
|
||||
{
|
||||
|
@ -1333,4 +1375,205 @@ internal partial struct PooledArrayBuilder<T> : IDisposable
|
|||
// Since _inlineCount tracks the number of inline items used, we zero it out here.
|
||||
_inlineCount = 0;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrdered()
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().Order();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrdered(IComparer<T> comparer)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().Order(comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrdered(Comparison<T> comparison)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().Order(comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedDescending()
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderDescending();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedDescending(IComparer<T> comparer)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderDescending(comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedDescending(Comparison<T> comparison)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderDescending(comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector, comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector, Comparison<TKey> comparison)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector, comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector, comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<T> ToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector, Comparison<TKey> comparison)
|
||||
{
|
||||
var result = ToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector, comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrdered()
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().Order();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrdered(IComparer<T> comparer)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().Order(comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrdered(Comparison<T> comparison)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().Order(comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedDescending()
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderDescending();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedDescending(IComparer<T> comparer)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderDescending(comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedDescending(Comparison<T> comparison)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderDescending(comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector, comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedBy<TKey>(Func<T, TKey> keySelector, Comparison<TKey> comparison)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderBy(keySelector, comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector, comparer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<T> DrainToImmutableOrderedByDescending<TKey>(Func<T, TKey> keySelector, Comparison<TKey> comparison)
|
||||
{
|
||||
var result = DrainToImmutable();
|
||||
result.Unsafe().OrderByDescending(keySelector, comparison);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal readonly TestAccessor GetTestAccessor() => new(in this);
|
||||
|
||||
internal readonly struct TestAccessor(ref readonly PooledArrayBuilder<T> builder)
|
||||
{
|
||||
public ImmutableArray<T>.Builder? InnerArrayBuilder { get; } = builder._builder;
|
||||
public int? Capacity { get; } = builder._capacity;
|
||||
public int InlineItemCount { get; } = builder._inlineCount;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче