diff --git a/.editorconfig b/.editorconfig
index 5339d29..8738748 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,6 +11,7 @@ indent_style = space
trim_trailing_whitespace = true
charset = utf-8
end_of_line = lf
+max_line_length = 120
# Verify settings
# https://github.com/VerifyTests/Verify?tab=readme-ov-file#text-file-settings
@@ -24,7 +25,7 @@ tab_width = unset
trim_trailing_whitespace = false
# Code files
-[*.{cs,csx,vb,vbx}]
+[*.{cs,csx,vb,vbx,razor,razor.cs}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
@@ -34,6 +35,7 @@ charset = utf-8-bom
# See https://github.com/dotnet/aspnetcore/pull/23502 and https://github.com/dotnet/aspnetcore/issues/22753
[*.{razor,cshtml}]
charset = utf-8-bom
+indent_size = 4
# Generated code
[*{_AssemblyInfo.cs,.notsupported.cs,.generated.cs}]
@@ -121,7 +123,7 @@ dotnet_style_null_propagation = true :
# Modifier preferences
# See https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#normalize-modifiers
-dotnet_style_require_accessibility_modifiers = always : error
+dotnet_style_require_accessibility_modifiers = for_non_interface_members : error
dotnet_style_readonly_field = true : warning
# Required Styles
@@ -276,3 +278,7 @@ dotnet_diagnostic.SA1502.severity = none
dotnet_diagnostic.SA1504.severity = none
dotnet_diagnostic.SA1515.severity = none
dotnet_diagnostic.SA1516.severity = none
+
+# Support for NetEvolve.Arguments Methods
+# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1062#null-check-validation-methods
+dotnet_code_quality.CA1062.null_check_validation_methods = M:NetEvolve.Arguments.Argument.ThrowIfNull(System.Object,System.String)|M:NetEvolve.Arguments.Argument.ThrowIfNull(System.Void*,System.String)|M:NetEvolve.Arguments.Argument.ThrowIfNullOrEmpty(System.String,System.String)|M:NetEvolve.Arguments.Argument.ThrowIfNullOrEmpty``1(System.Collections.Generic.IEnumerable{``0},System.String)|M:NetEvolve.Arguments.Argument.ThrowIfNullOrWhiteSpace(System.String,System.String)
diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml
index 7266720..585b7b1 100644
--- a/.github/workflows/cicd.yml
+++ b/.github/workflows/cicd.yml
@@ -18,15 +18,18 @@ on:
- detailed
- diagnostic
+permissions:
+ actions: read
+ contents: read
+ pull-requests: write
+ security-events: write
+
jobs:
all:
if: github.run_id != 1
- name: Build & Tests
- uses: dailydevops/pipelines/.github/workflows/cicd-dotnet.yml@0.14.110
+ uses: dailydevops/pipelines/.github/workflows/build-dotnet-single.yml@1.0.8
with:
- disablePublish: true
- dotnet-logging: ${{ inputs.dotnet-logging }}
- dotnet-version: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
- enableSonarQube: ${{ vars.NE_DOTNET_SONAR }}
- solution: ###SOLUTION###
+ dotnetVersion: ${{ vars.NE_DOTNET_TARGETFRAMEWORKS }}
+ dotnetQuality: ${{ vars.NE_DOTNET_QUALITY }}
+ solution: ./HealthChecks.slnx
secrets: inherit
diff --git a/CodeBuilder.sln b/CodeBuilder.sln
deleted file mode 100644
index f46e582..0000000
--- a/CodeBuilder.sln
+++ /dev/null
@@ -1,39 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{089100B1-113F-4E66-888A-E83F3999EAFD}"
- ProjectSection(SolutionItems) = preProject
- .commitlintrc = .commitlintrc
- .editorconfig = .editorconfig
- .filenesting.json = .filenesting.json
- .gitattributes = .gitattributes
- .gitignore = .gitignore
- Directory.Build.props = Directory.Build.props
- Directory.Packages.props = Directory.Packages.props
- Directory.Solution.props = Directory.Solution.props
- GitVersion.yml = GitVersion.yml
- LICENSE = LICENSE
- logo.png = logo.png
- nuget.config = nuget.config
- README.md = README.md
- testEnvironments.json = testEnvironments.json
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {03ABAC60-42A8-4CED-A77B-6D7CA2680D0C}
- EndGlobalSection
-EndGlobal
diff --git a/CodeBuilder.slnx b/CodeBuilder.slnx
new file mode 100644
index 0000000..14a4a5d
--- /dev/null
+++ b/CodeBuilder.slnx
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Directory.Build.props b/Directory.Build.props
index bb10fb7..3c5fd1e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,18 +1,19 @@
-
$(MSBuildProjectName)
-
-
-
+ Provides a high-performance, memory-efficient builder for creating C# code.
+ https://github.com/dailydevops/codebuilder.git
+ https://github.com/dailydevops/codebuilder
$(RepositoryUrl)/releases
-
+ $(PackageTags);codegeneration;sourcegenrator
2024
+ <_DefaultTargetFrameworks>net8.0;net9.0;net10.0
+ <_ProjectTargetFrameworks>netstandard2.0;netstandard2.1;$(_DefaultTargetFrameworks)
+ <_TestTargetFrameworks>net6.0;net7.0;$(_DefaultTargetFrameworks)
+ false
-
- net8.0
+ net9.0
-
diff --git a/Directory.Packages.props b/Directory.Packages.props
index feb65be..bd93ac1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,19 +1,21 @@
-
true
true
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
-
diff --git a/README.md b/README.md
index 0e844c8..3742067 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,358 @@
# template-dotnet
-.NET template for repositories
+.NET template for repositories# NetEvolve.CodeBuilder
+
+[](https://www.nuget.org/packages/NetEvolve.CodeBuilder/)
+[](https://github.com/dailydevops/codebuilder/actions)
+
+A high-performance, memory-efficient builder for creating C# code with proper indentation and formatting. Designed specifically for code generation scenarios, it provides an intuitive API with automatic indentation management and thread-safe operations.
+
+## Features
+
+- **Automatic Indentation**: Intelligent handling of code blocks with `{` and `}` characters
+- **High Performance**: Built on top of `StringBuilder` with optimized memory usage
+- **Flexible Formatting**: Support for both spaces and tabs indentation
+- **Thread-Safe**: Safe indentation operations for multi-threaded scenarios
+- **Conditional Appending**: `AppendIf` and `AppendLineIf` methods for conditional code generation
+- **Format Support**: `AppendFormat` methods with culture-specific formatting
+- **Memory Efficient**: Support for `ReadOnlyMemory` and unsafe pointer operations
+- **Multi-Target Framework**: Supports .NET Standard 2.0, 2.1, .NET 8, 9, and 10
+
+## Installation
+
+### Package Manager Console
+```powershell
+Install-Package NetEvolve.CodeBuilder
+```
+
+### .NET CLI
+```bash
+dotnet add package NetEvolve.CodeBuilder
+```
+
+### PackageReference
+```xml
+
+```
+
+## Quick Start
+
+```csharp
+using NetEvolve.CodeBuilder;
+
+var builder = new CSharpCodeBuilder();
+
+builder.AppendLine("public class HelloWorld")
+ .Append("{")
+ .AppendLine("public void SayHello()")
+ .Append("{")
+ .AppendLine("Console.WriteLine(\"Hello, World!\");")
+ .Append("}")
+ .Append("}");
+
+Console.WriteLine(builder.ToString());
+```
+
+**Output:**
+```csharp
+public class HelloWorld
+{
+ public void SayHello()
+ {
+ Console.WriteLine("Hello, World!");
+ }
+}
+```
+
+## Basic Usage
+
+### Creating a Builder
+
+```csharp
+// Default constructor
+var builder = new CSharpCodeBuilder();
+
+// With initial capacity for better performance
+var builder = new CSharpCodeBuilder(1024);
+```
+
+### Appending Content
+
+```csharp
+var builder = new CSharpCodeBuilder();
+
+// Append strings
+builder.Append("public class ")
+ .Append("MyClass");
+
+// Append with automatic line breaks
+builder.AppendLine("public class MyClass");
+
+// Append characters
+builder.Append('{'); // Automatically increments indentation
+builder.Append('}'); // Automatically decrements indentation
+```
+
+### Working with Indentation
+
+```csharp
+var builder = new CSharpCodeBuilder();
+
+// Manual indentation control
+builder.IncrementIndent();
+builder.AppendLine("// This line is indented");
+builder.DecrementIndent();
+
+// Automatic indentation with braces
+builder.AppendLine("if (condition)")
+ .Append("{") // Automatically increments indent
+ .AppendLine("DoSomething();")
+ .Append("}"); // Automatically decrements indent
+```
+
+### Using Tabs Instead of Spaces
+
+```csharp
+var builder = new CSharpCodeBuilder { UseTabs = true };
+
+builder.AppendLine("public class MyClass")
+ .Append("{")
+ .AppendLine("// This uses tab indentation")
+ .Append("}");
+```
+
+## Advanced Features
+
+### Conditional Appending
+
+```csharp
+var builder = new CSharpCodeBuilder();
+bool includeComments = true;
+bool isPublic = true;
+
+builder.AppendLineIf(includeComments, "// This is a comment")
+ .AppendIf(isPublic, "public ")
+ .AppendLine("class MyClass")
+ .Append("{")
+ .Append("}");
+```
+
+### Format Support
+
+```csharp
+var builder = new CSharpCodeBuilder();
+
+// Basic formatting
+builder.AppendFormat(CultureInfo.InvariantCulture, "public {0} {1}", "class", "MyClass");
+
+// Multiple arguments
+builder.AppendFormat(CultureInfo.InvariantCulture,
+ "public {0} {1}({2} {3})",
+ "void", "SetValue", "string", "value");
+
+// With culture-specific formatting
+var culture = new CultureInfo("de-DE");
+builder.AppendFormat(culture, "// Price: {0:C}", 123.45m);
+```
+
+### Memory-Efficient Operations
+
+```csharp
+var builder = new CSharpCodeBuilder();
+
+// Using ReadOnlyMemory
+ReadOnlyMemory codeFragment = "public void Method()".AsMemory();
+builder.Append(codeFragment);
+
+// Using character arrays
+char[] chars = ['p', 'u', 'b', 'l', 'i', 'c'];
+builder.Append(chars, 0, 6);
+
+// Unsafe operations for maximum performance
+unsafe
+{
+ fixed (char* ptr = "unsafe code")
+ {
+ builder.Append(ptr, 11);
+ }
+}
+```
+
+### Capacity Management
+
+```csharp
+var builder = new CSharpCodeBuilder();
+
+// Check current capacity and length
+Console.WriteLine($"Capacity: {builder.Capacity}");
+Console.WriteLine($"Length: {builder.Length}");
+
+// Ensure sufficient capacity for better performance
+builder.EnsureCapacity(2048);
+
+// Clear content but keep capacity
+builder.Clear();
+```
+
+## Real-World Examples
+
+### Class Generation
+
+```csharp
+public string GenerateClass(string className, List properties)
+{
+ var builder = new CSharpCodeBuilder();
+
+ builder.AppendLine("using System;")
+ .AppendLine()
+ .AppendFormat(CultureInfo.InvariantCulture, "public class {0}", className)
+ .AppendLine()
+ .Append("{");
+
+ foreach (var property in properties)
+ {
+ builder.AppendFormat(CultureInfo.InvariantCulture,
+ "public {0} {1} {{ get; set; }}",
+ property.Type, property.Name)
+ .AppendLine();
+ }
+
+ builder.Append("}");
+
+ return builder.ToString();
+}
+```
+
+### Method Generation with Conditions
+
+```csharp
+public string GenerateMethod(string methodName, bool isAsync, bool isPublic, List parameters)
+{
+ var builder = new CSharpCodeBuilder();
+
+ builder.AppendIf(isPublic, "public ")
+ .AppendIf(isAsync, "async ")
+ .AppendIf(isAsync, "Task", "void")
+ .Append(" ")
+ .Append(methodName)
+ .Append("(");
+
+ for (int i = 0; i < parameters.Count; i++)
+ {
+ if (i > 0) builder.Append(", ");
+ builder.AppendFormat(CultureInfo.InvariantCulture,
+ "{0} {1}", parameters[i].Type, parameters[i].Name);
+ }
+
+ builder.AppendLine(")")
+ .Append("{")
+ .AppendLineIf(isAsync, "await Task.CompletedTask;")
+ .Append("}");
+
+ return builder.ToString();
+}
+```
+
+### Interface Generation
+
+```csharp
+public string GenerateInterface(string interfaceName, List methods)
+{
+ var builder = new CSharpCodeBuilder();
+
+ builder.AppendFormat(CultureInfo.InvariantCulture, "public interface {0}", interfaceName)
+ .AppendLine()
+ .Append("{");
+
+ foreach (var method in methods)
+ {
+ builder.AppendFormat(CultureInfo.InvariantCulture,
+ "{0} {1}({2});",
+ method.ReturnType,
+ method.Name,
+ string.Join(", ", method.Parameters.Select(p => $"{p.Type} {p.Name}")))
+ .AppendLine();
+ }
+
+ builder.Append("}");
+
+ return builder.ToString();
+}
+```
+
+## API Reference
+
+### Core Methods
+
+| Method | Description |
+|--------|-------------|
+| `Append(string)` | Appends a string to the builder |
+| `AppendLine()` | Appends a line terminator |
+| `AppendLine(string)` | Appends a string followed by a line terminator |
+| `AppendIf(bool, string)` | Conditionally appends a string |
+| `AppendLineIf(bool, string)` | Conditionally appends a string with line terminator |
+| `AppendFormat(IFormatProvider, string, ...)` | Appends formatted string |
+| `Clear()` | Removes all content from the builder |
+| `EnsureCapacity(int)` | Ensures the builder has at least the specified capacity |
+| `ToString()` | Returns the built string |
+
+### Properties
+
+| Property | Type | Description |
+|----------|------|-------------|
+| `Capacity` | `int` | Gets the current capacity of the internal StringBuilder |
+| `Length` | `int` | Gets the current length of the content |
+| `UseTabs` | `bool` | Gets or sets whether to use tabs instead of spaces for indentation |
+
+### Indentation Methods
+
+| Method | Description |
+|--------|-------------|
+| `IncrementIndent()` | Increases indentation level by one |
+| `DecrementIndent()` | Decreases indentation level by one |
+
+## Performance Considerations
+
+- **Initial Capacity**: Specify an appropriate initial capacity to minimize memory allocations
+- **Memory Types**: Use `ReadOnlyMemory` overloads for better memory efficiency
+- **Unsafe Operations**: Use unsafe pointer methods for maximum performance in critical scenarios
+- **Capacity Management**: Use `EnsureCapacity()` when you know the approximate final size
+
+```csharp
+// Good: Pre-allocate capacity
+var builder = new CSharpCodeBuilder(4096);
+
+// Good: Ensure capacity before large operations
+builder.EnsureCapacity(estimatedSize);
+
+// Good: Use memory-efficient overloads
+builder.Append(text.AsMemory());
+```
+
+## Thread Safety
+
+The `CSharpCodeBuilder` uses thread-safe operations for indentation management through `Interlocked` operations. However, the underlying `StringBuilder` operations are not thread-safe, so avoid concurrent access to the same instance from multiple threads.
+
+## Target Frameworks
+
+- .NET Standard 2.0
+- .NET Standard 2.1
+- .NET 8.0
+- .NET 9.0
+- .NET 10.0
+
+## Dependencies
+
+- **.NET Standard 2.0/2.1**: `System.Memory` package for `ReadOnlyMemory` support
+- **.NET 8+**: No additional dependencies
+
+## Contributing
+
+Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
+
+## License
+
+This project is licensed under the MIT License - see the LICENSE file for details.
+
+## Changelog
+
+See [RELEASES](https://github.com/dailydevops/codebuilder/releases) for a detailed changelog.
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs
new file mode 100644
index 0000000..b0c1117
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs
@@ -0,0 +1,222 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a boolean value to the current builder.
+ ///
+ /// The boolean value to append.
+ /// The current instance to allow for method chaining.
+ /// Appends either "True" or "False" based on the value.
+ public CSharpCodeBuilder Append(bool value)
+ {
+ EnsureIndented();
+ _ = _builder.Append(value ? "true" : "false");
+ return this;
+ }
+
+ ///
+ /// Appends a character repeated a specified number of times to the current builder.
+ ///
+ /// The character to append.
+ /// The number of times to repeat the character.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is less than zero.
+ public CSharpCodeBuilder Append(char value, int repeatCount)
+ {
+ EnsureIndented();
+ _ = _builder.Append(value, repeatCount);
+ return this;
+ }
+
+ ///
+ /// Appends a character to the current builder.
+ ///
+ /// The character to append.
+ /// The current instance to allow for method chaining.
+ public CSharpCodeBuilder Append(char value)
+ {
+ if (value is '\0')
+ {
+ return this; // No need to append null character
+ }
+
+ if (value is '\n' or '\r')
+ {
+ return AppendLine(); // Handle new line characters
+ }
+
+ if (value is '}' or ']')
+ {
+ DecrementIndent();
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value);
+
+ if (value is '{' or '[')
+ {
+ IncrementIndent();
+ return AppendLine();
+ }
+ else if (value is '}' or ']')
+ {
+ return AppendLine();
+ }
+
+ return this;
+ }
+
+ ///
+ /// Appends a subset of an array of characters to the current builder.
+ ///
+ /// The character array to append.
+ /// The starting position in the character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(char[]? value, int startIndex, int charCount)
+ {
+ if (value is null || value.Length == 0)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value, startIndex, charCount);
+ return this;
+ }
+
+ ///
+ /// Appends an array of characters to the current builder.
+ ///
+ /// The character array to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(char[]? value)
+ {
+ if (value is null || value.Length == 0)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value);
+ return this;
+ }
+
+ ///
+ /// Appends characters from a pointer to the current builder.
+ ///
+ /// A pointer to a character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the pointer is null or length is negative, the method returns without appending anything.
+ public unsafe CSharpCodeBuilder Append(char* value, int length)
+ {
+ if (value == null || length < 0)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value, length);
+ return this;
+ }
+
+ ///
+ /// Appends a read-only memory of characters to the current builder.
+ ///
+ /// The read-only memory containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(ReadOnlyMemory value)
+ {
+ if (value.IsEmpty)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value);
+ return this;
+ }
+
+ ///
+ /// Appends a subset of a read-only memory of characters to the current builder.
+ ///
+ /// The read-only memory containing the characters to append.
+ /// The starting position in the memory.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(ReadOnlyMemory value, int startIndex, int count)
+ {
+ if (value.IsEmpty)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value.Slice(startIndex, count));
+ return this;
+ }
+
+ ///
+ /// Appends a subset of a string to the current builder.
+ ///
+ /// The string to append.
+ /// The starting position in the string.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(string? value, int startIndex, int count)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value, startIndex, count);
+ return this;
+ }
+
+ ///
+ /// Appends a string to the current builder.
+ ///
+ /// The string to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(string? value)
+ {
+ if (string.IsNullOrEmpty(value) || value is "\0")
+ {
+ return this;
+ }
+
+ if (value is "\n" or "\r")
+ {
+ return AppendLine(); // Handle new line characters
+ }
+
+ if (value is "}" or "]")
+ {
+ DecrementIndent();
+ _ = AppendLine();
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(value);
+
+ if (value is "{" or "[")
+ {
+ IncrementIndent();
+ _ = AppendLine();
+ }
+
+ return this;
+ }
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs
new file mode 100644
index 0000000..5cb118d
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs
@@ -0,0 +1,48 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a formatted string to the current builder using invariant culture.
+ ///
+ /// A composite format string.
+ /// The object to format.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is .
+ /// Thrown when is invalid or the index of a format item is greater than zero.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendFormat(string format, object? arg0) =>
+ AppendFormat(CultureInfo.InvariantCulture, format, arg0);
+
+ ///
+ /// Appends a formatted string to the current builder using invariant culture.
+ ///
+ /// A composite format string.
+ /// An array of objects to format.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is .
+ /// Thrown when is invalid or the index of a format item is greater than the number of elements in minus 1.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendFormat(string format, params object?[] args) =>
+ AppendFormat(CultureInfo.InvariantCulture, format, args);
+
+ ///
+ /// Appends a formatted string to the current builder using the specified format provider.
+ ///
+ /// An object that supplies culture-specific formatting information.
+ /// A composite format string.
+ /// An array of objects to format.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is .
+ /// Thrown when is invalid or the index of a format item is greater than the number of elements in minus 1.
+ public CSharpCodeBuilder AppendFormat(IFormatProvider? provider, string format, params object?[] args)
+ {
+ EnsureIndented();
+ _ = _builder.AppendFormat(provider, format, args);
+ return this;
+ }
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs
new file mode 100644
index 0000000..1feb663
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs
@@ -0,0 +1,119 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+using System.Runtime.CompilerServices;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a boolean value to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The boolean value to append.
+ /// The current instance to allow for method chaining.
+ /// Appends either "true" or "false" based on the value if the condition is true.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, bool value) => condition ? Append(value) : this;
+
+ ///
+ /// Appends a character repeated a specified number of times to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character to append.
+ /// The number of times to repeat the character.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is less than zero.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, char value, int repeatCount) =>
+ condition ? Append(value, repeatCount) : this;
+
+ ///
+ /// Appends a character to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character to append.
+ /// The current instance to allow for method chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, char value) => condition ? Append(value) : this;
+
+ ///
+ /// Appends a subset of an array of characters to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character array to append.
+ /// The starting position in the character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, char[]? value, int startIndex, int charCount) =>
+ condition ? Append(value, startIndex, charCount) : this;
+
+ ///
+ /// Appends an array of characters to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character array to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, char[]? value) => condition ? Append(value) : this;
+
+ ///
+ /// Appends characters from a pointer to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// A pointer to a character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the pointer is null or length is negative, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe CSharpCodeBuilder AppendIf(bool condition, char* value, int length) =>
+ condition ? Append(value, length) : this;
+
+ ///
+ /// Appends a read-only memory of characters to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only memory containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, ReadOnlyMemory value) => condition ? Append(value) : this;
+
+ ///
+ /// Appends a subset of a read-only memory of characters to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only memory containing the characters to append.
+ /// The starting position in the memory.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, ReadOnlyMemory value, int startIndex, int count) =>
+ condition ? Append(value, startIndex, count) : this;
+
+ ///
+ /// Appends a subset of a string to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The string to append.
+ /// The starting position in the string.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, string? value, int startIndex, int count) =>
+ condition ? Append(value, startIndex, count) : this;
+
+ ///
+ /// Appends a string to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The string to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, string? value) => condition ? Append(value) : this;
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs
new file mode 100644
index 0000000..b612b70
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs
@@ -0,0 +1,111 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+using System.Runtime.CompilerServices;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a line terminator to the current builder.
+ ///
+ /// The current instance to allow for method chaining.
+ ///
+ /// This method appends the default line terminator for the current environment and sets the internal state
+ /// to indicate that the next character will be at the beginning of a new line.
+ ///
+ public CSharpCodeBuilder AppendLine()
+ {
+ EnsureIndented(true);
+ _ = _builder.AppendLine();
+ _isNewline = true;
+ return this;
+ }
+
+ ///
+ /// Appends a string followed by a line terminator to the current builder.
+ ///
+ /// The string to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(string? value) => Append(value).AppendLine();
+
+ ///
+ /// Appends a read-only memory of characters followed by a line terminator to the current builder.
+ ///
+ /// The read-only memory containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(ReadOnlyMemory value) => Append(value).AppendLine();
+
+ ///
+ /// Appends a subset of a read-only memory of characters followed by a line terminator to the current builder.
+ ///
+ /// The read-only memory containing the characters to append.
+ /// The starting position in the memory.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(ReadOnlyMemory value, int startIndex, int count) =>
+ Append(value, startIndex, count).AppendLine();
+
+ ///
+ /// Appends an array of characters followed by a line terminator to the current builder.
+ ///
+ /// The character array to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(char[]? value) => Append(value).AppendLine();
+
+ ///
+ /// Appends a subset of an array of characters followed by a line terminator to the current builder.
+ ///
+ /// The character array to append.
+ /// The starting position in the character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(char[]? value, int startIndex, int charCount) =>
+ Append(value, startIndex, charCount).AppendLine();
+
+ ///
+ /// Appends characters from a pointer followed by a line terminator to the current builder.
+ ///
+ /// A pointer to a character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the pointer is null or length is negative, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe CSharpCodeBuilder AppendLine(char* value, int length) => Append(value, length).AppendLine();
+
+ ///
+ /// Appends a character followed by a line terminator to the current builder.
+ ///
+ /// The character to append.
+ /// The current instance to allow for method chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(char value) => Append(value).AppendLine();
+
+ ///
+ /// Appends a character repeated a specified number of times followed by a line terminator to the current builder.
+ ///
+ /// The character to append.
+ /// The number of times to repeat the character.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is less than zero.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(char value, int repeatCount) => Append(value, repeatCount).AppendLine();
+
+ ///
+ /// Appends a boolean value followed by a line terminator to the current builder.
+ ///
+ /// The boolean value to append.
+ /// The current instance to allow for method chaining.
+ /// Appends either "true" or "false" based on the value, followed by a line terminator.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(bool value) => Append(value).AppendLine();
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLineIf.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLineIf.cs
new file mode 100644
index 0000000..18e6c6b
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLineIf.cs
@@ -0,0 +1,115 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+using System.Runtime.CompilerServices;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the line terminator.
+ /// The current instance to allow for method chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition) => condition ? AppendLine() : this;
+
+ ///
+ /// Appends a string followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The string to append.
+ /// The current instance to allow for method chaining.
+ /// If the string is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, string? value) => condition ? AppendLine(value) : this;
+
+ ///
+ /// Appends a read-only memory of characters followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only memory containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlyMemory value) =>
+ condition ? AppendLine(value) : this;
+
+ ///
+ /// Appends a subset of a read-only memory of characters followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only memory containing the characters to append.
+ /// The starting position in the memory.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the memory is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlyMemory value, int startIndex, int count) =>
+ condition ? AppendLine(value, startIndex, count) : this;
+
+ ///
+ /// Appends an array of characters followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character array to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, char[]? value) => condition ? AppendLine(value) : this;
+
+ ///
+ /// Appends a subset of an array of characters followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character array to append.
+ /// The starting position in the character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the array is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, char[]? value, int startIndex, int charCount) =>
+ condition ? AppendLine(value, startIndex, charCount) : this;
+
+ ///
+ /// Appends characters from a pointer followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// A pointer to a character array.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the pointer is null or length is negative, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe CSharpCodeBuilder AppendLineIf(bool condition, char* value, int length) =>
+ condition ? AppendLine(value, length) : this;
+
+ ///
+ /// Appends a character followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character to append.
+ /// The current instance to allow for method chaining.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, char value) => condition ? AppendLine(value) : this;
+
+ ///
+ /// Appends a character repeated a specified number of times followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The character to append.
+ /// The number of times to repeat the character.
+ /// The current instance to allow for method chaining.
+ /// Thrown when is less than zero.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, char value, int repeatCount) =>
+ condition ? AppendLine(value, repeatCount) : this;
+
+ ///
+ /// Appends a boolean value followed by a line terminator to the current builder if the specified condition is true.
+ ///
+ /// The condition that determines whether to append the value.
+ /// The boolean value to append.
+ /// The current instance to allow for method chaining.
+ /// Appends either "true" or "false" based on the value if the condition is true.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, bool value) => condition ? AppendLine(value) : this;
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Clear.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Clear.cs
new file mode 100644
index 0000000..db25aef
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Clear.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.CodeBuilder;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Clears the content of the current builder and resets the indentation level to zero.
+ ///
+ /// The current instance to allow for method chaining.
+ ///
+ /// This method removes all characters from the internal and
+ /// resets the indentation level to zero, effectively providing a clean slate for building new content.
+ ///
+ public CSharpCodeBuilder Clear()
+ {
+ _ = _builder.Clear();
+ _ = Interlocked.Exchange(ref _indentLevel, 0);
+
+ return this;
+ }
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs
new file mode 100644
index 0000000..92a8627
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs
@@ -0,0 +1,392 @@
+namespace NetEvolve.CodeBuilder;
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Appends a single-line XML documentation comment.
+ ///
+ /// The content for the documentation comment.
+ /// The current instance to allow for method chaining.
+ /// If the content is null or empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendXmlDoc(string? content) =>
+ string.IsNullOrEmpty(content) ? this : EnsureNewLineForXmlDoc().AppendLine($"/// {content}");
+
+ ///
+ /// Appends an XML documentation summary element.
+ ///
+ /// The summary text to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the summary is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocSummary(string? summary)
+ {
+ if (string.IsNullOrEmpty(summary))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc()
+ .AppendLine("/// ")
+ .AppendLine($"/// {summary}")
+ .AppendLine("/// ");
+ }
+
+ ///
+ /// Appends an XML documentation summary element with multiple lines.
+ ///
+ /// The summary lines to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the summary lines collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocSummary(IEnumerable? summaryLines)
+ {
+ if (summaryLines is null)
+ {
+ return this;
+ }
+
+ var hasContent = false;
+ var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+
+ foreach (var line in summaryLines)
+ {
+ if (!string.IsNullOrEmpty(line))
+ {
+ builder = builder.AppendLine($"/// {line}");
+ hasContent = true;
+ }
+ }
+
+ return hasContent ? builder.AppendLine("/// ") : this;
+ }
+
+ ///
+ /// Appends an XML documentation param element.
+ ///
+ /// The name of the parameter.
+ /// The description of the parameter.
+ /// The current instance to allow for method chaining.
+ /// If the parameter name or description is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocParam(string? paramName, string? description)
+ {
+ if (string.IsNullOrEmpty(paramName) || string.IsNullOrEmpty(description))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ }
+
+ ///
+ /// Appends multiple XML documentation param elements.
+ ///
+ /// A collection of parameter name and description pairs.
+ /// The current instance to allow for method chaining.
+ /// If the parameters collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocParams(IEnumerable<(string Name, string Description)>? parameters)
+ {
+ if (parameters is null)
+ {
+ return this;
+ }
+
+ var builder = this;
+ foreach (var (name, description) in parameters)
+ {
+ builder = builder.AppendXmlDocParam(name, description);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Appends an XML documentation returns element.
+ ///
+ /// The description of the return value.
+ /// The current instance to allow for method chaining.
+ /// If the description is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocReturns(string? description)
+ {
+ if (string.IsNullOrEmpty(description))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ }
+
+ ///
+ /// Appends an XML documentation remarks element.
+ ///
+ /// The remarks text to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the remarks text is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocRemarks(string? remarks)
+ {
+ if (string.IsNullOrEmpty(remarks))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc()
+ .AppendLine("/// ")
+ .AppendLine($"/// {remarks}")
+ .AppendLine("/// ");
+ }
+
+ ///
+ /// Appends an XML documentation remarks element with multiple lines.
+ ///
+ /// The remarks lines to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the remarks lines collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocRemarks(IEnumerable? remarksLines)
+ {
+ if (remarksLines is null)
+ {
+ return this;
+ }
+
+ var hasContent = false;
+ var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+
+ foreach (var line in remarksLines)
+ {
+ if (!string.IsNullOrEmpty(line))
+ {
+ builder = builder.AppendLine($"/// {line}");
+ hasContent = true;
+ }
+ }
+
+ return hasContent ? builder.AppendLine("/// ") : this;
+ }
+
+ ///
+ /// Appends an XML documentation exception element.
+ ///
+ /// The type of exception that can be thrown.
+ /// The description of when the exception is thrown.
+ /// The current instance to allow for method chaining.
+ /// If the exception type or description is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocException(string? exceptionType, string? description)
+ {
+ if (string.IsNullOrEmpty(exceptionType) || string.IsNullOrEmpty(description))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc()
+ .AppendLine($"/// {description}");
+ }
+
+ ///
+ /// Appends multiple XML documentation exception elements.
+ ///
+ /// A collection of exception type and description pairs.
+ /// The current instance to allow for method chaining.
+ /// If the exceptions collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocExceptions(IEnumerable<(string Type, string Description)>? exceptions)
+ {
+ if (exceptions is null)
+ {
+ return this;
+ }
+
+ var builder = this;
+ foreach (var (type, description) in exceptions)
+ {
+ builder = builder.AppendXmlDocException(type, description);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Appends an XML documentation example element.
+ ///
+ /// The example text or code to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the example is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocExample(string? example)
+ {
+ if (string.IsNullOrEmpty(example))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc()
+ .AppendLine("/// ")
+ .AppendLine($"/// {example}")
+ .AppendLine("/// ");
+ }
+
+ ///
+ /// Appends an XML documentation example element with multiple lines.
+ ///
+ /// The example lines to include in the documentation.
+ /// The current instance to allow for method chaining.
+ /// If the example lines collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocExample(IEnumerable? exampleLines)
+ {
+ if (exampleLines is null)
+ {
+ return this;
+ }
+
+ var hasContent = false;
+ var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+
+ foreach (var line in exampleLines)
+ {
+ if (!string.IsNullOrEmpty(line))
+ {
+ builder = builder.AppendLine($"/// {line}");
+ hasContent = true;
+ }
+ }
+
+ return hasContent ? builder.AppendLine("/// ") : this;
+ }
+
+ ///
+ /// Appends an XML documentation see element for cross-references.
+ ///
+ /// The cross-reference to another member or type.
+ /// The current instance to allow for method chaining.
+ /// If the cref is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocSee(string? cref)
+ {
+ if (string.IsNullOrEmpty(cref))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// ");
+ }
+
+ ///
+ /// Appends an XML documentation seealso element for see-also references.
+ ///
+ /// The cross-reference to another member or type.
+ /// The current instance to allow for method chaining.
+ /// If the cref is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocSeeAlso(string? cref)
+ {
+ if (string.IsNullOrEmpty(cref))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// ");
+ }
+
+ ///
+ /// Appends an XML documentation value element for property documentation.
+ ///
+ /// The description of the property value.
+ /// The current instance to allow for method chaining.
+ /// If the description is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocValue(string? description)
+ {
+ if (string.IsNullOrEmpty(description))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ }
+
+ ///
+ /// Appends an XML documentation typeparam element for generic type parameters.
+ ///
+ /// The name of the type parameter.
+ /// The description of the type parameter.
+ /// The current instance to allow for method chaining.
+ /// If the parameter name or description is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocTypeParam(string? paramName, string? description)
+ {
+ if (string.IsNullOrEmpty(paramName) || string.IsNullOrEmpty(description))
+ {
+ return this;
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ }
+
+ ///
+ /// Appends multiple XML documentation typeparam elements.
+ ///
+ /// A collection of type parameter name and description pairs.
+ /// The current instance to allow for method chaining.
+ /// If the type parameters collection is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocTypeParams(IEnumerable<(string, string)>? typeParameters)
+ {
+ if (typeParameters is null)
+ {
+ return this;
+ }
+
+ var builder = this;
+ foreach (var (name, description) in typeParameters)
+ {
+ builder = builder.AppendXmlDocTypeParam(name, description);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Appends an inheritdoc XML documentation element.
+ ///
+ /// Optional cross-reference to specify which member to inherit documentation from.
+ /// The current instance to allow for method chaining.
+ /// If no cref is provided, inherits documentation from the base or interface member.
+ public CSharpCodeBuilder AppendXmlDocInheritDoc(string? cref = null) =>
+ string.IsNullOrEmpty(cref)
+ ? EnsureNewLineForXmlDoc().AppendLine("/// ")
+ : EnsureNewLineForXmlDoc().AppendLine($"/// ");
+
+ ///
+ /// Appends a custom XML documentation element.
+ ///
+ /// The name of the XML element.
+ /// The content of the XML element.
+ /// Optional attributes for the XML element.
+ /// The current instance to allow for method chaining.
+ /// If the element name is null or empty, the method returns without appending anything.
+ public CSharpCodeBuilder AppendXmlDocCustomElement(
+ string? elementName,
+ string? content = null,
+ string? attributes = null
+ )
+ {
+ if (string.IsNullOrEmpty(elementName))
+ {
+ return this;
+ }
+
+ var attributesPart = string.IsNullOrEmpty(attributes) ? string.Empty : $" {attributes}";
+
+ if (string.IsNullOrEmpty(content))
+ {
+ return EnsureNewLineForXmlDoc().AppendLine($"/// <{elementName}{attributesPart} />");
+ }
+
+ return EnsureNewLineForXmlDoc().AppendLine($"/// <{elementName}{attributesPart}>{content}{elementName}>");
+ }
+
+ ///
+ /// Ensures that XML documentation comments start on a new line if there's already content in the builder.
+ ///
+ /// The current instance to allow for method chaining.
+ ///
+ /// This method checks if the builder already has content and if we're not already on a new line,
+ /// it appends a line break to ensure XML documentation starts on a fresh line.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private CSharpCodeBuilder EnsureNewLineForXmlDoc() => AppendLineIf(Length > 0 && !_isNewline);
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs
new file mode 100644
index 0000000..39c4423
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs
@@ -0,0 +1,18 @@
+namespace NetEvolve.CodeBuilder;
+
+public partial record CSharpCodeBuilder
+{
+ ///
+ /// Ensures that the capacity of the internal is at least the specified value.
+ ///
+ /// The minimum capacity to ensure.
+ ///
+ /// If the current capacity is less than the value specified, the capacity is increased to the specified value.
+ ///
+ public CSharpCodeBuilder EnsureCapacity(int capacity)
+ {
+ _ = _builder.EnsureCapacity(capacity);
+
+ return this;
+ }
+}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs
new file mode 100644
index 0000000..7682b2f
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs
@@ -0,0 +1,3 @@
+namespace NetEvolve.CodeBuilder;
+
+public partial record CSharpCodeBuilder { }
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs
new file mode 100644
index 0000000..bd4d747
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs
@@ -0,0 +1,22 @@
+namespace NetEvolve.CodeBuilder;
+
+using System.Text;
+
+///
+/// Provides functionality for building C# code strings with proper indentation.
+///
+public partial record CSharpCodeBuilder : CodeBuilderBase
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CSharpCodeBuilder()
+ : base() { }
+
+ ///
+ /// Initializes a new instance of the class with the specified initial capacity.
+ ///
+ /// The initial capacity of the internal .
+ public CSharpCodeBuilder(int initialCapacity)
+ : base(initialCapacity) { }
+}
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs
new file mode 100644
index 0000000..898b688
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs
@@ -0,0 +1,52 @@
+namespace NetEvolve.CodeBuilder;
+
+using System.Runtime.CompilerServices;
+
+public partial record CodeBuilderBase
+{
+ ///
+ /// Ensures that indentation is applied if we are at the start of a new line.
+ ///
+ ///
+ /// This method adds the appropriate indentation (tabs or spaces) at the beginning of a line
+ /// based on the current indentation level. It only applies indentation if the current position is
+ /// at the start of a new line (when is ).
+ ///
+ private protected void EnsureIndented(bool deactivate = false)
+ {
+ if (!_isNewline || deactivate)
+ {
+ return;
+ }
+
+ _ = _builder.Append(UseTabs ? '\t' : ' ', _indentLevel * (UseTabs ? 1 : 4));
+
+ _isNewline = false;
+ }
+
+ ///
+ /// Increments the indentation level by one.
+ ///
+ ///
+ /// This method increases the current indentation level, which affects subsequent lines
+ /// that are appended to the builder. The operation is thread-safe.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void IncrementIndent() => Interlocked.Increment(ref _indentLevel);
+
+ ///
+ /// Decrements the indentation level by one.
+ ///
+ ///
+ /// This method decreases the current indentation level, which affects subsequent lines
+ /// that are appended to the builder. The operation is thread-safe.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void DecrementIndent()
+ {
+ if (Interlocked.Decrement(ref _indentLevel) < 0)
+ {
+ _ = Interlocked.Exchange(ref _indentLevel, 0);
+ }
+ }
+}
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs
new file mode 100644
index 0000000..b480359
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs
@@ -0,0 +1,13 @@
+namespace NetEvolve.CodeBuilder;
+
+public partial record CodeBuilderBase
+{
+ ///
+ /// Returns the string that has been built by this .
+ ///
+ /// The string representation of the current instance.
+ ///
+ /// This method returns the content of the internal .
+ ///
+ public override sealed string ToString() => _builder.ToString();
+}
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs
new file mode 100644
index 0000000..6397834
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs
@@ -0,0 +1,42 @@
+namespace NetEvolve.CodeBuilder;
+
+using System.Text;
+
+///
+/// Provides the base functionality for building code strings with proper indentation and formatting.
+///
+public abstract partial record CodeBuilderBase
+{
+ private protected readonly StringBuilder _builder;
+ private protected int _indentLevel;
+ private protected bool _isNewline = true;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ private protected CodeBuilderBase() => _builder = new StringBuilder();
+
+ ///
+ /// Initializes a new instance of the class with the specified initial capacity.
+ ///
+ /// The initial capacity of the internal .
+ private protected CodeBuilderBase(int initialCapacity) => _builder = new StringBuilder(initialCapacity);
+
+ ///
+ /// Gets the current capacity of the internal .
+ ///
+ /// The capacity of the internal string builder.
+ public int Capacity => _builder.Capacity;
+
+ ///
+ /// Gets the current length of the internal .
+ ///
+ /// The length of the content that has been built so far.
+ public int Length => _builder.Length;
+
+ ///
+ /// Gets or sets a value indicating whether to use tabs instead of spaces for indentation.
+ ///
+ /// true to use tabs for indentation; false to use spaces.
+ public bool UseTabs { get; set; }
+}
diff --git a/src/NetEvolve.CodeBuilder/NetEvolve.CodeBuilder.csproj b/src/NetEvolve.CodeBuilder/NetEvolve.CodeBuilder.csproj
new file mode 100644
index 0000000..6d086c3
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/NetEvolve.CodeBuilder.csproj
@@ -0,0 +1,9 @@
+
+
+ $(_ProjectTargetFrameworks)
+ true
+
+
+
+
+
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs
new file mode 100644
index 0000000..ce48611
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs
@@ -0,0 +1,247 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task Append_Boolean_True_Should_Append_TrueString()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append(true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("true");
+ }
+
+ [Test]
+ public async Task Append_Boolean_False_Should_Append_FalseString()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append(false);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("false");
+ }
+
+ [Test]
+ public async Task Append_Char_Should_Append_Character()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append('x');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("x");
+ }
+
+ [Test]
+ public async Task Append_Char_Multiple_Should_Append_All_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append("a").Append('b').Append('c');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task Append_Multiple_Should_Same()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var builder2 = builder.Append('a').Append('b').Append('c');
+
+ _ = await Assert.That(builder).IsEqualTo(builder2);
+ }
+
+ [Test]
+ public async Task Append_Char_With_RepeatCount_Should_Append_Character_Repeated_Times()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append('x', 5);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("xxxxx");
+ }
+
+ [Test]
+ public async Task Append_Char_With_RepeatCount_Zero_Should_Not_Append_Anything()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append('x', 0);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_Char_With_RepeatCount_Negative_Should_Throw_ArgumentOutOfRangeException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.Append('x', -1);
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("repeatCount");
+ }
+
+ [Test]
+ public async Task Append_CharArray_Should_Append_All_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ _ = builder.Append(chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task Append_CharArray_Null_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append((char[]?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_CharArray_Empty_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append([]);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_CharArray_With_StartIndex_And_Count_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ _ = builder.Append(chars, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task Append_CharArray_With_StartIndex_And_Count_Null_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ char[]? chars = null;
+
+ _ = builder.Append(chars, 0, 0);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_ReadOnlyMemory_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ _ = builder.Append(memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task Append_ReadOnlyMemory_Empty_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = ReadOnlyMemory.Empty;
+
+ _ = builder.Append(memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_ReadOnlyMemory_With_StartIndex_And_Count_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ _ = builder.Append(memory, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task Append_String_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append("abc");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task Append_String_Null_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append((string?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_String_Empty_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append(string.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_String_With_StartIndex_And_Count_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.Append("abcdef", 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task Append_String_With_StartIndex_And_Count_Null_Should_Not_Change_Builder()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ string? text = null;
+
+ _ = builder.Append(text, 0, 0);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task Append_Multiple_Calls_Should_Append_In_Sequence()
+ {
+ var builder = new CSharpCodeBuilder(20);
+
+ _ = builder.Append("Hello").Append(' ').Append("World").Append('!');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello World!");
+ }
+
+ [Test]
+ public async Task Append_With_Capacity_Expansion_Should_Work_Correctly()
+ {
+ // Start with small capacity to force expansion
+ var builder = new CSharpCodeBuilder(5);
+ var longString = new string('x', 100);
+
+ _ = builder.Append(longString);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(longString);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs
new file mode 100644
index 0000000..51b128f
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs
@@ -0,0 +1,484 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+using System.Globalization;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendFormat_OneArgument_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Value: {0}", 42);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 42");
+ }
+
+ [Test]
+ public async Task AppendFormat_OneArgument_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var decimalValue = 1234.56m;
+
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Value: {0:N2}", decimalValue);
+
+ // InvariantCulture uses period as decimal separator
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 1,234.56");
+ }
+
+ [Test]
+ public async Task AppendFormat_OneArgument_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ // First append a newline, then format text to see indentation
+ _ = builder.AppendLine().AppendFormat(CultureInfo.InvariantCulture, "Value: {0}", 42);
+
+ var expected = Environment.NewLine + " Value: 42";
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendFormat_OneArgument_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat(CultureInfo.InvariantCulture, "Value: {0}", 42);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_OneArgument_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, null!, 42);
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ public async Task AppendFormat_OneArgument_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Value: {1}", 42);
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Values: {0}, {1}", 42, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 42, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var decimalValue = 1234.56m;
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0:N2}, {1}",
+ decimalValue,
+ "test"
+ );
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo("Values: 1,234.56, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ // First append a newline, then format text to see indentation
+ var result = builder
+ .AppendLine()
+ .AppendFormat(CultureInfo.InvariantCulture, "Values: {0}, {1}", 42, "test")
+ .ToString();
+
+ var expected = Environment.NewLine + " Values: 42, test";
+ _ = await Assert.That(result).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}",
+ 42,
+ "test"
+ );
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, null!, 42, "test");
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ public async Task AppendFormat_TwoArguments_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Values: {0}, {2}", 42, "test");
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}",
+ 42,
+ "test",
+ true
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 42, test, True");
+ }
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var decimalValue = 1234.56m;
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0:N2}, {1}, {2}",
+ decimalValue,
+ "test",
+ true
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1,234.56, test, True");
+ }
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ // First append a newline, then format text to see indentation
+ _ = builder
+ .AppendLine()
+ .AppendFormat(CultureInfo.InvariantCulture, "Values: {0}, {1}, {2}", 42, "test", true);
+
+ var expected = Environment.NewLine + " Values: 42, test, True";
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}",
+ 42,
+ "test",
+ true
+ );
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, null!, 42, "test", true);
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ public async Task AppendFormat_ThreeArguments_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {3}",
+ 42,
+ "test",
+ true
+ );
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}, {3}",
+ 42,
+ "test",
+ true,
+ 3.14
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 42, test, True, 3.14");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var decimalValue = 1234.56m;
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0:N2}, {1}, {2}, {3:F2}",
+ decimalValue,
+ "test",
+ true,
+ 3.14
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1,234.56, test, True, 3.14");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ // First append a newline, then format text to see indentation
+ _ = builder
+ .AppendLine()
+ .AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}, {3}",
+ 42,
+ "test",
+ true,
+ 3.14
+ );
+
+ var expected = Environment.NewLine + " Values: 42, test, True, 3.14";
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}, {3}",
+ 42,
+ "test",
+ true,
+ 3.14
+ );
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, null!, 42, "test", true, 3.14);
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArray_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {0}, {1}, {2}, {4}",
+ 42,
+ "test",
+ true,
+ 3.14
+ );
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ public void AppendFormat_EmptyArray_ThrowsFormatException()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = Assert.Throws(() =>
+ builder.AppendFormat(CultureInfo.InvariantCulture, "No params: {0}", [])
+ );
+ }
+
+ [Test]
+ public async Task AppendFormat_WithProvider_OneArgument_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var cultureInfo = new CultureInfo("de-DE");
+
+ _ = builder.AppendFormat(cultureInfo, "Value: {0:N2}", 1234.56);
+
+ // French culture uses comma as decimal separator
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 1.234,56");
+ }
+
+ [Test]
+ public async Task AppendFormat_WithProvider_TwoArguments_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var cultureInfo = new CultureInfo("de-DE");
+
+ _ = builder.AppendFormat(cultureInfo, "Values: {0:N2}, {1}", 1234.56, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1.234,56, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_WithProvider_ThreeArguments_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var cultureInfo = new CultureInfo("de-DE");
+
+ _ = builder.AppendFormat(cultureInfo, "Values: {0:N2}, {1}, {2}", 1234.56, "test", true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1.234,56, test, True");
+ }
+
+ [Test]
+ public async Task AppendFormat_WithProvider_ParamsArray_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var cultureInfo = new CultureInfo("de-DE");
+
+ _ = builder.AppendFormat(
+ cultureInfo,
+ "Values: {0:N2}, {1}, {2}, {3:F2}",
+ 1234.56,
+ "test",
+ true,
+ 3.14
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1.234,56, test, True, 3,14");
+ }
+
+ [Test]
+ public async Task AppendFormat_WithProvider_NullProvider_Should_Use_CurrentCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var originalCulture = CultureInfo.CurrentCulture;
+
+ try
+ {
+ CultureInfo.CurrentCulture = new CultureInfo("de-DE");
+#pragma warning disable S3220 // Method calls should not resolve ambiguously to overloads with "params"
+ _ = builder.AppendFormat(null, "Value: {0:N2}", 1234.56);
+#pragma warning restore S3220 // Method calls should not resolve ambiguously to overloads with "params"
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 1.234,56");
+ }
+ finally
+ {
+ CultureInfo.CurrentCulture = originalCulture;
+ }
+ }
+
+ [Test]
+ public async Task AppendFormat_Multiple_Calls_Should_Append_Sequentially()
+ {
+ var builder = new CSharpCodeBuilder(20);
+
+ _ = builder
+ .AppendFormat(CultureInfo.InvariantCulture, "First: {0}", 1)
+ .AppendFormat(CultureInfo.InvariantCulture, " Second: {0}", 2)
+ .AppendFormat(CultureInfo.InvariantCulture, " Third: {0}", 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("First: 1 Second: 2 Third: 3");
+ }
+
+ [Test]
+ public async Task AppendFormat_With_NonSequentialFormatItems_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(20);
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Values: {1}, {0}, {2}",
+ "A",
+ "B",
+ "C"
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: B, A, C");
+ }
+
+ [Test]
+ public async Task AppendFormat_With_RepeatedFormatItems_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(20);
+
+ _ = builder.AppendFormat(CultureInfo.InvariantCulture, "Value: {0}, repeat: {0}", "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: test, repeat: test");
+ }
+
+ [Test]
+ public async Task AppendFormat_WithComplexFormatting_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(30);
+ var date = new DateTime(2023, 1, 15, 0, 0, 0, DateTimeKind.Utc);
+
+ _ = builder.AppendFormat(
+ CultureInfo.InvariantCulture,
+ "Date: {0:yyyy-MM-dd}, Value: {1:X8}",
+ date,
+ 255
+ );
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Date: 2023-01-15, Value: 000000FF");
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs
new file mode 100644
index 0000000..9cd9c69
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs
@@ -0,0 +1,462 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendIf_Boolean_True_Condition_True_Should_Append_TrueString()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("true");
+ }
+
+ [Test]
+ public async Task AppendIf_Boolean_False_Condition_True_Should_Append_FalseString()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, false);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("false");
+ }
+
+ [Test]
+ public async Task AppendIf_Boolean_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_Boolean_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, true);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_Char_Condition_True_Should_Append_Character()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, 'x');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("x");
+ }
+
+ [Test]
+ public async Task AppendIf_Char_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, 'x');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_Char_Should_Handle_Special_Characters_When_Condition_True()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, '{');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("{" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendIf_Char_Should_Not_Handle_Special_Characters_When_Condition_False()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, '{');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_Char_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, 'x');
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_Char_With_RepeatCount_Condition_True_Should_Append_Repeated_Character()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, 'x', 5);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("xxxxx");
+ }
+
+ [Test]
+ public async Task AppendIf_Char_With_RepeatCount_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, 'x', 5);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_Char_With_RepeatCount_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, 'x', 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_Condition_True_Should_Append_All_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ _ = builder.AppendIf(true, chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ _ = builder.AppendIf(false, chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_Null_Condition_True_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, (char[]?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ var result = builder.AppendIf(true, chars);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_With_StartIndex_And_Count_Condition_True_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ _ = builder.AppendIf(true, chars, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ _ = builder.AppendIf(false, chars, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_CharArray_With_StartIndex_And_Count_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ var result = builder.AppendIf(true, chars, 1, 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_CharPointer_Condition_True_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ _ = builder.AppendIf(true, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task AppendIf_CharPointer_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ _ = builder.AppendIf(false, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_CharPointer_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+ CSharpCodeBuilder result;
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ result = builder.AppendIf(true, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_Condition_True_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ _ = builder.AppendIf(true, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ _ = builder.AppendIf(false, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_Empty_Condition_True_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = ReadOnlyMemory.Empty;
+
+ _ = builder.AppendIf(true, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ var result = builder.AppendIf(true, memory);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_With_StartIndex_And_Count_Condition_True_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ _ = builder.AppendIf(true, memory, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ _ = builder.AppendIf(false, memory, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlyMemory_With_StartIndex_And_Count_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ var result = builder.AppendIf(true, memory, 1, 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_String_Condition_True_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, "abc");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc");
+ }
+
+ [Test]
+ public async Task AppendIf_String_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, "abc");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_String_Null_Condition_True_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, (string?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_String_Empty_Condition_True_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, string.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_String_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, "abc");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_String_With_StartIndex_And_Count_Condition_True_Should_Append_Specified_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, "abcdef", 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd");
+ }
+
+ [Test]
+ public async Task AppendIf_String_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, "abcdef", 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendIf_String_With_StartIndex_And_Count_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, "abcdef", 1, 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_Multiple_Calls_Should_Respect_Conditions()
+ {
+ var builder = new CSharpCodeBuilder(20);
+
+ _ = builder
+ .AppendIf(true, "Hello")
+ .AppendIf(false, " Skipped")
+ .AppendIf(true, " World")
+ .AppendIf(true, '!');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello World!");
+ }
+
+ [Test]
+ public async Task AppendIf_Should_Apply_Indentation_When_Condition_True()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ _ = builder.AppendLine();
+
+ _ = builder.AppendIf(true, "test");
+
+ var expected = Environment.NewLine + " test";
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendIf_Should_Not_Apply_Indentation_When_Condition_False()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ _ = builder.AppendLine();
+
+ _ = builder.AppendIf(false, "test");
+
+ var expected = Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendIf_Chaining_Should_Work_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(30);
+
+ var result = builder.AppendIf(true, "a").AppendIf(false, "b").AppendIf(true, "c");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("ac");
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs
new file mode 100644
index 0000000..f49d893
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs
@@ -0,0 +1,265 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendLine_Empty_Should_Append_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine();
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_String_Should_Append_String_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine("Hello World");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello World" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_String_Null_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine((string?)null);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_String_Empty_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine(string.Empty);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlyMemory_Should_Append_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var memory = "Hello World".AsMemory();
+
+ var result = builder.AppendLine(memory);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello World" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlyMemory_Empty_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var memory = ReadOnlyMemory.Empty;
+
+ var result = builder.AppendLine(memory);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlyMemory_With_StartIndex_And_Count_Should_Append_Subset_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var memory = "Hello World".AsMemory();
+
+ var result = builder.AppendLine(memory, 6, 5);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("World" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_CharArray_Should_Append_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var chars = "Hello".ToCharArray();
+
+ var result = builder.AppendLine(chars);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_CharArray_Null_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine((char[]?)null);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_CharArray_Empty_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var chars = Array.Empty();
+
+ var result = builder.AppendLine(chars);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_CharArray_With_StartIndex_And_Count_Should_Append_Subset_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var chars = "Hello World".ToCharArray();
+
+ var result = builder.AppendLine(chars, 6, 5);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("World" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Char_Should_Append_Character_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine('X');
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("X" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Char_With_RepeatCount_Should_Append_Repeated_Character_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine('X', 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("XXX" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Bool_True_Should_Append_True_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine(true);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("true" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Bool_False_Should_Append_False_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine(false);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("false" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Multiple_Should_Create_Multiple_Lines()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine("First").AppendLine("Second").AppendLine("Third");
+
+ var expected =
+ "First"
+ + Environment.NewLine
+ + "Second"
+ + Environment.NewLine
+ + "Third"
+ + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLine_With_Indentation_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendLine("Hello");
+
+ var expected = Environment.NewLine + " Hello" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLine_Unsafe_CharPointer_Should_Append_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var text = "Hello";
+ CSharpCodeBuilder result;
+ string builderResult;
+
+ unsafe
+ {
+ fixed (char* ptr = text)
+ {
+ result = builder.AppendLine(ptr, text.Length);
+ }
+ }
+
+ builderResult = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builderResult).IsEqualTo("Hello" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Unsafe_CharPointer_Null_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ CSharpCodeBuilder result;
+ string builderResult;
+
+ unsafe
+ {
+ result = builder.AppendLine(null, 0);
+ }
+
+ builderResult = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builderResult).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_Unsafe_CharPointer_Negative_Length_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder();
+ var text = "Hello";
+ CSharpCodeBuilder result;
+ string builderResult;
+
+ unsafe
+ {
+ fixed (char* ptr = text)
+ {
+ result = builder.AppendLine(ptr, -1);
+ }
+ }
+
+ builderResult = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builderResult).IsEqualTo(Environment.NewLine);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs
new file mode 100644
index 0000000..ec28c47
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs
@@ -0,0 +1,501 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendLineIf_NoParameters_Condition_True_Should_Append_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_NoParameters_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_NoParameters_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_String_Condition_True_Should_Append_String_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("test" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_String_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_String_Null_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, (string?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_String_Empty_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, string.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_String_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true, "test");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_Condition_True_Should_Append_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ _ = builder.AppendLineIf(true, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ _ = builder.AppendLineIf(false, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_Empty_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = ReadOnlyMemory.Empty;
+
+ _ = builder.AppendLineIf(true, memory);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abc".AsMemory();
+
+ var result = builder.AppendLineIf(true, memory);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_With_StartIndex_And_Count_Condition_True_Should_Append_Specified_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ _ = builder.AppendLineIf(true, memory, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ _ = builder.AppendLineIf(false, memory, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlyMemory_With_StartIndex_And_Count_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var memory = "abcde".AsMemory();
+
+ var result = builder.AppendLineIf(true, memory, 1, 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_Condition_True_Should_Append_All_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ _ = builder.AppendLineIf(true, chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ _ = builder.AppendLineIf(false, chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_Null_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, (char[]?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_Empty_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = Array.Empty();
+
+ _ = builder.AppendLineIf(true, chars);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c' };
+
+ var result = builder.AppendLineIf(true, chars);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_With_StartIndex_And_Count_Condition_True_Should_Append_Specified_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ _ = builder.AppendLineIf(true, chars, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("bcd" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ _ = builder.AppendLineIf(false, chars, 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharArray_With_StartIndex_And_Count_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = new[] { 'a', 'b', 'c', 'd', 'e' };
+
+ var result = builder.AppendLineIf(true, chars, 1, 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharPointer_Condition_True_Should_Append_Characters_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ _ = builder.AppendLineIf(true, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("abc" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharPointer_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ _ = builder.AppendLineIf(false, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_CharPointer_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var chars = "abc".ToCharArray();
+ CSharpCodeBuilder result;
+
+ unsafe
+ {
+ fixed (char* ptr = chars)
+ {
+ result = builder.AppendLineIf(true, ptr, chars.Length);
+ }
+ }
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_Condition_True_Should_Append_Character_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, 'x');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("x" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, 'x');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_Should_Handle_Special_Characters_When_Condition_True()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, '{');
+
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("{" + Environment.NewLine + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_Should_Not_Handle_Special_Characters_When_Condition_False()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, '{');
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true, 'x');
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_With_RepeatCount_Condition_True_Should_Append_Repeated_Character_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, 'x', 5);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("xxxxx" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_With_RepeatCount_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, 'x', 5);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_Char_With_RepeatCount_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true, 'x', 3);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Boolean_True_Condition_True_Should_Append_TrueString_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("true" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Boolean_False_Condition_True_Should_Append_FalseString_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, false);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("false" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Boolean_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("");
+ }
+
+ [Test]
+ public async Task AppendLineIf_Boolean_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true, true);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Multiple_Calls_Should_Respect_Conditions()
+ {
+ var builder = new CSharpCodeBuilder(50);
+
+ _ = builder
+ .AppendLineIf(true, "Line 1")
+ .AppendLineIf(false, "Skipped Line")
+ .AppendLineIf(true, "Line 2")
+ .AppendLineIf(true);
+
+ var expected =
+ "Line 1" + Environment.NewLine + "Line 2" + Environment.NewLine + Environment.NewLine;
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Should_Apply_Indentation_When_Condition_True()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ _ = builder.AppendLine();
+
+ _ = builder.AppendLineIf(true, "test");
+
+ var expected = Environment.NewLine + " test" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Should_Not_Apply_Indentation_When_Condition_False()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ _ = builder.AppendLine();
+
+ _ = builder.AppendLineIf(false, "test");
+
+ var expected = Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Chaining_Should_Work_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(50);
+
+ var result = builder
+ .AppendLineIf(true, "a")
+ .AppendLineIf(false, "b")
+ .AppendLineIf(true, "c");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+
+ var expected = "a" + Environment.NewLine + "c" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineIf_Mixed_With_AppendIf_Should_Work_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(50);
+
+ _ = builder
+ .AppendIf(true, "Start: ")
+ .AppendLineIf(true, "First Line")
+ .AppendIf(false, "Skipped")
+ .AppendLineIf(true, "Second Line")
+ .AppendIf(true, "End");
+
+ var expected =
+ "Start: First Line" + Environment.NewLine + "Second Line" + Environment.NewLine + "End";
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs
new file mode 100644
index 0000000..2e76e80
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs
@@ -0,0 +1,96 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task Clear_Empty_Builder_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.Clear();
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task Clear_Builder_With_Content_Should_Remove_All_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+
+ var result = builder.Clear();
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task Clear_Should_Reset_Indentation_Level()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ _ = builder.Clear();
+ _ = builder.AppendLine().Append("World");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "World");
+ }
+
+ [Test]
+ public async Task Clear_Should_Allow_Method_Chaining()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello");
+
+ var result = builder.Clear().Append("World");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("World");
+ }
+
+ [Test]
+ public async Task Clear_Multiple_Times_Should_Work()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("First");
+ _ = builder.Clear();
+ _ = builder.Append("Second");
+ _ = builder.Clear();
+ _ = builder.Append("Third");
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo("Third");
+ }
+
+ [Test]
+ public async Task Clear_Should_Preserve_UseTabs_Setting()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+ _ = builder.Append("Hello");
+
+ _ = builder.Clear();
+
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(true);
+ }
+
+ [Test]
+ public async Task Clear_Should_Preserve_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(100);
+ var originalCapacity = builder.Capacity;
+ _ = builder.Append("Hello World");
+
+ _ = builder.Clear();
+
+ _ = await Assert.That(builder.Capacity).IsEqualTo(originalCapacity);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Constructor.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Constructor.cs
new file mode 100644
index 0000000..5706a3f
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Constructor.cs
@@ -0,0 +1,47 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task Constructor_Default_Should_Create_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = await Assert.That(builder).IsNotNull();
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ _ = await Assert.That(builder.Capacity).IsGreaterThan(0);
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(false);
+ }
+
+ [Test]
+ public async Task Constructor_WithCapacity_Should_Create_Instance_With_Specified_Capacity()
+ {
+ var initialCapacity = 100;
+ var builder = new CSharpCodeBuilder(initialCapacity);
+
+ _ = await Assert.That(builder).IsNotNull();
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ _ = await Assert.That(builder.Capacity).IsGreaterThanOrEqualTo(initialCapacity);
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(false);
+ }
+
+ [Test]
+ public async Task Constructor_WithZeroCapacity_Should_Create_Instance()
+ {
+ var builder = new CSharpCodeBuilder(0);
+
+ _ = await Assert.That(builder).IsNotNull();
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(false);
+ }
+
+ [Test]
+ public async Task Constructor_WithNegativeCapacity_Should_Throw_ArgumentOutOfRangeException() =>
+ _ = await Assert.ThrowsAsync(() =>
+ {
+ _ = new CSharpCodeBuilder(-1);
+ return Task.CompletedTask;
+ });
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs
new file mode 100644
index 0000000..ef49ba0
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs
@@ -0,0 +1,474 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendXmlDoc_WithContent_Should_AppendSingleLineComment()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDoc("This is a comment");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// This is a comment" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDoc_WithNullContent_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDoc(null);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDoc_WithEmptyContent_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDoc("");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSummary_WithSingleLine_Should_AppendSummaryElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocSummary("This is a summary");
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// This is a summary"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSummary_WithMultipleLines_Should_AppendSummaryElementWithAllLines()
+ {
+ var builder = new CSharpCodeBuilder();
+ var summaryLines = new[] { "First line", "Second line", "Third line" };
+
+ var result = builder.AppendXmlDocSummary(summaryLines);
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// First line"
+ + Environment.NewLine
+ + "/// Second line"
+ + Environment.NewLine
+ + "/// Third line"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSummary_WithEmptyAndNullLines_Should_SkipEmptyLines()
+ {
+ var builder = new CSharpCodeBuilder();
+ var summaryLines = new List { "First line", "", null, "Last line" };
+
+ var result = builder.AppendXmlDocSummary(summaryLines.Where(x => x is not null)!);
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// First line"
+ + Environment.NewLine
+ + "/// Last line"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocParam_WithValidParameters_Should_AppendParamElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocParam("paramName", "Parameter description");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo(
+ "/// Parameter description" + Environment.NewLine
+ );
+ }
+
+ [Test]
+ public async Task AppendXmlDocParam_WithNullName_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocParam(null, "Parameter description");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocParams_WithMultipleParameters_Should_AppendAllParamElements()
+ {
+ var builder = new CSharpCodeBuilder();
+ var parameters = new List<(string Name, string Description)>
+ {
+ ("param1", "First parameter"),
+ ("param2", "Second parameter"),
+ };
+
+ var result = builder.AppendXmlDocParams(parameters);
+
+ var expected =
+ "/// First parameter"
+ + Environment.NewLine
+ + "/// Second parameter"
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocReturns_WithDescription_Should_AppendReturnsElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocReturns("The result value");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// The result value" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocRemarks_WithSingleLine_Should_AppendRemarksElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocRemarks("This is a remark");
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// This is a remark"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocException_WithValidParameters_Should_AppendExceptionElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocException(
+ "ArgumentNullException",
+ "Thrown when argument is null"
+ );
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo(
+ "/// Thrown when argument is null"
+ + Environment.NewLine
+ );
+ }
+
+ [Test]
+ public async Task AppendXmlDocExample_WithContent_Should_AppendExampleElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocExample("var example = new Example();");
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// var example = new Example();"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSee_WithCref_Should_AppendSeeElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocSee("System.String");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_WithCref_Should_AppendSeeAlsoElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocSeeAlso("System.Object");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocValue_WithDescription_Should_AppendValueElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocValue("The value of the property");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// The value of the property" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocTypeParam_WithValidParameters_Should_AppendTypeParamElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocTypeParam("T", "The generic type parameter");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo(
+ "/// The generic type parameter"
+ + Environment.NewLine
+ );
+ }
+
+ [Test]
+ public async Task AppendXmlDocInheritDoc_WithoutCref_Should_AppendInheritDocElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocInheritDoc();
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocInheritDoc_WithCref_Should_AppendInheritDocElementWithCref()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocInheritDoc("BaseClass.Method");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocCustomElement_WithContentAndAttributes_Should_AppendCustomElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocCustomElement(
+ "custom",
+ "Custom content",
+ "attr=\"value\""
+ );
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// Custom content" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocCustomElement_WithoutContent_Should_AppendSelfClosingElement()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocCustomElement("custom", null, "attr=\"value\"");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task XmlDocumentationMethods_Should_SupportMethodChaining()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder
+ .AppendXmlDocSummary("Method summary")
+ .AppendXmlDocParam("param1", "First parameter")
+ .AppendXmlDocParam("param2", "Second parameter")
+ .AppendXmlDocReturns("Return value description")
+ .AppendXmlDocRemarks("Additional remarks");
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// Method summary"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// First parameter"
+ + Environment.NewLine
+ + "/// Second parameter"
+ + Environment.NewLine
+ + "/// Return value description"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Additional remarks"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task XmlDocumentationMethods_WithIndentation_Should_RespectIndentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+
+ var result = builder
+ .AppendXmlDocSummary("Indented summary")
+ .AppendXmlDocParam("param", "Parameter description");
+
+ var expected =
+ " /// "
+ + Environment.NewLine
+ + " /// Indented summary"
+ + Environment.NewLine
+ + " /// "
+ + Environment.NewLine
+ + " /// Parameter description"
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task XmlDocumentationMethods_AfterContent_Should_StartOnNewLine()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder
+ .Append("public class MyClass")
+ .AppendXmlDocSummary("Method summary")
+ .AppendXmlDocParam("param", "Parameter description")
+ .Append("public void MyMethod(string param) { }");
+
+ var expected =
+ "public class MyClass"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Method summary"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Parameter description"
+ + Environment.NewLine
+ + "public void MyMethod(string param) { }";
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task XmlDocumentationMethods_AtStartOfBuilder_Should_NotAddExtraNewLine()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder
+ .AppendXmlDocSummary("Method summary")
+ .AppendXmlDocParam("param", "Parameter description");
+
+ var expected =
+ "/// "
+ + Environment.NewLine
+ + "/// Method summary"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Parameter description"
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task XmlDocumentationMethods_AfterNewLine_Should_NotAddExtraNewLine()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder
+ .AppendLine("public class MyClass")
+ .AppendXmlDocSummary("Method summary")
+ .AppendXmlDocParam("param", "Parameter description");
+
+ var expected =
+ "public class MyClass"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Method summary"
+ + Environment.NewLine
+ + "/// "
+ + Environment.NewLine
+ + "/// Parameter description"
+ + Environment.NewLine;
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.EnsureCapacity.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.EnsureCapacity.cs
new file mode 100644
index 0000000..1d507dd
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.EnsureCapacity.cs
@@ -0,0 +1,103 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task EnsureCapacity_Smaller_Than_Current_Should_Not_Change_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(100);
+ var originalCapacity = builder.Capacity;
+
+ var result = builder.EnsureCapacity(50);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Capacity).IsEqualTo(originalCapacity);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Larger_Than_Current_Should_Increase_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var originalCapacity = builder.Capacity;
+
+ var result = builder.EnsureCapacity(200);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Capacity).IsGreaterThanOrEqualTo(200);
+ _ = await Assert.That(builder.Capacity).IsGreaterThan(originalCapacity);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Equal_To_Current_Should_Not_Change_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(100);
+ var originalCapacity = builder.Capacity;
+
+ var result = builder.EnsureCapacity(originalCapacity);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Capacity).IsEqualTo(originalCapacity);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Zero_Should_Not_Change_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(50);
+ var originalCapacity = builder.Capacity;
+
+ var result = builder.EnsureCapacity(0);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.Capacity).IsEqualTo(originalCapacity);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Should_Not_Affect_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+ var originalContent = builder.ToString();
+
+ _ = builder.EnsureCapacity(200);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(originalContent);
+ _ = await Assert.That(builder.Length).IsEqualTo(originalContent.Length);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Should_Allow_Method_Chaining()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.EnsureCapacity(100).Append("Hello");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello");
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Multiple_Calls_Should_Work()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.EnsureCapacity(50);
+ var capacity50 = builder.Capacity;
+
+ _ = builder.EnsureCapacity(100);
+ var capacity100 = builder.Capacity;
+
+ _ = await Assert.That(capacity100).IsGreaterThanOrEqualTo(100);
+ _ = await Assert.That(capacity100).IsGreaterThanOrEqualTo(capacity50);
+ }
+
+ [Test]
+ public async Task EnsureCapacity_Negative_Value_Should_Throw_ArgumentOutOfRangeException() =>
+ _ = await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.EnsureCapacity(-1);
+ return Task.CompletedTask;
+ });
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs
new file mode 100644
index 0000000..793af39
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs
@@ -0,0 +1,167 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task IncrementIndent_Should_Increase_Indentation_Level()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello");
+ }
+
+ [Test]
+ public async Task IncrementIndent_Multiple_Times_Should_Increase_Indentation_Level()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello"); // 8 spaces (2 * 4)
+ }
+
+ [Test]
+ public async Task IncrementIndent_With_Tabs_Should_Use_Tab_Characters()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "\tHello");
+ }
+
+ [Test]
+ public async Task IncrementIndent_Multiple_With_Tabs_Should_Use_Multiple_Tab_Characters()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "\t\t\tHello");
+ }
+
+ [Test]
+ public async Task DecrementIndent_Should_Decrease_Indentation_Level()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+
+ builder.DecrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello"); // 4 spaces (1 * 4)
+ }
+
+ [Test]
+ public async Task DecrementIndent_To_Zero_Should_Remove_All_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+
+ builder.DecrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "Hello");
+ }
+
+ [Test]
+ public async Task DecrementIndent_Below_Zero_Should_Handle_Gracefully()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ builder.DecrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "Hello");
+ }
+
+ [Test]
+ public async Task IncrementIndent_And_DecrementIndent_Should_Balance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ builder.DecrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello"); // 4 spaces (1 * 4)
+ }
+
+ [Test]
+ public async Task IncrementIndent_Should_Not_Affect_Existing_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello");
+
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("World");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo("Hello" + Environment.NewLine + " World");
+ }
+
+ [Test]
+ public async Task DecrementIndent_Should_Not_Affect_Existing_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ builder.DecrementIndent();
+ _ = builder.AppendLine().Append("World");
+
+ var result = builder.ToString();
+ _ = await Assert
+ .That(result)
+ .IsEqualTo(Environment.NewLine + " Hello" + Environment.NewLine + "World");
+ }
+
+ [Test]
+ public async Task IncrementIndent_And_DecrementIndent_Multiple_Operations_Should_Work()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ // Simulate nested code blocks - the braces automatically handle indentation
+ _ = builder.Append("class MyClass");
+ _ = builder.Append("{"); // This automatically increments indent and adds newline
+ _ = builder.Append("public void Method()");
+ _ = builder.Append("{"); // This automatically increments indent and adds newline
+ _ = builder.Append("Console.WriteLine(\"Hello\");");
+ _ = builder.Append("}"); // This automatically decrements indent but doesn't add newline
+ _ = builder.Append("}"); // This automatically decrements indent but doesn't add newline
+
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ // The actual output based on the CSharpCodeBuilder's behavior
+ var expected = """
+ class MyClass{
+ public void Method(){
+ Console.WriteLine("Hello");
+ }
+ }
+ """;
+
+ _ = await Assert.That(result).IsEqualTo(expected);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Properties.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Properties.cs
new file mode 100644
index 0000000..d5b7a08
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Properties.cs
@@ -0,0 +1,160 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task Capacity_Get_Should_Return_Current_Capacity()
+ {
+ var builder = new CSharpCodeBuilder(100);
+
+ var capacity = builder.Capacity;
+
+ _ = await Assert.That(capacity).IsGreaterThanOrEqualTo(100);
+ }
+
+ [Test]
+ public async Task Capacity_After_EnsureCapacity_Should_Be_Updated()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var originalCapacity = builder.Capacity;
+
+ _ = builder.EnsureCapacity(200);
+
+ _ = await Assert.That(builder.Capacity).IsGreaterThan(originalCapacity);
+ _ = await Assert.That(builder.Capacity).IsGreaterThanOrEqualTo(200);
+ }
+
+ [Test]
+ public async Task Length_Empty_Builder_Should_Return_Zero()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var length = builder.Length;
+
+ _ = await Assert.That(length).IsEqualTo(0);
+ }
+
+ [Test]
+ public async Task Length_After_Append_Should_Return_Correct_Length()
+ {
+ var builder = new CSharpCodeBuilder();
+ var text = "Hello World";
+
+ _ = builder.Append(text);
+
+ _ = await Assert.That(builder.Length).IsEqualTo(text.Length);
+ }
+
+ [Test]
+ public async Task Length_After_Multiple_Appends_Should_Return_Total_Length()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.Append("Hello").Append(" ").Append("World");
+
+ _ = await Assert.That(builder.Length).IsEqualTo(11);
+ }
+
+ [Test]
+ public async Task Length_After_Clear_Should_Return_Zero()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+
+ _ = builder.Clear();
+
+ _ = await Assert.That(builder.Length).IsEqualTo(0);
+ }
+
+ [Test]
+ public async Task Length_After_AppendLine_Should_Include_Newline_Characters()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine("Hello");
+
+ _ = await Assert.That(builder.Length).IsEqualTo(5 + Environment.NewLine.Length);
+ }
+
+ [Test]
+ public async Task UseTabs_Default_Should_Be_False()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var useTabs = builder.UseTabs;
+
+ _ = await Assert.That(useTabs).IsEqualTo(false);
+ }
+
+ [Test]
+ public async Task UseTabs_Set_To_True_Should_Update_Property()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(true);
+ }
+
+ [Test]
+ public async Task UseTabs_Set_To_False_Should_Update_Property()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+
+ builder.UseTabs = false;
+
+ _ = await Assert.That(builder.UseTabs).IsEqualTo(false);
+ }
+
+ [Test]
+ public async Task UseTabs_True_Should_Use_Tab_Character_For_Indentation()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "\tHello");
+ }
+
+ [Test]
+ public async Task UseTabs_False_Should_Use_Spaces_For_Indentation()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = false };
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello");
+ }
+
+ [Test]
+ public async Task UseTabs_Multiple_Indent_Levels_With_Tabs_Should_Use_Multiple_Tabs()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "\t\t\tHello");
+ }
+
+ [Test]
+ public async Task UseTabs_Multiple_Indent_Levels_With_Spaces_Should_Use_Multiple_Space_Groups()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = false };
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello"); // 12 spaces (3 * 4)
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.ToString.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.ToString.cs
new file mode 100644
index 0000000..a2c8d1d
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.ToString.cs
@@ -0,0 +1,88 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task ToString_Empty_Should_Return_Empty_String()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task ToString_WithContent_Should_Return_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo("Hello World");
+ }
+
+ [Test]
+ public async Task ToString_WithMultipleAppends_Should_Return_All_Content()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello").Append(" ").Append("World");
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo("Hello World");
+ }
+
+ [Test]
+ public async Task ToString_WithIndentation_Should_Return_Content_With_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + " Hello");
+ }
+
+ [Test]
+ public async Task ToString_WithTabs_Should_Return_Content_With_Tab_Indentation()
+ {
+ var builder = new CSharpCodeBuilder { UseTabs = true };
+ builder.IncrementIndent();
+ _ = builder.AppendLine().Append("Hello");
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo(Environment.NewLine + "\tHello");
+ }
+
+ [Test]
+ public async Task ToString_AfterClear_Should_Return_Empty_String()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+ _ = builder.Clear();
+
+ var result = builder.ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task ToString_Multiple_Calls_Should_Return_Same_Result()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("Hello World");
+
+ var result1 = builder.ToString();
+ var result2 = builder.ToString();
+
+ _ = await Assert.That(result1).IsEqualTo("Hello World");
+ _ = await Assert.That(result2).IsEqualTo("Hello World");
+ _ = await Assert.That(result1).IsEqualTo(result2);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.cs
new file mode 100644
index 0000000..cc9e660
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.cs
@@ -0,0 +1,3 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+public partial class CSharpCodeBuilderTests { }
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/NetEvolve.CodeBuilder.Tests.Unit.csproj b/tests/NetEvolve.CodeBuilder.Tests.Unit/NetEvolve.CodeBuilder.Tests.Unit.csproj
new file mode 100644
index 0000000..077ef45
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/NetEvolve.CodeBuilder.Tests.Unit.csproj
@@ -0,0 +1,19 @@
+
+
+ $(_TestTargetFrameworks)
+ Exe
+ true
+ $(NoWarn);CA2000;S2930
+ true
+
+
+
+
+
+
+
+
+
+
+
+