Skip to content

Commit

Permalink
cref resolving concept & improve snapshot tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidVollmers committed May 23, 2024
1 parent 75ed57d commit ed286b1
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 15 deletions.
14 changes: 14 additions & 0 deletions Doki.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doki.Output.Json", "src\Dok
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doki.Output.Json.Tests", "tests\Doki.Output.Json.Tests\Doki.Output.Json.Tests.csproj", "{6CCD9EE6-B3FC-485F-9155-553165141B20}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doki.TestAssembly", "tests\assemblies\Doki.TestAssembly\Doki.TestAssembly.csproj", "{0293D689-DFDC-4A78-80D8-BFC11DB0A175}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doki.Tests.Common", "tests\Doki.Tests.Common\Doki.Tests.Common.csproj", "{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -46,6 +50,8 @@ Global
{A89D22B2-2427-4863-A2D9-9E1BEFF37C61} = {568576F3-3D48-459E-B4D2-1790DAE80E7A}
{00BCCBC0-A719-489C-A746-559B4D055B56} = {568576F3-3D48-459E-B4D2-1790DAE80E7A}
{6CCD9EE6-B3FC-485F-9155-553165141B20} = {8C7B5305-B599-4F08-B28B-DD9F1715DD51}
{0293D689-DFDC-4A78-80D8-BFC11DB0A175} = {08041208-BE3D-4BE8-9AF7-806B73985275}
{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC} = {8C7B5305-B599-4F08-B28B-DD9F1715DD51}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6F31B87A-2BD3-4FB4-8C08-7E059A338D4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -96,5 +102,13 @@ Global
{6CCD9EE6-B3FC-485F-9155-553165141B20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CCD9EE6-B3FC-485F-9155-553165141B20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CCD9EE6-B3FC-485F-9155-553165141B20}.Release|Any CPU.Build.0 = Release|Any CPU
{0293D689-DFDC-4A78-80D8-BFC11DB0A175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0293D689-DFDC-4A78-80D8-BFC11DB0A175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0293D689-DFDC-4A78-80D8-BFC11DB0A175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0293D689-DFDC-4A78-80D8-BFC11DB0A175}.Release|Any CPU.Build.0 = Release|Any CPU
{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FA0FF7A-6EDA-4CB1-8D81-2DFB1A4077CC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
5 changes: 5 additions & 0 deletions src/Doki.Abstractions/MemberDocumentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@ public record MemberDocumentation : DocumentationObject
/// </summary>
public XmlDocumentation? Summary { get; set; }

/// <summary>
/// Gets a value indicating whether the type is documented.
/// </summary>
public bool IsDocumented { get; init; }

public new DocumentationContentType ContentType { get; init; }
}
5 changes: 0 additions & 5 deletions src/Doki.Abstractions/TypeDocumentationReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ public record TypeDocumentationReference : MemberDocumentation
/// </summary>
public string FullName { get; init; } = null!;

/// <summary>
/// Gets a value indicating whether the type is documented.
/// </summary>
public bool IsDocumented { get; init; }

/// <summary>
/// Gets a value indicating whether the type is from Microsoft.
/// </summary>
Expand Down
51 changes: 44 additions & 7 deletions src/Doki/DocumentationGenerator.Content.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ private IEnumerable<MemberDocumentation> BuildFieldDocumentation(Type type, Docu
Namespace = field.DeclaringType.Namespace,
Assembly = fieldAssembly.Name,
Parent = parent,
IsDocumented = true
};

if (summary != null)
Expand Down Expand Up @@ -173,6 +174,7 @@ private IEnumerable<MemberDocumentation> BuildConstructorDocumentation(Type type
Namespace = constructor.DeclaringType.Namespace,
Assembly = constructorAssembly.Name,
Parent = parent,
IsDocumented = true
};

if (summary != null)
Expand Down Expand Up @@ -214,6 +216,7 @@ private IEnumerable<MemberDocumentation> BuildPropertyDocumentation(Type type, D
Namespace = property.DeclaringType.Namespace,
Assembly = propertyAssembly.Name,
Parent = parent,
IsDocumented = true
};

if (summary != null)
Expand Down Expand Up @@ -257,6 +260,7 @@ private IEnumerable<MemberDocumentation> BuildMethodDocumentation(Type type, Doc
Namespace = method.DeclaringType.Namespace,
Assembly = methodAssembly.Name,
Parent = parent,
IsDocumented = true
};

if (summary != null)
Expand Down Expand Up @@ -337,13 +341,16 @@ private XmlDocumentation BuildXmlDocumentation(XPathNavigator navigator, Documen

private DocumentationObject BuildCRefDocumentation(string cref, DocumentationObject parent)
{
if (!cref.StartsWith("T:")) throw new ArgumentOutOfRangeException(nameof(cref), cref, "Unsupported cref.");
var parts = cref.Split(':');
if (parts.Length != 2) throw new ArgumentOutOfRangeException(nameof(cref), cref, "Invalid cref format.");

var typeName = cref[2..];
if (!typeName.Contains('.'))
var memberType = parts[0];
var memberName = parts[1];
var typeName = parts[1];
if (memberType != "T")
{
var @namespace = parent.TryGetParent<NamespaceDocumentation>(DocumentationContentType.Namespace);
if (@namespace != null) typeName = $"{@namespace.Id}.{typeName}";
memberName = memberName.Split('.').Last();
typeName = typeName[..typeName.LastIndexOf('.')];
}

var type = LookupType(typeName);
Expand All @@ -352,10 +359,40 @@ private DocumentationObject BuildCRefDocumentation(string cref, DocumentationObj
{
Id = "text",
Parent = parent,
Text = typeName
Text = memberName
};

return BuildTypeDocumentationReference(type, parent);
var typeDocumentationReference = BuildTypeDocumentationReference(type, parent);

switch (memberType)
{
case "T":
return typeDocumentationReference;
case "P":
{
var property = type.GetProperty(memberName, AllMembersBindingFlags);
if (property == null)
return new TextContent
{
Id = "text",
Parent = parent,
Text = memberName
};

return new MemberDocumentation
{
Id = property.GetXmlDocumentationId(),
Name = property.Name,
ContentType = DocumentationContentType.Property,
Namespace = type.Namespace,
Assembly = type.Assembly.GetName().Name,
Parent = typeDocumentationReference,
IsDocumented = PropertyFilter.Expression?.Invoke(property) ?? PropertyFilter.Default(property)
};
}
default:
throw new ArgumentOutOfRangeException(nameof(cref), cref, "Unsupported cref member type.");
}
}

private TypeDocumentationReference BuildTypeDocumentationReference(Type type, DocumentationObject parent)
Expand Down
14 changes: 14 additions & 0 deletions tests/Doki.Tests.Common/Doki.Tests.Common.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
</ItemGroup>

</Project>
29 changes: 29 additions & 0 deletions tests/Doki.Tests.Common/TestOutputLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Extensions.Logging;
using Xunit.Abstractions;

namespace Doki.Tests.Common;

public sealed class TestOutputLogger(ITestOutputHelper output) : ILogger
{
public bool HadError { get; private set; }

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
Func<TState, Exception?, string> formatter)
{
if (logLevel == LogLevel.Error) HadError = true;

output.WriteLine(formatter(state, exception));

if (exception != null) output.WriteLine(exception.ToString());
}

public bool IsEnabled(LogLevel logLevel)
{
return true;
}

public IDisposable? BeginScope<TState>(TState state) where TState : notnull
{
return null;
}
}
2 changes: 2 additions & 0 deletions tests/Doki.Tests.Snapshots/Doki.Tests.Snapshots.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
<ProjectReference Include="..\..\src\Doki\Doki.csproj" />
<ProjectReference Include="..\assemblies\Doki.TestAssembly.ParentRootNamespace\Doki.TestAssembly.ParentRootNamespace.csproj" />
<ProjectReference Include="..\assemblies\Doki.TestAssembly.InheritanceChain\Doki.TestAssembly.InheritanceChain.csproj" />
<ProjectReference Include="..\assemblies\Doki.TestAssembly\Doki.TestAssembly.csproj" />
<ProjectReference Include="..\Doki.Tests.Common\Doki.Tests.Common.csproj" />
</ItemGroup>

</Project>
53 changes: 50 additions & 3 deletions tests/Doki.Tests.Snapshots/SnapshotTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Doki.TestAssembly;
using Doki.TestAssembly.InheritanceChain;
using Doki.TestAssembly.InheritanceChain.Abstractions;
using Microsoft.Extensions.Logging.Abstractions;
using Doki.Tests.Common;
using Xunit.Abstractions;

namespace Doki.Tests.Snapshots;
Expand All @@ -27,9 +27,13 @@ public async Task Test_RootNamespaceIsParentNamespace()
OutputDirectory = snapshot.OutputDirectory
}));

