Skip to content

Commit

Permalink
Added constructor initializer and xml documentation for arguments (#58)
Browse files Browse the repository at this point in the history
Fix #57 
Fix #55
  • Loading branch information
MilleBo authored Jan 24, 2020
1 parent 144abd2 commit c2b9ad1
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using NUnit.Framework;
using Testura.Code.Generators.Class;
using Testura.Code.Generators.Common;
using Testura.Code.Generators.Common.Arguments.ArgumentTypes;
using Testura.Code.Models;
using Attribute = Testura.Code.Models.Attribute;

Expand All @@ -16,6 +17,24 @@ public void Constructor_WhenCreatingConstructor_ShouldGenerateCorrectCode()
Assert.AreEqual("MyClass(){}", ConstructorGenerator.Create("MyClass", BodyGenerator.Create()).ToString());
}

[Test]
public void Constructor_WhenCreatingConstructorWithThisInitializer_ShouldGenerateCorrectCode()
{
Assert.AreEqual("MyClass():this(){}", ConstructorGenerator.Create("MyClass", BodyGenerator.Create(), constructorInitializer: new ConstructorInitializer(ConstructorInitializerTypes.This, null)).ToString());
}

[Test]
public void Constructor_WhenCreatingConstructorWithBaseInitializer_ShouldGenerateCorrectCode()
{
Assert.AreEqual("MyClass():base(){}", ConstructorGenerator.Create("MyClass", BodyGenerator.Create(), constructorInitializer: new ConstructorInitializer(ConstructorInitializerTypes.Base, null)).ToString());
}

[Test]
public void Constructor_WhenCreatingConstructorWithBaseInitializerWithArgument_ShouldGenerateCorrectCode()
{
Assert.AreEqual("MyClass():base(\"myText\"){}", ConstructorGenerator.Create("MyClass", BodyGenerator.Create(), constructorInitializer: new ConstructorInitializer(ConstructorInitializerTypes.Base, new List<Argument> { new ValueArgument("myText")})).ToString());
}

[Test]
public void Constructor_WhenCreatingConstructorWithParameters_ShouldGenerateCorrectCode()
{
Expand Down
17 changes: 17 additions & 0 deletions src/Testura.Code.Tests/Integration/ModelClassTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,22 @@ public void Test_CreateClassWithRegionWithMultipleMembers()
"usingSystem;namespaceModels{publicclassCat{#region MyRegion \nprivatestring_name;privateint_age;publicstringName{get;set;}publicCat(stringname,intage){Name=name;Age=age;}#endregion}}",
@class.ToString());
}

[Test]
public void Test_CreateClassWithMethodThatHaveXmlDocumentation()
{
var classBuilder = new ClassBuilder("Cat", "Models");
var @class = classBuilder
.WithUsings("System")
.WithMethods(new MethodBuilder("MyMethod")
.WithParameters(new Parameter("MyParameter", typeof(string), xmlDocumentation: "Some documentation"))
.WithSummary("Some summary")
.Build())
.Build();

Assert.AreEqual(
"usingSystem;namespaceModels{publicclassCat{/// <summary>\n/// Some summary\n/// </summary>\n/// <param name=\"MyParameter\">Some documentation</param>\nvoidMyMethod(stringMyParameter){}}}",
@class.ToString());
}
}
}
109 changes: 89 additions & 20 deletions src/Testura.Code/Builders/MethodBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class MethodBuilder
private string _summary;

private SyntaxList<AttributeListSyntax> _attributes;
private readonly List<Parameter> _parameterXmlDocumentation;

/// <summary>
/// Initializes a new instance of the <see cref="MethodBuilder"/> class.
Expand All @@ -39,6 +40,7 @@ public MethodBuilder(string name)
_name = name.Replace(" ", "_");
_parameters = new List<ParameterSyntax>();
_modifiers = new List<Modifiers>();
_parameterXmlDocumentation = new List<Parameter>();
_body = BodyGenerator.Create();
}

Expand All @@ -50,9 +52,16 @@ public MethodBuilder(string name)
public MethodBuilder WithParameters(params Parameter[] parameters)
{
_parameters.Clear();
_parameterXmlDocumentation.Clear();

foreach (var parameter in parameters)
{
_parameters.Add(ParameterGenerator.Create(parameter));

if (parameter.XmlDocumentation != null)
{
_parameterXmlDocumentation.Add(parameter);
}
}

return this;
Expand Down Expand Up @@ -183,32 +192,21 @@ private MethodDeclarationSyntax BuildXmlComments(MethodDeclarationSyntax method)
return method;
}

