Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ public static DemoServices AddFluentUIDemoServices(this IServiceCollection servi
options.PageTitle = "{0} - FluentUI Blazor Components";
options.ComponentsAssembly = typeof(Client._Imports).Assembly;
options.ResourcesAssembly = typeof(Client._Imports).Assembly;
options.ApiAssembly = typeof(Microsoft.FluentUI.AspNetCore.Components._Imports).Assembly;
options.ApiAssemblies =
[
typeof(Microsoft.FluentUI.AspNetCore.Components._Imports).Assembly,
];
options.ApiCommentSummary = (data, component, member) =>
{
if (member is null && (data is null || data?.Items?.Count <= 1))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
// This file is licensed to you under the MIT License.
// ------------------------------------------------------------------------

using FluentUI.Demo.DocApiGen;
using System.Reflection;
using System.Text.Json;
using FluentUI.Demo.DocApiGen.Abstractions;
using FluentUI.Demo.DocApiGen.Formatters;
using FluentUI.Demo.DocApiGen.Generators;
using System.Reflection;
using System.Text.Json;
using Xunit;
using FluentUI.Demo.DocApiGen.Models;

namespace FluentUI.Demo.DocApiGen.IntegrationTests;

Expand All @@ -24,7 +23,9 @@ public class FluentUIComponentsIntegrationTests : IDisposable
private readonly FileInfo _xmlDocumentation;
private readonly string _tempOutputDirectory;
private readonly string _xmlPath;
private readonly DocumentationAssemblyLoadContext _assemblyLoadContext;
private readonly Assembly _fluentUIAssembly;
private readonly IReadOnlyList<DocumentationInput> _documentationInputs;

/// <summary>
/// Initializes a new instance of the <see cref="FluentUIComponentsIntegrationTests"/> class.
Expand All @@ -44,22 +45,30 @@ public FluentUIComponentsIntegrationTests()
}

_xmlDocumentation = new FileInfo(_xmlPath);
_assemblyLoadContext = new DocumentationAssemblyLoadContext([GetAssemblyPath(projectRoot, Path.Combine("src", "Core"), "Microsoft.FluentUI.AspNetCore.Components.dll")]);

// Load the FluentUI assembly dynamically
var fluentUIAssemblyPath = Path.Combine(projectRoot, "src", "Core", "bin", "Debug", NET_VERSION, "Microsoft.FluentUI.AspNetCore.Components.dll");
var fluentUIAssemblyPath = GetAssemblyPath(projectRoot, Path.Combine("src", "Core"), "Microsoft.FluentUI.AspNetCore.Components.dll");

if (!File.Exists(fluentUIAssemblyPath))
_fluentUIAssembly = _assemblyLoadContext.LoadFromAssemblyPath(fluentUIAssemblyPath);
_documentationInputs = [new DocumentationInput(_fluentUIAssembly, _xmlDocumentation)];
}

private static string GetAssemblyPath(string projectRoot, string relativeProjectDirectory, string assemblyFileName)
{
var debugPath = Path.Combine(projectRoot, relativeProjectDirectory, "bin", "Debug", NET_VERSION, assemblyFileName);
if (File.Exists(debugPath))
{
// Try alternative path (Release build)
fluentUIAssemblyPath = Path.Combine(projectRoot, "src", "Core", "bin", "Release", NET_VERSION, "Microsoft.FluentUI.AspNetCore.Components.dll");
return debugPath;
}

if (!File.Exists(fluentUIAssemblyPath))
{
throw new FileNotFoundException($"FluentUI assembly not found. Please build the Core project first. Looked for: {fluentUIAssemblyPath}");
}
var releasePath = Path.Combine(projectRoot, relativeProjectDirectory, "bin", "Release", NET_VERSION, assemblyFileName);
if (File.Exists(releasePath))
{
return releasePath;
}

_fluentUIAssembly = Assembly.LoadFrom(fluentUIAssemblyPath);
throw new FileNotFoundException($"Assembly not found. Please build the project first. Looked for: {releasePath}");
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

GetAssemblyPath checks both Debug and Release locations, but the thrown FileNotFoundException message only reports the Release path. This makes failures harder to diagnose because the Debug path was also tried. Consider including both attempted paths in the exception message.

Suggested change
throw new FileNotFoundException($"Assembly not found. Please build the project first. Looked for: {releasePath}");
throw new FileNotFoundException(
$"Assembly not found. Please build the project first. Looked for: {debugPath}; {releasePath}");

Copilot uses AI. Check for mistakes.
}