await generator.GenerateAsync(NullLogger.Instance);
var logger = new TestOutputLogger(testOutputHelper);

await generator.GenerateAsync(logger);

await snapshot.SaveIfNotExists().MatchSnapshotAsync(testOutputHelper);

Assert.False(logger.HadError);
}

[Fact]
Expand All @@ -49,8 +53,51 @@ public async Task Test_InheritanceChain()
OutputDirectory = snapshot.OutputDirectory
}));

await generator.GenerateAsync(NullLogger.Instance);
var logger = new TestOutputLogger(testOutputHelper);

await generator.GenerateAsync(logger);

await snapshot.SaveIfNotExists().MatchSnapshotAsync(testOutputHelper);

Assert.False(logger.HadError);
}

[Fact]
public async Task Test_ClassWithPropertyRef()
{
var snapshot = Snapshot.Create();

var emptyDocumentation = new XPathDocument(new StringReader("""
<?xml version="1.0"?>
<doc>
<assembly>
<name>Doki.TestAssembly</name>
</assembly>
<members>
<member name="M:Doki.TestAssembly.ClassWithPropertyRef.Method">
<summary>
Does something with <see cref="P:Doki.TestAssembly.ClassWithPropertyRef.Property"/>.
</summary>
</member>
</members>
</doc>
"""));

var generator = new DocumentationGenerator();

generator.AddAssembly(typeof(ClassWithPropertyRef).Assembly, emptyDocumentation);

generator.AddOutput(new MarkdownOutput(new OutputOptions<MarkdownOutput>
{
OutputDirectory = snapshot.OutputDirectory
}));

var logger = new TestOutputLogger(testOutputHelper);

await generator.GenerateAsync(logger);

await snapshot.SaveIfNotExists().MatchSnapshotAsync(testOutputHelper);

Assert.False(logger.HadError);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Doki.TestAssembly Namespace

## Types



Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Doki.TestAssembly

## Namespaces

- [Doki.TestAssembly](Doki.TestAssembly/README.md)


Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Packages

- [Doki.TestAssembly](Doki.TestAssembly/README.md)



14 changes: 14 additions & 0 deletions tests/assemblies/Doki.TestAssembly/ClassWithPropertyRef.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Doki.TestAssembly;

public class ClassWithPropertyRef

Check warning on line 3 in tests/assemblies/Doki.TestAssembly/ClassWithPropertyRef.cs

View workflow job for this annotation

GitHub Actions / Test

Missing XML comment for publicly visible type or member 'ClassWithPropertyRef'
{
public string? Property { get; set; }

Check warning on line 5 in tests/assemblies/Doki.TestAssembly/ClassWithPropertyRef.cs

View workflow job for this annotation

GitHub Actions / Test

Missing XML comment for publicly visible type or member 'ClassWithPropertyRef.Property'

/// <summary>
/// Does something with <see cref="Property"/>.
/// </summary>
public void Method()
{
var property = Property;
}
}
10 changes: 10 additions & 0 deletions tests/assemblies/Doki.TestAssembly/Doki.TestAssembly.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>

</Project>

0 comments on commit ed286b1

Please sign in to comment.