Skip to content

Commit 7ce3317

Browse files
committed
Add MCP JSON doc generation and model tests to DocApiGen
- Added "mcp" output format to DocApiGen for MCP-compatible JSON documentation, consumable by McpServer. - Implemented McpDocumentationGenerator and new model classes for components, enums, and metadata. - Updated Program.cs to support "mcp" format and improved CLI help. - Added FluentUI.Demo.DocApiGen.Tests project with xUnit tests for all new MCP documentation models. - All new files are MIT licensed and follow consistent style.
1 parent fc2faa7 commit 7ce3317

16 files changed

+1406
-9
lines changed

Microsoft.FluentUI-v5.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<Project Path="examples/Demo/FluentUI.Demo/FluentUI.Demo.csproj" />
77
</Folder>
88
<Folder Name="/examples/tools/">
9+
<Project Path="examples/Tools/FluentUI.Demo.DocApiGen.Tests/FluentUI.Demo.DocApiGen.Tests.csproj" />
910
<Project Path="examples/Tools/FluentUI.Demo.DocApiGen/FluentUI.Demo.DocApiGen.csproj" />
1011
<Project Path="examples/Tools/FluentUI.Demo.DocViewer.Tests/FluentUI.Demo.DocViewer.Tests.csproj" />
1112
<Project Path="examples/Tools/FluentUI.Demo.DocViewer/FluentUI.Demo.DocViewer.csproj" />
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<LangVersion>latest</LangVersion>
9+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
10+
<NoWarn>$(NoWarn);CS1591</NoWarn>
11+
<IsPackable>false</IsPackable>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" />
16+
<PackageReference Include="xunit.v3" />
17+
<PackageReference Include="xunit.runner.visualstudio">
18+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
19+
<PrivateAssets>all</PrivateAssets>
20+
</PackageReference>
21+
<PackageReference Include="coverlet.msbuild">
22+
<PrivateAssets>all</PrivateAssets>
23+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24+
</PackageReference>
25+
<PackageReference Include="coverlet.collector">
26+
<PrivateAssets>all</PrivateAssets>
27+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
28+
</PackageReference>
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<ProjectReference Include="..\FluentUI.Demo.DocApiGen\FluentUI.Demo.DocApiGen.csproj" />
33+
</ItemGroup>
34+
35+
</Project>
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
// ------------------------------------------------------------------------
2+
// This file is licensed to you under the MIT License.
3+
// ------------------------------------------------------------------------
4+
5+
using Xunit;
6+
using FluentUI.Demo.DocApiGen.Models.McpDocumentation;
7+
8+
namespace FluentUI.Demo.DocApiGen.Tests.Models.McpDocumentation;
9+
10+
/// <summary>
11+
/// Unit tests for <see cref="McpComponentInfo"/>.
12+
/// </summary>
13+
public class McpComponentInfoTests
14+
{
15+
[Fact]
16+
public void Constructor_ShouldInitializeWithDefaults()
17+
{
18+
// Arrange & Act
19+
var component = new McpComponentInfo();
20+
21+
// Assert
22+
Assert.Equal(string.Empty, component.Name);
23+
Assert.Equal(string.Empty, component.FullName);
24+
Assert.Equal(string.Empty, component.Summary);
25+
Assert.Equal(string.Empty, component.Category);
26+
Assert.False(component.IsGeneric);
27+
Assert.Null(component.BaseClass);
28+
Assert.NotNull(component.Properties);
29+
Assert.NotNull(component.Events);
30+
Assert.NotNull(component.Methods);
31+
Assert.Empty(component.Properties);
32+
Assert.Empty(component.Events);
33+
Assert.Empty(component.Methods);
34+
}
35+
36+
[Fact]
37+
public void Name_ShouldBeSettable()
38+
{
39+
// Arrange
40+
var component = new McpComponentInfo();
41+
42+
// Act
43+
component.Name = "FluentButton";
44+
45+
// Assert
46+
Assert.Equal("FluentButton", component.Name);
47+
}
48+
49+
[Fact]
50+
public void FullName_ShouldBeSettable()
51+
{
52+
// Arrange
53+
var component = new McpComponentInfo();
54+
55+
// Act
56+
component.FullName = "Microsoft.FluentUI.AspNetCore.Components.FluentButton";
57+
58+
// Assert
59+
Assert.Equal("Microsoft.FluentUI.AspNetCore.Components.FluentButton", component.FullName);
60+
}
61+
62+
[Fact]
63+
public void Summary_ShouldBeSettable()
64+
{
65+
// Arrange
66+
var component = new McpComponentInfo();
67+
68+
// Act
69+
component.Summary = "A button component";
70+
71+
// Assert
72+
Assert.Equal("A button component", component.Summary);
73+
}
74+
75+
[Fact]
76+
public void Category_ShouldBeSettable()
77+
{
78+
// Arrange
79+
var component = new McpComponentInfo();
80+
81+
// Act
82+
component.Category = "Forms";
83+
84+
// Assert
85+
Assert.Equal("Forms", component.Category);
86+
}
87+
88+
[Fact]
89+
public void IsGeneric_ShouldBeSettable()
90+
{
91+
// Arrange
92+
var component = new McpComponentInfo();
93+
94+
// Act
95+
component.IsGeneric = true;
96+
97+
// Assert
98+
Assert.True(component.IsGeneric);
99+
}
100+
101+
[Fact]
102+
public void BaseClass_ShouldBeSettableToNull()
103+
{
104+
// Arrange
105+
var component = new McpComponentInfo { BaseClass = "SomeBase" };
106+
107+
// Act
108+
component.BaseClass = null;
109+
110+
// Assert
111+
Assert.Null(component.BaseClass);
112+
}
113+
114+
[Fact]
115+
public void BaseClass_ShouldBeSettableToValue()
116+
{
117+
// Arrange
118+
var component = new McpComponentInfo();
119+
120+
// Act
121+
component.BaseClass = "FluentComponentBase";
122+
123+
// Assert
124+
Assert.Equal("FluentComponentBase", component.BaseClass);
125+
}
126+
127+
[Fact]
128+
public void Properties_ShouldBeSettable()
129+
{
130+
// Arrange
131+
var component = new McpComponentInfo();
132+
var properties = new List<McpPropertyInfo>
133+
{
134+
new() { Name = "Appearance", Type = "Appearance?" },
135+
new() { Name = "Disabled", Type = "bool" }
136+
};
137+
138+
// Act
139+
component.Properties = properties;
140+
141+
// Assert
142+
Assert.Same(properties, component.Properties);
143+
Assert.Equal(2, component.Properties.Count);
144+
}
145+
146+
[Fact]
147+
public void Events_ShouldBeSettable()
148+
{
149+
// Arrange
150+
var component = new McpComponentInfo();
151+
var events = new List<McpEventInfo>
152+
{
153+
new() { Name = "OnClick", Type = "EventCallback<MouseEventArgs>" }
154+
};
155+
156+
// Act
157+
component.Events = events;
158+
159+
// Assert
160+
Assert.Same(events, component.Events);
161+
Assert.Single(component.Events);
162+
}
163+
164+
[Fact]
165+
public void Methods_ShouldBeSettable()
166+
{
167+
// Arrange
168+
var component = new McpComponentInfo();
169+
var methods = new List<McpMethodInfo>
170+
{
171+
new() { Name = "Focus", ReturnType = "Task" }
172+
};
173+
174+
// Act
175+
component.Methods = methods;
176+
177+
// Assert
178+
Assert.Same(methods, component.Methods);
179+
Assert.Single(component.Methods);
180+
}
181+
182+
[Fact]
183+
public void CompleteObject_ShouldBeConstructedProperly()
184+
{
185+
// Arrange & Act
186+
var component = new McpComponentInfo
187+
{
188+
Name = "FluentButton",
189+
FullName = "Microsoft.FluentUI.AspNetCore.Components.FluentButton",
190+
Summary = "A button component",
191+
Category = "Forms",
192+
IsGeneric = false,
193+
BaseClass = "FluentComponentBase",
194+
Properties =
195+
[
196+
new McpPropertyInfo { Name = "Appearance", Type = "Appearance?" }
197+
],
198+
Events =
199+
[
200+
new McpEventInfo { Name = "OnClick", Type = "EventCallback<MouseEventArgs>" }
201+
],
202+
Methods =
203+
[
204+
new McpMethodInfo { Name = "Focus", ReturnType = "Task" }
205+
]
206+
};
207+
208+
// Assert
209+
Assert.Equal("FluentButton", component.Name);
210+
Assert.Equal("Microsoft.FluentUI.AspNetCore.Components.FluentButton", component.FullName);
211+
Assert.Equal("A button component", component.Summary);
212+
Assert.Equal("Forms", component.Category);
213+
Assert.False(component.IsGeneric);
214+
Assert.Equal("FluentComponentBase", component.BaseClass);
215+
Assert.Single(component.Properties);
216+
Assert.Single(component.Events);
217+
Assert.Single(component.Methods);
218+
}
219+
220+
[Fact]
221+
public void Collections_CanBeModifiedAfterConstruction()
222+
{
223+
// Arrange
224+
var component = new McpComponentInfo();
225+
226+
// Act
227+
component.Properties.Add(new McpPropertyInfo { Name = "Prop1" });
228+
component.Events.Add(new McpEventInfo { Name = "Event1" });
229+
component.Methods.Add(new McpMethodInfo { Name = "Method1" });
230+
231+
// Assert
232+
Assert.Single(component.Properties);
233+
Assert.Single(component.Events);
234+
Assert.Single(component.Methods);
235+
Assert.Equal("Prop1", component.Properties[0].Name);
236+
Assert.Equal("Event1", component.Events[0].Name);
237+
Assert.Equal("Method1", component.Methods[0].Name);
238+
}
239+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// ------------------------------------------------------------------------
2+
// This file is licensed to you under the MIT License.
3+
// ------------------------------------------------------------------------
4+
5+
using Xunit;
6+
using FluentUI.Demo.DocApiGen.Models.McpDocumentation;
7+
8+
namespace FluentUI.Demo.DocApiGen.Tests.Models.McpDocumentation;
9+
10+
/// <summary>
11+
/// Unit tests for <see cref="McpDocumentationMetadata"/>.
12+
/// </summary>
13+
public class McpDocumentationMetadataTests
14+
{
15+
[Fact]
16+
public void Constructor_ShouldInitializeWithDefaults()
17+
{
18+
// Arrange & Act
19+
var metadata = new McpDocumentationMetadata();
20+
21+
// Assert
22+
Assert.Equal(string.Empty, metadata.AssemblyVersion);
23+
Assert.Equal(string.Empty, metadata.GeneratedDateUtc);
24+
Assert.Equal(0, metadata.ComponentCount);
25+
Assert.Equal(0, metadata.EnumCount);
26+
}
27+
28+
[Fact]
29+
public void AssemblyVersion_ShouldBeSettable()
30+
{
31+
// Arrange
32+
var metadata = new McpDocumentationMetadata();
33+
34+
// Act
35+
metadata.AssemblyVersion = "1.2.3";
36+
37+
// Assert
38+
Assert.Equal("1.2.3", metadata.AssemblyVersion);
39+
}
40+
41+
[Fact]
42+
public void GeneratedDateUtc_ShouldBeSettable()
43+
{
44+
// Arrange
45+
var metadata = new McpDocumentationMetadata();
46+
var date = "2024-12-01T10:30:00Z";
47+
48+
// Act
49+
metadata.GeneratedDateUtc = date;
50+
51+
// Assert
52+
Assert.Equal(date, metadata.GeneratedDateUtc);
53+
}
54+
55+
[Fact]
56+
public void ComponentCount_ShouldBeSettable()
57+
{
58+
// Arrange
59+
var metadata = new McpDocumentationMetadata();
60+
61+
// Act
62+
metadata.ComponentCount = 42;
63+
64+
// Assert
65+
Assert.Equal(42, metadata.ComponentCount);
66+
}
67+
68+
[Fact]
69+
public void EnumCount_ShouldBeSettable()
70+
{
71+
// Arrange
72+
var metadata = new McpDocumentationMetadata();
73+
74+
// Act
75+
metadata.EnumCount = 15;
76+
77+
// Assert
78+
Assert.Equal(15, metadata.EnumCount);
79+
}
80+
81+
[Fact]
82+
public void AllProperties_CanBeSetTogether()
83+
{
84+
// Arrange & Act
85+
var metadata = new McpDocumentationMetadata
86+
{
87+
AssemblyVersion = "2.0.0",
88+
GeneratedDateUtc = "2024-12-01T12:00:00Z",
89+
ComponentCount = 100,
90+
EnumCount = 20
91+
};
92+
93+
// Assert
94+
Assert.Equal("2.0.0", metadata.AssemblyVersion);
95+
Assert.Equal("2024-12-01T12:00:00Z", metadata.GeneratedDateUtc);
96+
Assert.Equal(100, metadata.ComponentCount);
97+
Assert.Equal(20, metadata.EnumCount);
98+
}
99+
}

0 commit comments

Comments
 (0)