From a55df75894c70503cb636832abbcbbba946599a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mille=20Bostr=C3=B6m?= Date: Tue, 6 Aug 2019 11:09:52 +0200 Subject: [PATCH] Release 0.11.0 (#37) * Added interface builder * Changed method builder so it add a semicolon if you set body to null --- .../Builders/ClassBuilderTests.cs | 1 - .../Builders/InterfaceBuilderTests.cs | 64 +++++ .../Builders/MethodBuildersTest.cs | 19 +- .../Testura.Code.Tests.csproj | 1 + src/Testura.Code/Builders/ClassBuilder.cs | 207 +--------------- src/Testura.Code/Builders/InterfaceBuilder.cs | 45 ++++ src/Testura.Code/Builders/MethodBuilder.cs | 7 +- src/Testura.Code/Builders/TypeBuilderBase.cs | 228 ++++++++++++++++++ src/Testura.Code/Testura.Code.csproj | 7 +- src/Testura.Code/Testura.Code.nuspec | 18 +- src/Testura.Code/packages.config | 2 +- 11 files changed, 380 insertions(+), 219 deletions(-) create mode 100644 src/Testura.Code.Tests/Builders/InterfaceBuilderTests.cs create mode 100644 src/Testura.Code/Builders/InterfaceBuilder.cs create mode 100644 src/Testura.Code/Builders/TypeBuilderBase.cs diff --git a/src/Testura.Code.Tests/Builders/ClassBuilderTests.cs b/src/Testura.Code.Tests/Builders/ClassBuilderTests.cs index 3926412..b23648d 100644 --- a/src/Testura.Code.Tests/Builders/ClassBuilderTests.cs +++ b/src/Testura.Code.Tests/Builders/ClassBuilderTests.cs @@ -64,7 +64,6 @@ public void Build_WhenGivenModifiers_CodeShouldContainModifiers() [Test] public void Build_WhenGivenInheritance_CodeShouldContainInheritance() { - var o = _classBuilder.ThatInheritFrom(typeof(int)).Build().ToString(); Assert.IsTrue(_classBuilder.ThatInheritFrom(typeof(int)).Build().ToString().Contains("TestClass:int")); } } diff --git a/src/Testura.Code.Tests/Builders/InterfaceBuilderTests.cs b/src/Testura.Code.Tests/Builders/InterfaceBuilderTests.cs new file mode 100644 index 0000000..c66d8e7 --- /dev/null +++ b/src/Testura.Code.Tests/Builders/InterfaceBuilderTests.cs @@ -0,0 +1,64 @@ +using NUnit.Framework; +using Testura.Code.Builders; +using Testura.Code.Models; +using Testura.Code.Models.Properties; + +namespace Testura.Code.Tests.Builders +{ + [TestFixture] + public class InterfaceBuilderTests + { + private InterfaceBuilder _interfaceBuilder; + + [SetUp] + public void SetUp() + { + _interfaceBuilder = new InterfaceBuilder("TestInterface", "MyNamespace"); + } + + [Test] + public void Build_WhenGivenClassName_CodeShouldContainClassName() + { + Assert.IsTrue(_interfaceBuilder.Build().ToString().Contains("TestInterface")); + } + + [Test] + public void Build_WhenGivenNamespace_CodeShouldContainNamespace() + { + Assert.IsTrue(_interfaceBuilder.Build().ToString().Contains("MyNamespace")); + } + + [Test] + public void Build_WhenGivenAttributes_CodeShouldContainAttributes() + { + Assert.IsTrue(_interfaceBuilder.WithAttributes(new Attribute("MyAttribute")).Build().ToString().Contains("[MyAttribute]")); + } + + + [Test] + public void Build_WhenGivenProperty_CodeShouldContainProperty() + { + Assert.IsTrue(_interfaceBuilder.WithProperties(new AutoProperty("MyProperty", typeof(int), PropertyTypes.GetAndSet)).Build().ToString().Contains("intMyProperty{get;set;}")); + } + + [Test] + public void Build_WhenGivenUsing_CodeShouldContainUsing() + { + Assert.IsTrue(_interfaceBuilder.WithUsings("some.namespace").Build().ToString().Contains("some.namespace")); + } + + + [Test] + public void Build_WhenGivenModifiers_CodeShouldContainModifiers() + { + Assert.IsTrue(_interfaceBuilder.WithModifiers(Modifiers.Public, Modifiers.Abstract).Build().ToString().Contains("publicabstractinterfaceTestInterface")); + } + + [Test] + public void Build_WhenGivenInheritance_CodeShouldContainInheritance() + { + var o = _interfaceBuilder.ThatInheritFrom(typeof(int)).Build().ToString(); + Assert.IsTrue(_interfaceBuilder.ThatInheritFrom(typeof(int)).Build().ToString().Contains("TestInterface:int")); + } + } +} diff --git a/src/Testura.Code.Tests/Builders/MethodBuildersTest.cs b/src/Testura.Code.Tests/Builders/MethodBuildersTest.cs index 41e0b19..ce67913 100644 --- a/src/Testura.Code.Tests/Builders/MethodBuildersTest.cs +++ b/src/Testura.Code.Tests/Builders/MethodBuildersTest.cs @@ -18,28 +18,32 @@ public void Build_WhenGivingMethodName_CodeShouldContainName() public void Build_WhenGivingAttribute_CodeShouldContainAttribute() { var builder = new MethodBuilder("MyMethod"); - Assert.IsTrue(builder.WithAttributes(new Attribute("MyAttribute")).Build().ToString().Contains("[MyAttribute]")); + Assert.IsTrue(builder.WithAttributes(new Attribute("MyAttribute")).Build().ToString() + .Contains("[MyAttribute]")); } [Test] public void Build_WhenGivingModifier_CodeShouldContainModifiers() { var builder = new MethodBuilder("MyMethod"); - Assert.IsTrue(builder.WithModifiers(Modifiers.Public, Modifiers.Abstract).Build().ToString().Contains("publicabstract")); + Assert.IsTrue(builder.WithModifiers(Modifiers.Public, Modifiers.Abstract).Build().ToString() + .Contains("publicabstract")); } [Test] public void Build_WhenGivingParameters_CodeShouldContainParamters() { var builder = new MethodBuilder("MyMethod"); - Assert.IsTrue(builder.WithParameters(new Parameter("myParamter", typeof(int))).Build().ToString().Contains("intmyParamter")); + Assert.IsTrue(builder.WithParameters(new Parameter("myParamter", typeof(int))).Build().ToString() + .Contains("intmyParamter")); } [Test] public void Build_WhenGivingParameterWithModifier_CodeShouldContainParamters() { var builder = new MethodBuilder("MyMethod"); - Assert.IsTrue(builder.WithParameters(new Parameter("myParamter", typeof(int), ParameterModifiers.This)).Build().ToString().Contains("thisintmyParamter")); + Assert.IsTrue(builder.WithParameters(new Parameter("myParamter", typeof(int), ParameterModifiers.This)) + .Build().ToString().Contains("thisintmyParamter")); } [Test] @@ -48,5 +52,12 @@ public void Build_WhenGivingReturnType_CodeShouldContainReturn() var builder = new MethodBuilder("MyMethod"); Assert.IsTrue(builder.WithReturnType(typeof(int)).Build().ToString().Contains("intMyMethod()")); } + + [Test] + public void Build_WhenGivingNullBody_CodeShouldContainMethodWithSemicolonAtTheEnd() + { + var builder = new MethodBuilder("MyMethod"); + Assert.IsTrue(builder.WithBody(null).Build().ToString().Contains("MyMethod();")); + } } } diff --git a/src/Testura.Code.Tests/Testura.Code.Tests.csproj b/src/Testura.Code.Tests/Testura.Code.Tests.csproj index 4b9d1b4..a94fea7 100644 --- a/src/Testura.Code.Tests/Testura.Code.Tests.csproj +++ b/src/Testura.Code.Tests/Testura.Code.Tests.csproj @@ -234,6 +234,7 @@ + diff --git a/src/Testura.Code/Builders/ClassBuilder.cs b/src/Testura.Code/Builders/ClassBuilder.cs index 6162613..eccb1f3 100644 --- a/src/Testura.Code/Builders/ClassBuilder.cs +++ b/src/Testura.Code/Builders/ClassBuilder.cs @@ -1,117 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Testura.Code.Generators.Class; -using Testura.Code.Generators.Common; using Testura.Code.Models; -using Testura.Code.Models.Properties; -using Attribute = Testura.Code.Models.Attribute; namespace Testura.Code.Builders { /// /// Provides a builder to generate a class /// - public class ClassBuilder + public class ClassBuilder : TypeBuilderBase { - private readonly string _name; - private readonly string _namespace; - private readonly List _usings; - private readonly List _modifiers; - private readonly List _methods; - private readonly List _inheritance; private readonly List _fields; - private readonly List _properties; private ConstructorDeclarationSyntax _constructor; - private SyntaxList _attributes; - /// /// Initializes a new instance of the class. /// /// Name of the class. /// Name of the class namespace. public ClassBuilder(string name, string @namespace) + : base(name, @namespace) { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentException("Value cannot be null or empty.", nameof(name)); - } - - if (string.IsNullOrEmpty(@namespace)) - { - throw new ArgumentException("Value cannot be null or empty.", nameof(@namespace)); - } - - _name = name.Replace(" ", "_"); - _namespace = @namespace; - _methods = new List(); - _inheritance = new List(); - _modifiers = new List { Modifiers.Public }; _fields = new List(); - _properties = new List(); - _usings = new List(); - } - - /// - /// Set the using directives. - /// - /// A set of wanted using directive names. - /// The current class builder - public ClassBuilder WithUsings(params string[] usings) - { - _usings.Clear(); - _usings.AddRange(usings); - return this; - } - - /// - /// Set class modifiers - /// - /// A set of wanted modifiers. - /// The current class builder - public ClassBuilder WithModifiers(params Modifiers[] modifier) - { - _modifiers.Clear(); - _modifiers.AddRange(modifier); - return this; - } - - /// - /// Set type(s) that the generated class should inherit from. - /// - /// A set of types to inherit from. - /// The current class builder - public ClassBuilder ThatInheritFrom(params Type[] types) - { - _inheritance.Clear(); - _inheritance.AddRange(types); - return this; - } - - /// - /// Set class attributes. - /// - /// A set of wanted attributes. - /// The current class builder - public ClassBuilder WithAttributes(params Attribute[] attributes) - { - _attributes = AttributeGenerator.Create(attributes); - return this; - } - - /// - /// Set class attributes. - /// - /// A syntax list of already generated attributes. - /// The current class builder - public ClassBuilder WithAttributes(SyntaxList attributes) - { - _attributes = attributes; - return this; } /// @@ -153,46 +65,6 @@ public ClassBuilder WithConstructor(ConstructorDeclarationSyntax constructor) return this; } - /// - /// Set class methods. - /// - /// A set of already generated methods - /// The current class builder - public ClassBuilder WithMethods(params MethodDeclarationSyntax[] methods) - { - _methods.Clear(); - _methods.AddRange(methods); - return this; - } - - /// - /// Set class properties. - /// - /// A set of wanted properties. - /// The current class builder - public ClassBuilder WithProperties(params Property[] properties) - { - _properties.Clear(); - foreach (var property in properties) - { - _properties.Add(PropertyGenerator.Create(property)); - } - - return this; - } - - /// - /// A class properties. - /// - /// A sete of already generated properties - /// The current class builder - public ClassBuilder WithProperties(params PropertyDeclarationSyntax[] properties) - { - _properties.Clear(); - _properties.AddRange(properties); - return this; - } - /// /// Build the class and return the generated code. /// @@ -208,67 +80,16 @@ public CompilationUnitSyntax Build() @class = BuildAttributes(@class); @class = @class.WithMembers(members); var @base = SyntaxFactory.CompilationUnit(); - @base = BuildUsing(@base); - @base = @base.AddMembers(SyntaxFactory.NamespaceDeclaration(SyntaxFactory.IdentifierName(_namespace)).AddMembers(@class)); + @base = BuildUsings(@base); + @base = BuildNamespace(@base, @class); return @base; } - private CompilationUnitSyntax BuildUsing(CompilationUnitSyntax @base) - { - var usingSyntaxes = default(SyntaxList); - foreach (var @using in _usings) - { - if (@using == null) - { - continue; - } - - usingSyntaxes = usingSyntaxes.Add(SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName(@using))); - } - - foreach (var @using in usingSyntaxes) - { - @base = @base.AddUsings(@using); - } - - return @base; - } - - private ClassDeclarationSyntax BuildClassBase() - { - if (_inheritance.Any()) - { - var syntaxNodeOrToken = new SyntaxNodeOrToken[(_inheritance.Count * 2) - 1]; - for (int n = 0; n < (_inheritance.Count * 2) - 1; n += 2) - { - syntaxNodeOrToken[n] = SyntaxFactory.SimpleBaseType(TypeGenerator.Create(_inheritance[n])); - if (n + 1 < _inheritance.Count - 1) - { - syntaxNodeOrToken[n + 1] = SyntaxFactory.Token(SyntaxKind.CommaToken); - } - } - - return SyntaxFactory.ClassDeclaration(_name).WithBaseList(SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(syntaxNodeOrToken))).WithModifiers(ModifierGenerator.Create(_modifiers.ToArray())); - } - - return SyntaxFactory.ClassDeclaration(_name).WithModifiers(ModifierGenerator.Create(_modifiers.ToArray())); - } - - private ClassDeclarationSyntax BuildAttributes(ClassDeclarationSyntax @class) - { - return @class.WithAttributeLists(_attributes); - } - private SyntaxList BuildFields(SyntaxList members) { return AddMembers(members, _fields); } - private SyntaxList BuildProperties(SyntaxList members) - { - return AddMembers(members, _properties); - } - private SyntaxList BuildConstructor(SyntaxList members) { if (_constructor == null) @@ -279,24 +100,10 @@ private SyntaxList BuildConstructor(SyntaxList(_constructor)); } - private SyntaxList BuildMethods(SyntaxList members) - { - return AddMembers(members, _methods); - } - private SyntaxList AddMembers(SyntaxList members, IEnumerable memberDeclarationSyntaxs) + private TypeDeclarationSyntax BuildClassBase() { - if (!memberDeclarationSyntaxs.Any()) - { - return members; - } - - foreach (var memberDeclarationSyntax in memberDeclarationSyntaxs) - { - members = members.Add(memberDeclarationSyntax); - } - - return members; + return SyntaxFactory.ClassDeclaration(Name).WithBaseList(CreateBaseList()).WithModifiers(CreateModifiers()); } } } diff --git a/src/Testura.Code/Builders/InterfaceBuilder.cs b/src/Testura.Code/Builders/InterfaceBuilder.cs new file mode 100644 index 0000000..2c60dec --- /dev/null +++ b/src/Testura.Code/Builders/InterfaceBuilder.cs @@ -0,0 +1,45 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Testura.Code.Builders +{ + /// + /// Provides a builder to generate an interface + /// + public class InterfaceBuilder : TypeBuilderBase + { + /// + /// Initializes a new instance of the class. + /// + /// Name of the interface. + /// Name of the interface namespace. + public InterfaceBuilder(string name, string @namespace) + : base(name, @namespace) + { + } + + /// + /// Build the interface and return the generated code. + /// + /// The generated class. + public CompilationUnitSyntax Build() + { + var members = default(SyntaxList); + members = BuildProperties(members); + members = BuildMethods(members); + var @interface = BuildInterfaceBase(); + @interface = BuildAttributes(@interface); + @interface = @interface.WithMembers(members); + var @base = SyntaxFactory.CompilationUnit(); + @base = BuildUsings(@base); + @base = BuildNamespace(@base, @interface); + return @base; + } + + private TypeDeclarationSyntax BuildInterfaceBase() + { + return SyntaxFactory.InterfaceDeclaration(Name).WithBaseList(CreateBaseList()).WithModifiers(CreateModifiers()); + } + } +} diff --git a/src/Testura.Code/Builders/MethodBuilder.cs b/src/Testura.Code/Builders/MethodBuilder.cs index bad8c98..a16932e 100644 --- a/src/Testura.Code/Builders/MethodBuilder.cs +++ b/src/Testura.Code/Builders/MethodBuilder.cs @@ -224,7 +224,12 @@ private MethodDeclarationSyntax BuildParameters(MethodDeclarationSyntax method) private MethodDeclarationSyntax BuildBody(MethodDeclarationSyntax method) { - return _body == null ? method : method.WithBody(_body); + if (_body == null) + { + return method.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); + } + + return method.WithBody(_body); } } } diff --git a/src/Testura.Code/Builders/TypeBuilderBase.cs b/src/Testura.Code/Builders/TypeBuilderBase.cs new file mode 100644 index 0000000..a4829f7 --- /dev/null +++ b/src/Testura.Code/Builders/TypeBuilderBase.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Testura.Code.Generators.Class; +using Testura.Code.Generators.Common; +using Testura.Code.Models.Properties; +using Attribute = Testura.Code.Models.Attribute; + +namespace Testura.Code.Builders +{ + public abstract class TypeBuilderBase + where TBuilder : TypeBuilderBase + { + private readonly string _namespace; + private readonly List _methods; + private readonly List _inheritance; + private SyntaxList _attributes; + private readonly List _properties; + + private readonly List _usings; + private readonly List _modifiers; + + protected TypeBuilderBase(string name, string @namespace) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException("Value cannot be null or empty.", nameof(name)); + } + + if (string.IsNullOrEmpty(@namespace)) + { + throw new ArgumentException("Value cannot be null or empty.", nameof(@namespace)); + } + + Name = name.Replace(" ", "_"); + _namespace = @namespace; + _methods = new List(); + _inheritance = new List(); + _modifiers = new List { Modifiers.Public }; + _usings = new List(); + _properties = new List(); + } + + protected string Name { get; } + + /// + /// Set the using directives. + /// + /// A set of wanted using directive names. + /// The current builder + public TBuilder WithUsings(params string[] usings) + { + _usings.Clear(); + _usings.AddRange(usings); + return (TBuilder)this; + } + + /// + /// Set class modifiers + /// + /// A set of wanted modifiers. + /// The current builder + public TBuilder WithModifiers(params Modifiers[] modifier) + { + _modifiers.Clear(); + _modifiers.AddRange(modifier); + return (TBuilder)this; + } + + /// + /// Set type(s) that the generated class should inherit from. + /// + /// A set of types to inherit from. + /// The current builder + public TBuilder ThatInheritFrom(params Type[] types) + { + _inheritance.Clear(); + _inheritance.AddRange(types); + return (TBuilder)this; + } + + /// + /// Set class attributes. + /// + /// A syntax list of already generated attributes. + /// The current builder + public TBuilder WithAttributes(SyntaxList attributes) + { + _attributes = attributes; + return (TBuilder)this; + } + + /// + /// Set class attributes. + /// + /// A set of wanted attributes. + /// The current builder + public TBuilder WithAttributes(params Attribute[] attributes) + { + _attributes = AttributeGenerator.Create(attributes); + return (TBuilder)this; + } + + /// + /// Set class methods. + /// + /// A set of already generated methods + /// The current class builder + public TBuilder WithMethods(params MethodDeclarationSyntax[] methods) + { + _methods.Clear(); + _methods.AddRange(methods); + return (TBuilder)this; + } + + /// + /// Set class properties. + /// + /// A set of wanted properties. + /// The current builder + public TBuilder WithProperties(params Property[] properties) + { + _properties.Clear(); + foreach (var property in properties) + { + _properties.Add(PropertyGenerator.Create(property)); + } + + return (TBuilder)this; + } + + /// + /// A class properties. + /// + /// A sete of already generated properties + /// The current builder + public TBuilder WithProperties(params PropertyDeclarationSyntax[] properties) + { + _properties.Clear(); + _properties.AddRange(properties); + return (TBuilder)this; + } + + protected CompilationUnitSyntax BuildUsings(CompilationUnitSyntax @base) + { + var usingSyntaxes = default(SyntaxList); + foreach (var @using in _usings) + { + if (@using == null) + { + continue; + } + + usingSyntaxes = usingSyntaxes.Add(SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName(@using))); + } + + foreach (var @using in usingSyntaxes) + { + @base = @base.AddUsings(@using); + } + + return @base; + } + + protected SyntaxList BuildProperties(SyntaxList members) + { + return AddMembers(members, _properties); + } + + protected SyntaxList BuildMethods(SyntaxList members) + { + return AddMembers(members, _methods); + } + + protected TypeDeclarationSyntax BuildAttributes(TypeDeclarationSyntax @class) + { + return @class.WithAttributeLists(_attributes); + } + + protected CompilationUnitSyntax BuildNamespace(CompilationUnitSyntax @base, TypeDeclarationSyntax @interface) + { + return @base.AddMembers(SyntaxFactory.NamespaceDeclaration(SyntaxFactory.IdentifierName(_namespace)).AddMembers(@interface)); + } + + protected SyntaxTokenList CreateModifiers() + { + return ModifierGenerator.Create(_modifiers.ToArray()); + } + + protected BaseListSyntax CreateBaseList() + { + if (!_inheritance.Any()) + { + return null; + } + + var syntaxNodeOrToken = new SyntaxNodeOrToken[(_inheritance.Count * 2) - 1]; + for (int n = 0; n < (_inheritance.Count * 2) - 1; n += 2) + { + syntaxNodeOrToken[n] = SyntaxFactory.SimpleBaseType(TypeGenerator.Create(_inheritance[n])); + if (n + 1 < _inheritance.Count - 1) + { + syntaxNodeOrToken[n + 1] = SyntaxFactory.Token(SyntaxKind.CommaToken); + } + } + + return SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(syntaxNodeOrToken)); + } + + protected SyntaxList AddMembers(SyntaxList members, IEnumerable memberDeclarationSyntaxs) + { + if (!memberDeclarationSyntaxs.Any()) + { + return members; + } + + foreach (var memberDeclarationSyntax in memberDeclarationSyntaxs) + { + members = members.Add(memberDeclarationSyntax); + } + + return members; + } + } +} diff --git a/src/Testura.Code/Testura.Code.csproj b/src/Testura.Code/Testura.Code.csproj index 74e398b..a43d494 100644 --- a/src/Testura.Code/Testura.Code.csproj +++ b/src/Testura.Code/Testura.Code.csproj @@ -222,11 +222,13 @@ + + @@ -309,9 +311,8 @@ - - - + + diff --git a/src/Testura.Code/Testura.Code.nuspec b/src/Testura.Code/Testura.Code.nuspec index 2b74127..30dd3f4 100644 --- a/src/Testura.Code/Testura.Code.nuspec +++ b/src/Testura.Code/Testura.Code.nuspec @@ -2,24 +2,24 @@ $id$ - 0.7.0 + 0.11.0 $title$ - Mille Boström - Mille Boström + Mille Bostrom + Mille Bostrom https://opensource.org/licenses/MIT https://github.com/Testura/Testura.Code - http://testura.net/Content/Images/logo128-new.png + https://i.ibb.co/nnSPd11/logo128-new.png true 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. - Release 0.7.0: - - Added support for attributes on fields - - Fixed named arguments in attributes + Release 0.11.0: + - Added interface builder + - Changed method builder so it add a semicolon if you set body to null Copyright 2016 Code generation roslyn - - + + diff --git a/src/Testura.Code/packages.config b/src/Testura.Code/packages.config index 4de2ab3..56cd760 100644 --- a/src/Testura.Code/packages.config +++ b/src/Testura.Code/packages.config @@ -12,7 +12,7 @@ - +