/// <summary>
Expand All @@ -72,7 +81,7 @@ private static string GetProjectRootDirectory()
// Look for solution file
while (directory != null)
{
var solutionFiles = directory.GetFiles("*.sln");
var solutionFiles = directory.GetFiles("*.slnx");
if (solutionFiles.Length > 0)
{
return directory.FullName;
Expand Down Expand Up @@ -108,7 +117,7 @@ public void Dispose()
public void SummaryGenerator_ShouldGenerateJsonSuccessfully()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -125,7 +134,7 @@ public void SummaryGenerator_ShouldGenerateJsonSuccessfully()
public void SummaryGenerator_ShouldGenerateCSharpSuccessfully()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateCSharpFormatter();

// Act
Expand All @@ -143,7 +152,7 @@ public void SummaryGenerator_ShouldGenerateCSharpSuccessfully()
public void SummaryGenerator_JsonOutput_ShouldContainFluentUIComponents()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -158,7 +167,7 @@ public void SummaryGenerator_JsonOutput_ShouldContainFluentUIComponents()
public void SummaryGenerator_CSharpOutput_ShouldContainFluentUIComponents()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateCSharpFormatter();

// Act
Expand All @@ -173,7 +182,7 @@ public void SummaryGenerator_CSharpOutput_ShouldContainFluentUIComponents()
public void SummaryGenerator_JsonOutput_ShouldBeValidJson()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -188,7 +197,7 @@ public void SummaryGenerator_JsonOutput_ShouldBeValidJson()
public void SummaryGenerator_SaveToFile_JsonShouldSucceed()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);
var outputPath = Path.Combine(_tempOutputDirectory, "fluentui_summary.json");

Expand All @@ -211,7 +220,7 @@ public void SummaryGenerator_SaveToFile_JsonShouldSucceed()
public void SummaryGenerator_SaveToFile_CSharpShouldSucceed()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateCSharpFormatter();
var outputPath = Path.Combine(_tempOutputDirectory, "fluentui_summary.cs");

Expand All @@ -230,7 +239,7 @@ public void SummaryGenerator_SaveToFile_CSharpShouldSucceed()
public void SummaryGenerator_LargeScale_ShouldCompleteWithoutErrors()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var jsonFormatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);
var csharpFormatter = OutputFormatterFactory.CreateCSharpFormatter();

Expand All @@ -253,7 +262,7 @@ public void SummaryGenerator_LargeScale_ShouldCompleteWithoutErrors()
public void SummaryGenerator_OutputSize_ShouldBeReasonable()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var jsonFormatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);
var csharpFormatter = OutputFormatterFactory.CreateCSharpFormatter();

Expand All @@ -273,7 +282,7 @@ public void SummaryGenerator_OutputSize_ShouldBeReasonable()
public void SummaryGenerator_JsonMetadata_ShouldBePresent()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -296,7 +305,7 @@ public void SummaryGenerator_JsonMetadata_ShouldBePresent()
public void SummaryGenerator_CompactFormat_ShouldGenerateCorrectStructure()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -315,7 +324,7 @@ public void SummaryGenerator_CompactFormat_ShouldGenerateCorrectStructure()
public void SummaryGenerator_CompactFormat_ShouldBeValidJson()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);

// Act
Expand All @@ -330,7 +339,7 @@ public void SummaryGenerator_CompactFormat_ShouldBeValidJson()
public void SummaryGenerator_CompactFormat_SaveToFile_ShouldSucceed()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: true);
var outputPath = Path.Combine(_tempOutputDirectory, "fluentui_compact.json");

Expand All @@ -349,6 +358,41 @@ public void SummaryGenerator_CompactFormat_SaveToFile_ShouldSucceed()
Assert.Null(exception);
}