var summary = new List<SyntaxToken>();
summary.Add(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()));
var commentLines = _summary.Split(new[] { "\n" }, StringSplitOptions.None);
for (int n = 0; n < commentLines.Length; n++)
{
var fixedCommentLine = $" {commentLines[n]}";
if (n != commentLines.Length - 1)
{
fixedCommentLine += "\n";
}
var content = List<XmlNodeSyntax>();

summary.Add(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), fixedCommentLine, fixedCommentLine, TriviaList()));
content = CreateSummaryDocumentation(content);

foreach (var parameter in _parameterXmlDocumentation)
{
content = CreateParameterDocumentation(content, parameter);
}

summary.Add(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()));
summary.Add(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), " ", " ", TriviaList()));
content = content.Add(XmlText().WithTextTokens(TokenList(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()))));

var trivia = Trivia(
DocumentationCommentTrivia(
SyntaxKind.SingleLineDocumentationCommentTrivia,
List<XmlNodeSyntax>(new XmlNodeSyntax[]
{
XmlText().WithTextTokens(TokenList(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), " ", " ", TriviaList()))),
XmlElement(XmlElementStartTag(XmlName(Identifier("summary"))), XmlElementEndTag(XmlName(Identifier("summary"))))
.WithContent(SingletonList<XmlNodeSyntax>(XmlText().WithTextTokens(TokenList(summary)))),
XmlText().WithTextTokens(TokenList(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList())))
})));
content));
return method.WithLeadingTrivia(trivia);
}

Expand All @@ -231,5 +229,76 @@ private MethodDeclarationSyntax BuildBody(MethodDeclarationSyntax method)

return method.WithBody(_body);
}

private SyntaxList<XmlNodeSyntax> CreateSummaryDocumentation(SyntaxList<XmlNodeSyntax> content)
{
var summary = new List<SyntaxToken>();
summary.Add(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()));
var commentLines = _summary.Split(new[] { "\n" }, StringSplitOptions.None);
for (int n = 0; n < commentLines.Length; n++)
{
var fixedCommentLine = $" {commentLines[n]}";
if (n != commentLines.Length - 1)
{
fixedCommentLine += "\n";
}

summary.Add(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), fixedCommentLine, fixedCommentLine, TriviaList()));
}

summary.Add(XmlTextNewLine(TriviaList(), "\n", "\n", TriviaList()));
summary.Add(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), " ", " ", TriviaList()));

return content.AddRange(new List<XmlNodeSyntax>
{
XmlText().WithTextTokens(TokenList(XmlTextLiteral(TriviaList(DocumentationCommentExterior("///")), " ", " ", TriviaList()))),
XmlElement(XmlElementStartTag(XmlName(Identifier("summary"))), XmlElementEndTag(XmlName(Identifier("summary"))))
.WithContent(SingletonList<XmlNodeSyntax>(XmlText().WithTextTokens(TokenList(summary)))),
});
}

private SyntaxList<XmlNodeSyntax> CreateParameterDocumentation(SyntaxList<XmlNodeSyntax> content, Parameter parameter)
{
return content.AddRange(new List<XmlNodeSyntax> {
XmlText().WithTextTokens(
TokenList(
new[]
{
XmlTextNewLine(
TriviaList(),
"\n",
"\n",
TriviaList()),
XmlTextLiteral(
TriviaList(
DocumentationCommentExterior("///")),
" ",
" ",
TriviaList())
})),
XmlExampleElement(SingletonList<XmlNodeSyntax>(
XmlText().WithTextTokens(
TokenList(
XmlTextLiteral(
TriviaList(),
parameter.XmlDocumentation,
parameter.XmlDocumentation,
TriviaList())))))
.WithStartTag(XmlElementStartTag(
XmlName(
Identifier("param")))
.WithAttributes(
SingletonList<XmlAttributeSyntax>(
XmlNameAttribute(
XmlName(
Identifier(" name")),
Token(SyntaxKind.DoubleQuoteToken),
IdentifierName(parameter.Name),
Token(SyntaxKind.DoubleQuoteToken)))))
.WithEndTag(
XmlElementEndTag(
XmlName(
Identifier("param")))) });
}
}
}
13 changes: 13 additions & 0 deletions src/Testura.Code/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,17 @@ internal enum AssertType
AreSame,
AreNotSame
}

