diff --git a/EasyCodeBuilder.Test/Csharp/ReadmeExamplesVerificationTests.cs b/EasyCodeBuilder.Test/Csharp/ReadmeExamplesVerificationTests.cs new file mode 100644 index 0000000..2b1f117 --- /dev/null +++ b/EasyCodeBuilder.Test/Csharp/ReadmeExamplesVerificationTests.cs @@ -0,0 +1,295 @@ +using System; +using Fengb3.EasyCodeBuilder.Csharp; +using Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations; +using Xunit.Abstractions; + +namespace EasyCodeBuilder.Test.Csharp; + +/// +/// Tests to verify that the README examples work correctly +/// +public class ReadmeExamplesVerificationTests +{ + private readonly ITestOutputHelper _testOutputHelper; + public ReadmeExamplesVerificationTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + [Fact] + public void TestBasicUsageExample() + { + // This verifies the "Basic Usage" example in README + var code = Code.Create() + .Using("System") + .Namespace(ns => { + ns.Name = "MyProject"; + ns.Public.Class(cls => { + cls.WithName("Person"); + cls.Public.AutoProperty(p => p + .WithType("string") + .WithName("Name") + ); + cls.Public.AutoProperty(p => p + .WithType("int") + .WithName("Age") + ); + }); + }) + .Build(); + + const string expected = + """ + using System; + + namespace MyProject + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } + + [Fact] + public void TestGenerateClassWithMethodsExample() + { + // This verifies the "Generate a Class with Methods" example in README + var code = Code.Create() + .Using("System") + .Namespace(ns => { + ns.Name = "MyApp"; + ns.Public.Class(cls => { + cls.WithName("Calculator"); + cls.Public.Method(method => { + method.WithName("Add") + .WithReturnType("int") + .WithParameters("int a", "int b") + .AppendLine("return a + b;"); + }); + }); + }) + .Build(); + + const string expected = + """ + using System; + + namespace MyApp + { + public class Calculator + { + public int Add(int a, int b) + { + return a + b; + } + } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } + + [Fact] + public void TestKeywordConfiguratorPublicClassExample() + { + // This verifies the first "Using Keyword Configurator" example in README + var @namespace = new NamespaceOption() + .WithName("MyNamespace") + .Public.Class(cls => { + cls.WithName("MyClass"); + }); + + var code = @namespace.Build(); + + const string expected = + """ + namespace MyNamespace + { + public class MyClass + { + } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } + + [Fact] + public void TestKeywordConfiguratorAutoPropertyExample() + { + // This verifies the second "Using Keyword Configurator" example in README + var @class = Code.Create() + .Class(cls => cls + .WithName("MyClass") + .Public.AutoProperty(prop => prop + .WithName("MyProperty") + .WithType(typeof(int).FullName ?? "int") + ) + ); + + var classCode = @class.Build(); + + const string expected = + """ + class MyClass + { + public System.Int32 MyProperty { get; set; } + } + """; + + Assert.Equal(expected.Trim(), classCode.Trim()); + _testOutputHelper.WriteLine(classCode); + } + + [Fact] + public void TestUsingConstructorsExample() + { + // This verifies the "Using Constructors" example in README + var classOption = new TypeOption() + .WithTypeKind(TypeOption.Type.Class) + .WithName("Person") + .WithKeyword("public"); + + classOption.Constructor(ctor => { + ctor.WithKeyword("public") + .WithParameter("string name") + .WithParameter("int age") + .AppendLine("Name = name;") + .AppendLine("Age = age;"); + }); + + classOption.Public.AutoProperty(p => p + .WithType("string") + .WithName("Name")); + + classOption.Public.AutoProperty(p => p + .WithType("int") + .WithName("Age")); + + var code = classOption.Build(); + + const string expected = + """ + public class Person + { + public Person(string name, int age) + { + Name = name; + Age = age; + } + public string Name { get; set; } + public int Age { get; set; } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } + + [Fact] + public void TestControlStructuresForLoopExample() + { + // This verifies the "Control Structures - For Loop" example in README + var classOption = new TypeOption() + .WithTypeKind(TypeOption.Type.Class) + .WithName("NumberPrinter"); + + classOption.Public.Method(method => { + method.WithName("PrintNumbers") + .WithReturnType("void") + .For(@for => { + @for.WithInitializer("int i = 0") + .WithCondition("i < 10") + .WithIterator("i++") + .AppendLine("Console.WriteLine(i);"); + }); + }); + + var code = classOption.Build(); + + const string expected = + """ + class NumberPrinter + { + public void PrintNumbers() + { + for (int i = 0; i < 10; i++) + { + Console.WriteLine(i); + } + } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } + + [Fact] + public void TestControlStructuresSwitchStatementExample() + { + // This verifies the "Control Structures - Switch Statement" example in README + var classOption = new TypeOption() + .WithTypeKind(TypeOption.Type.Class) + .WithName("DayHelper"); + + classOption.Public.Method(method => { + method.WithName("GetDayName") + .WithReturnType("string") + .WithParameters("int day"); + + method.Switch(@switch => { + @switch.Expression = "day"; + @switch.Case(@case => { + @case.Value = "1"; + @case.AppendLine("return \"Monday\";"); + }); + @switch.Case(@case => { + @case.Value = "2"; + @case.AppendLine("return \"Tuesday\";"); + }); + @switch.Default(@default => + @default.AppendLine("return \"Unknown\";") + ); + }); + }); + + var code = classOption.Build(); + + const string expected = + """ + class DayHelper + { + public string GetDayName(int day) + { + switch (day) + { + case 1: + { + return "Monday"; + } + case 2: + { + return "Tuesday"; + } + default: + { + return "Unknown"; + } + } + } + } + """; + + Assert.Equal(expected.Trim(), code.Trim()); + _testOutputHelper.WriteLine(code); + } +} diff --git a/README.md b/README.md index 1031055..cb11f55 100644 --- a/README.md +++ b/README.md @@ -39,18 +39,16 @@ var code = Create() .Using("System") .Namespace(ns => { ns.Name = "MyProject"; - ns.Class(cls => { - cls.Name = "Person"; - cls.AutoProperty(p => { - p.WithKeyword("public") - .WithType("string") - .WithName("Name"); - }); - cls.AutoProperty(p => { - p.WithKeyword("public") - .WithType("int") - .WithName("Age"); - }); + ns.Public.Class(cls => { + cls.WithName("Person"); + cls.Public.AutoProperty(p => p + .WithType("string") + .WithName("Name") + ); + cls.Public.AutoProperty(p => p + .WithType("int") + .WithName("Age") + ); }); }) .Build(); @@ -111,12 +109,10 @@ var code = Create() .Using("System") .Namespace(ns => { ns.Name = "MyApp"; - ns.Class(cls => { - cls.Name = "Calculator"; - cls.WithKeyword("public"); - cls.Method(method => { + ns.Public.Class(cls => { + cls.WithName("Calculator"); + cls.Public.Method(method => { method.WithName("Add") - .WithKeyword("public") .WithReturnType("int") .WithParameters("int a", "int b") .AppendLine("return a + b;"); @@ -148,34 +144,112 @@ namespace MyApp -### Using Constructors +### Using Keyword Configurator + +The new `KeywordOptionConfigurator` API provides a fluent way to specify access modifiers and other keywords. Note: You need to import `Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations` to use these extension methods.
**API Calling**: ```csharp +using Fengb3.EasyCodeBuilder.Csharp; +using Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations; + +var @namespace = new NamespaceOption() + .WithName("MyNamespace") + .Public.Class(cls => { + cls.WithName("MyClass"); + }); + +var code = @namespace.Build(); +``` + +
+
+ +**Generated Code**: +```csharp +namespace MyNamespace +{ + public class MyClass + { + } +} +``` + +
+
+ +You can also use the keyword configurator with auto-properties: + +
+
+ +**API Calling**: +```csharp +using Fengb3.EasyCodeBuilder.Csharp; using static Fengb3.EasyCodeBuilder.Csharp.Code; +var @class = Create() + .Class(cls => cls + .WithName("MyClass") + .Public.AutoProperty(prop => prop + .WithName("MyProperty") + .WithType(typeof(int).FullName ?? "int") + ) + ); + +var classCode = @class.Build(); +``` + +
+
+ +**Generated Code**: +```csharp +class MyClass +{ + public System.Int32 MyProperty { get; set; } +} +``` + +
+
+ +### Using Constructors + +
+
+ +**API Calling**: +```csharp +using Fengb3.EasyCodeBuilder.Csharp; +using Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations; + +// Create a public class using KeywordConfigurator approach var classOption = new TypeOption() .WithTypeKind(TypeOption.Type.Class) .WithName("Person") - .WithKeyword("public") - .Constructor(ctor => { - ctor.WithKeyword("public") - .WithParameter("string name") // WithParameter for constructors - .WithParameter("int age") // WithParameter for constructors - .AppendLine("Name = name;") - .AppendLine("Age = age;"); - }) - .AutoProperty(p => p - .WithKeyword("public") - .WithType("string") - .WithName("Name")) - .AutoProperty(p => p - .WithKeyword("public") - .WithType("int") - .WithName("Age")); + .WithKeyword("public"); // TypeOption's public keyword + +// Add constructor (note: Constructor doesn't support KeywordConfigurator yet) +classOption.Constructor(ctor => { + ctor.WithKeyword("public") + .WithParameter("string name") + .WithParameter("int age") + .AppendLine("Name = name;") + .AppendLine("Age = age;"); +}); + +// Use KeywordConfigurator for properties +classOption.Public.AutoProperty(p => p + .WithType("string") + .WithName("Name")); + +classOption.Public.AutoProperty(p => p + .WithType("int") + .WithName("Age")); var code = classOption.Build(); ``` @@ -207,20 +281,26 @@ public class Person **API Calling**: ```csharp -using static Fengb3.EasyCodeBuilder.Csharp.Code; +using Fengb3.EasyCodeBuilder.Csharp; +using Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations; -var method = new MethodOption() - .WithName("PrintNumbers") - .WithReturnType("void") - .WithKeyword("public") - .For(@for => { - @for.WithInitializer("int i = 0") - .WithCondition("i < 10") - .WithIterator("i++") - .AppendLine("Console.WriteLine(i);"); - }); +// Create a method using KeywordConfigurator for public access +var classOption = new TypeOption() + .WithTypeKind(TypeOption.Type.Class) + .WithName("NumberPrinter"); + +classOption.Public.Method(method => { + method.WithName("PrintNumbers") + .WithReturnType("void") + .For(@for => { + @for.WithInitializer("int i = 0") + .WithCondition("i < 10") + .WithIterator("i++") + .AppendLine("Console.WriteLine(i);"); + }); +}); -var code = method.Build(); +var code = classOption.Build(); ```
@@ -228,11 +308,14 @@ var code = method.Build(); **Generated Code**: ```csharp -public void PrintNumbers() +class NumberPrinter { - for (int i = 0; i < 10; i++) + public void PrintNumbers() { - Console.WriteLine(i); + for (int i = 0; i < 10; i++) + { + Console.WriteLine(i); + } } } ``` @@ -247,30 +330,36 @@ public void PrintNumbers() **API Calling**: ```csharp -using static Fengb3.EasyCodeBuilder.Csharp.Code; +using Fengb3.EasyCodeBuilder.Csharp; +using Fengb3.EasyCodeBuilder.Csharp.OptionConfigurations; -var method = new MethodOption() - .WithName("GetDayName") - .WithReturnType("string") - .WithKeyword("public") - .WithParameters("int day"); // WithParameters for methods - -method.Switch(@switch => { - @switch.Expression = "day"; - @switch.Case(@case => { - @case.Value = "1"; - @case.AppendLine("return \"Monday\";"); - }); - @switch.Case(@case => { - @case.Value = "2"; - @case.AppendLine("return \"Tuesday\";"); +// Create a class with a public method using KeywordConfigurator +var classOption = new TypeOption() + .WithTypeKind(TypeOption.Type.Class) + .WithName("DayHelper"); + +classOption.Public.Method(method => { + method.WithName("GetDayName") + .WithReturnType("string") + .WithParameters("int day"); // WithParameters for methods + + method.Switch(@switch => { + @switch.Expression = "day"; + @switch.Case(@case => { + @case.Value = "1"; + @case.AppendLine("return \"Monday\";"); + }); + @switch.Case(@case => { + @case.Value = "2"; + @case.AppendLine("return \"Tuesday\";"); + }); + @switch.Default(@default => + @default.AppendLine("return \"Unknown\";") + ); }); - @switch.Default(@default => - @default.AppendLine("return \"Unknown\";") - ); }); -var code = method.Build(); +var code = classOption.Build(); ```
@@ -278,21 +367,24 @@ var code = method.Build(); **Generated Code**: ```csharp -public string GetDayName(int day) +class DayHelper { - switch (day) + public string GetDayName(int day) { - case 1: - { - return "Monday"; - } - case 2: - { - return "Tuesday"; - } - default: + switch (day) { - return "Unknown"; + case 1: + { + return "Monday"; + } + case 2: + { + return "Tuesday"; + } + default: + { + return "Unknown"; + } } } } @@ -317,6 +409,8 @@ EasyCodeBuilder v0.1.0 uses a configuration-based approach where you: The library provides fluent extension methods for common operations: - **`WithName()`**, **`WithKeyword()`**, **`WithType()`** - Configure basic properties +- **`Public`**, **`Private`**, **`Internal`**, **`Static`** - Keyword configurator properties for fluent keyword specification +- **`KeywordConfigurator`** - Access the keyword configurator for advanced chaining with `Parent` property - **`Using()`** - Add using statements - **`Namespace()`**, **`Class()`**, **`Method()`** - Add structural elements - **`AutoProperty()`**, **`Constructor()`** - Add members