[Fact]
public void AllGenerator_WithMultipleDocumentationInputs_ShouldIncludeChartsAssemblyTypes()
{
// Arrange
var projectRoot = GetProjectRootDirectory();
var chartsAssemblyPath = Path.Combine(projectRoot, "src", "Charts", "bin", "Debug", NET_VERSION, "Microsoft.FluentUI.AspNetCore.Components.Charts.dll");

if (!File.Exists(chartsAssemblyPath))
{
chartsAssemblyPath = Path.Combine(projectRoot, "src", "Charts", "bin", "Release", NET_VERSION, "Microsoft.FluentUI.AspNetCore.Components.Charts.dll");
}

var chartsXmlPath = Path.Combine(projectRoot, "examples", "Tools", "FluentUI.Demo.DocApiGen", "Microsoft.FluentUI.AspNetCore.Components.Charts.xml");

if (!File.Exists(chartsAssemblyPath) || !File.Exists(chartsXmlPath))
{
return;
}
Comment on lines +375 to +378
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This new integration test currently becomes a no-op in this repo layout: the referenced src/Charts/.../Microsoft.FluentUI.AspNetCore.Components.Charts.dll and the Microsoft.FluentUI.AspNetCore.Components.Charts.xml file don’t exist, so the test hits return; and always passes without asserting multi-input behavior. Consider pointing the test at an assembly/docs pair that is present in-repo (or making missing prerequisites fail/explicitly skip) so CI actually exercises the multi-assembly path.

Suggested change
if (!File.Exists(chartsAssemblyPath) || !File.Exists(chartsXmlPath))
{
return;
}
Assert.True(
File.Exists(chartsAssemblyPath) && File.Exists(chartsXmlPath),
$"Multi-input integration test prerequisites are missing. Expected assembly: '{chartsAssemblyPath}' (exists: {File.Exists(chartsAssemblyPath)}), expected XML docs: '{chartsXmlPath}' (exists: {File.Exists(chartsXmlPath)}).");

Copilot uses AI. Check for mistakes.

var inputs = new List<DocumentationInput>(_documentationInputs)
{
new(new DocumentationAssemblyLoadContext([chartsAssemblyPath]).LoadFromAssemblyPath(chartsAssemblyPath), new FileInfo(chartsXmlPath))
};

var generator = DocumentationGeneratorFactory.Create(GenerationMode.All, inputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: false);

// Act
var json = generator.Generate(formatter);

// Assert
Assert.Contains("FluentDonutChart", json);
Assert.Contains("FluentHorizontalBarChart", json);
}

#endregion

#region Summary Mode Tests - Structured Format (Extended)
Expand All @@ -357,7 +401,7 @@ public void SummaryGenerator_CompactFormat_SaveToFile_ShouldSucceed()
public void SummaryGenerator_StructuredFormat_ShouldContainMetadata()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateSummaryGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.Summary, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: false);

// Act
Expand All @@ -381,7 +425,7 @@ public void SummaryGenerator_StructuredFormat_ShouldContainMetadata()
public void AllGenerator_ShouldGenerateJsonSuccessfully()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateAllGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.All, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: false);

// Act
Expand All @@ -398,7 +442,7 @@ public void AllGenerator_ShouldGenerateJsonSuccessfully()
public void AllGenerator_ShouldNotSupportCSharpFormat()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateAllGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.All, _documentationInputs);
var formatter = OutputFormatterFactory.CreateCSharpFormatter();

// Act & Assert
Expand All @@ -410,7 +454,7 @@ public void AllGenerator_ShouldNotSupportCSharpFormat()
public void AllGenerator_JsonOutput_ShouldContainComponents()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateAllGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.All, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: false);

// Act
Expand All @@ -427,7 +471,7 @@ public void AllGenerator_JsonOutput_ShouldContainComponents()
public void AllGenerator_SaveToFile_ShouldSucceed()
{
// Arrange
var generator = DocumentationGeneratorFactory.CreateAllGenerator(_fluentUIAssembly, _xmlDocumentation);
var generator = DocumentationGeneratorFactory.Create(GenerationMode.All, _documentationInputs);
var formatter = OutputFormatterFactory.CreateJsonFormatter(useCompactFormat: false);
var outputPath = Path.Combine(_tempOutputDirectory, "fluentui_all.json");

Expand Down Expand Up @@ -478,7 +522,7 @@ private static (Assembly McpAssembly, FileInfo McpXml)? TryLoadMcpAssembly()
return null;
}

var mcpAssembly = Assembly.LoadFrom(mcpAssemblyPath);
var mcpAssembly = new DocumentationAssemblyLoadContext([mcpAssemblyPath]).LoadFromAssemblyPath(mcpAssemblyPath);
var mcpXml = new FileInfo(mcpXmlPath);

return (mcpAssembly, mcpXml);
Expand Down
Loading
Loading