Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run all cohosting tests with FUSE on and off #11330

Merged
merged 11 commits into from
Jan 6, 2025
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Xunit;
using Xunit.Sdk;

namespace Microsoft.AspNetCore.Razor.Test.Common;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer($"Microsoft.AspNetCore.Razor.Test.Common.{nameof(FuseFactDiscoverer)}", "Microsoft.AspNetCore.Razor.Test.Common")]
internal sealed class FuseFactAttribute : FactAttribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Microsoft.AspNetCore.Razor.Test.Common;

internal sealed class FuseFactDiscoverer(IMessageSink diagnosticMessageSink)
: FactDiscoverer(diagnosticMessageSink)
{
public override IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{
return CreateTestCases(discoveryOptions, testMethod, DiagnosticMessageSink);
}

public static IEnumerable<IXunitTestCase> CreateTestCases(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IMessageSink messageSink, object[]? dataRow = null)
{
yield return CreateTestCase(forceRuntimeCodeGeneration: false);
yield return CreateTestCase(forceRuntimeCodeGeneration: true);

FuseTestCase CreateTestCase(bool forceRuntimeCodeGeneration)
{
return new FuseTestCase(forceRuntimeCodeGeneration, messageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, dataRow);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Microsoft.AspNetCore.Razor.Test.Common;

internal sealed class FuseTestCase : XunitTestCase
{
private bool _forceRuntimeCodeGeneration;

[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public FuseTestCase() { }

public FuseTestCase(bool forceRuntimeCodeGeneration, IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[]? testMethodArguments = null)
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments)
{
_forceRuntimeCodeGeneration = forceRuntimeCodeGeneration;
}

protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName)
{
return base.GetDisplayName(factAttribute, displayName) + (_forceRuntimeCodeGeneration ? " (FUSE)" : "");
}

protected override string GetSkipReason(IAttributeInfo factAttribute)
{
if (_forceRuntimeCodeGeneration && TestMethod.TestClass.TestCollection.TestAssembly.Assembly.Name.StartsWith("Microsoft.AspNetCore.Razor.LanguageServer"))
{
return "Language server cannot run FUSE tests";
}

return base.GetSkipReason(factAttribute);
}

public override Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
{
Debug.Assert(constructorArguments.Length >= 1 && constructorArguments[0] is FuseTestContext, $"{TestMethod.TestClass.Class.Name}.{TestMethod.Method.Name} uses a formatting test attribute in a class without a FuseTestContext parameter?");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we know that a formatting test attribute is getting used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, we don't, but instances of this test case are only created by the discoverer for those attributes. If we could actually know for sure, then this assert wouldn't be needed.

constructorArguments[0] = new FuseTestContext
{
ForceRuntimeCodeGeneration = _forceRuntimeCodeGeneration
};
return base.RunAsync(diagnosticMessageSink, messageBus, constructorArguments, aggregator, cancellationTokenSource);
}

public override void Deserialize(IXunitSerializationInfo data)
{
_forceRuntimeCodeGeneration = data.GetValue<bool>(nameof(_forceRuntimeCodeGeneration));
base.Deserialize(data);
}

public override void Serialize(IXunitSerializationInfo data)
{
data.AddValue(nameof(_forceRuntimeCodeGeneration), _forceRuntimeCodeGeneration);
base.Serialize(data);
}

protected override string GetUniqueID()
{
return base.GetUniqueID() + (_forceRuntimeCodeGeneration ? "FUSE" : "NOFUSE");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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.Test.Common;

public sealed class FuseTestContext
{
public required bool ForceRuntimeCodeGeneration { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Xunit;
using Xunit.Sdk;

namespace Microsoft.AspNetCore.Razor.Test.Common;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer($"Microsoft.AspNetCore.Razor.Test.Common.{nameof(FuseTheoryDiscoverer)}", "Microsoft.AspNetCore.Razor.Test.Common")]
internal sealed class FuseTheoryAttribute : TheoryAttribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Microsoft.AspNetCore.Razor.Test.Common;

internal sealed class FuseTheoryDiscoverer(IMessageSink diagnosticMessageSink)
: TheoryDiscoverer(diagnosticMessageSink)
{
public override IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
{
// We have to force pre-enumeration of theories for this discoverer to work correctly. Normally its true in VS,
// but false in command line/CI. Since we're injecting "fake" data rows, we rely on it everywhere. Without this
// set to true, the method below that we override doesn't get called.
discoveryOptions.SetValue("xunit.discovery.PreEnumerateTheories", true);
return base.Discover(discoveryOptions, testMethod, theoryAttribute);
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
{
return FuseFactDiscoverer.CreateTestCases(discoveryOptions, testMethod, DiagnosticMessageSink, dataRow);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.Razor.IntegrationTests" Key="$(RazorKey)" />
</ItemGroup>

<ItemGroup>
davidwengier marked this conversation as resolved.
Show resolved Hide resolved
<Folder Include="Formatting\" />
</ItemGroup>

</Project>