public enum ConstructorInitializerTypes
{
/// <summary>
/// Generate constructor initializer with <c>Base</c>
/// </summary>
Base,

/// <summary>
/// Generate constructor initializer with <c>This</c>
/// </summary>
This
}
}
13 changes: 11 additions & 2 deletions src/Testura.Code/Generators/Class/ConstructorGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace Testura.Code.Generators.Class
{
/// <summary>
/// Provides functionality to generate class constructors
/// Provides functionality to generate class constructors.
/// </summary>
public static class ConstructorGenerator
{
Expand All @@ -28,7 +28,8 @@ public static ConstructorDeclarationSyntax Create(
BlockSyntax body,
IEnumerable<Parameter> parameters = null,
IEnumerable<Modifiers> modifiers = null,
IEnumerable<Attribute> attributes = null)
IEnumerable<Attribute> attributes = null,
ConstructorInitializer constructorInitializer = null)
{
if (className == null)
{
Expand All @@ -42,6 +43,14 @@ public static ConstructorDeclarationSyntax Create(
constructor = constructor.WithParameterList(ParameterGenerator.Create(parameters.ToArray()));
}

if (constructorInitializer != null)
{
constructor = constructor.WithInitializer(
SyntaxFactory.ConstructorInitializer(
constructorInitializer.ConstructorInitializerType == ConstructorInitializerTypes.Base ? SyntaxKind.BaseConstructorInitializer : SyntaxKind.ThisConstructorInitializer,
constructorInitializer.Arguments == null ? null : ArgumentGenerator.Create(constructorInitializer.Arguments.ToArray())));
}

if (attributes != null)
{
constructor = constructor.WithAttributeLists(AttributeGenerator.Create(attributes.ToArray()));
Expand Down
33 changes: 33 additions & 0 deletions src/Testura.Code/Models/ConstructorInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using Testura.Code.Generators.Common.Arguments.ArgumentTypes;

namespace Testura.Code.Models
{
/// <summary>
/// Represent a constructor initializer.
/// </summary>
public class ConstructorInitializer
{
/// <summary>
/// Initializes a new instance of the <see cref="ConstructorInitializer"/> class.
/// </summary>
/// <param name="constructorInitializerType">Type of constructor initializer.</param>
/// <param name="arguments">Constructor initializer arguments.</param>
public ConstructorInitializer(ConstructorInitializerTypes constructorInitializerType, IEnumerable<Argument> arguments)
{
ConstructorInitializerType = constructorInitializerType;
Arguments = arguments;
}

/// <summary>
/// Gets the constructor initializer type.
/// </summary>
public ConstructorInitializerTypes ConstructorInitializerType { get; }

/// <summary>
/// Gets the constructor initializer arguments.
/// </summary>
public IEnumerable<Argument> Arguments { get; }
}
}
9 changes: 8 additions & 1 deletion src/Testura.Code/Models/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ public class Parameter
/// <param name="name">Name of the paramter.</param>
/// <param name="type">Type of the paramter.</param>
/// <param name="modifier">The paramter modifiers.</param>
public Parameter(string name, Type type, ParameterModifiers modifier = ParameterModifiers.None)
/// <param name="xmlDocumentation">The parameters xml documentation.</param>
public Parameter(string name, Type type, ParameterModifiers modifier = ParameterModifiers.None, string xmlDocumentation = null)
{
if (name == null)
{
Expand All @@ -28,6 +29,7 @@ public Parameter(string name, Type type, ParameterModifiers modifier = Parameter
Name = name;
Type = type;
Modifier = modifier;
XmlDocumentation = xmlDocumentation;
}

/// <summary>
Expand All @@ -44,5 +46,10 @@ public Parameter(string name, Type type, ParameterModifiers modifier = Parameter
/// Gets or sets the parameter modifier.
/// </summary>
public ParameterModifiers Modifier { get; set; }

/// <summary>
/// Gets or sets the xml documentation
/// </summary>
public string XmlDocumentation { get; }
}
}
10 changes: 5 additions & 5 deletions src/Testura.Code/Testura.Code.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.14.0</Version>
<Version>0.15.0</Version>
<Authors>Mille Bostrom</Authors>
<Copyright>Copyright 2016</Copyright>
<Title>$(ProjectName)</Title>
<Description>Testura.Code is a wrapper around the Roslyn API and used for generation, saving and and compiling C# code. It provides methods and helpers to generate classes, methods, statements and expressions.</Description>
<PackageReleaseNotes>
Release 0.14.0:
- Added modifiers for get and set in properties
- Added protected modifier
Release 0.15.0:
- Added support for constructor initializer
- Added xml documentation support for arguments

</PackageReleaseNotes>
<PackageTags>
Expand All @@ -24,7 +24,7 @@
<CodeAnalysisRuleSet>Settings\Testura.ruleset</CodeAnalysisRuleSet>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<AssemblyVersion>0.14.0.0</AssemblyVersion>
<AssemblyVersion>0.15.0.0</AssemblyVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

Expand Down

0 comments on commit c2b9ad1

Please sign in to comment.