diff --git a/.editorconfig b/.editorconfig
index fa80a79..9c53899 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -87,10 +87,6 @@ insert_final_newline = false
[*.sln]
indent_style = tab
-[*.{received,verified}.txt]
-insert_final_newline = false
-trim_trailing_whitespace = false
-
[*.{cs,csx,vb,vbx}]
# .NET Code Style Settings
# See https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
@@ -132,9 +128,16 @@ dotnet_naming_style.all_const.capitalization = pascal
dotnet_naming_symbols.all_const.applicable_kinds = field
dotnet_naming_symbols.all_const.required_modifiers = const
dotnet_naming_rule.all_const.severity = error
-dotnet_naming_rule.all_const.style = all_elements
+dotnet_naming_rule.all_const.style = all_const
dotnet_naming_rule.all_const.symbols = all_const
+dotnet_naming_style.all_static_readonly.capitalization = pascal_case
+dotnet_naming_symbols.all_static_readonly.applicable_kinds = field
+dotnet_naming_symbols.all_static_readonly.required_modifiers = static, readonly
+dotnet_naming_rule.all_static_readonly.severity = error
+dotnet_naming_rule.all_static_readonly.style = all_static_readonly
+dotnet_naming_rule.all_static_readonly.symbols = all_static_readonly
+
dotnet_naming_style.all_fields.required_prefix = _
dotnet_naming_style.all_fields.capitalization = camel_case
dotnet_naming_symbols.all_fields.applicable_kinds = field
@@ -267,18 +270,6 @@ dotnet_diagnostic.IDE0290.severity = sugges
# [CSharpier] Incompatible rules deactivated
# https://csharpier.com/docs/IntegratingWithLinters#code-analysis-rules
dotnet_diagnostic.IDE0055.severity = none
-dotnet_diagnostic.SA1000.severity = none
-dotnet_diagnostic.SA1009.severity = none
-dotnet_diagnostic.SA1111.severity = none
-dotnet_diagnostic.SA1118.severity = none
-dotnet_diagnostic.SA1137.severity = none
-dotnet_diagnostic.SA1413.severity = none
-dotnet_diagnostic.SA1500.severity = none
-dotnet_diagnostic.SA1501.severity = none
-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
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs
index 2f198a9..7b91668 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Append.cs
@@ -1,15 +1,15 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System;
-public partial record CSharpCodeBuilder
+public partial class 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.
+ /// Appends either or based on the value.
public CSharpCodeBuilder Append(bool value)
{
EnsureIndented();
@@ -36,6 +36,16 @@ public CSharpCodeBuilder Append(char value, int repeatCount)
///
/// The character to append.
/// The current instance to allow for method chaining.
+ ///
+ /// The following characters receive special treatment:
+ ///
+ /// - '\0' — ignored; the method returns without appending.
+ /// - '\n' or '\r' — treated as a line terminator; equivalent to calling .
+ /// - '{' or '[' — appended with the current indentation, then the indentation level is incremented and a line terminator is added.
+ /// - '}' or ']' — the indentation level is decremented first, then the character is appended with the new indentation level, followed by a line terminator.
+ ///
+ /// All other characters are appended after applying the current indentation at the start of a new line.
+ ///
public CSharpCodeBuilder Append(char value)
{
if (value is '\0')
@@ -164,6 +174,53 @@ public CSharpCodeBuilder Append(ReadOnlyMemory value, int startIndex, int
return this;
}
+ ///
+ /// Appends a read-only span of characters to the current builder.
+ ///
+ /// The read-only span containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(ReadOnlySpan value)
+ {
+ if (value.IsEmpty)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+#if NETSTANDARD2_0
+ _ = _builder.Append(value.ToString());
+#else
+ _ = _builder.Append(value);
+#endif
+ return this;
+ }
+
+ ///
+ /// Appends a subset of a read-only span of characters to the current builder.
+ ///
+ /// The read-only span containing the characters to append.
+ /// The starting position in the span.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, the method returns without appending anything.
+ public CSharpCodeBuilder Append(ReadOnlySpan value, int startIndex, int count)
+ {
+ var slice = value.Slice(startIndex, count);
+ if (slice.IsEmpty)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+#if NETSTANDARD2_0
+ _ = _builder.Append(slice.ToString());
+#else
+ _ = _builder.Append(slice);
+#endif
+ return this;
+ }
+
///
/// Appends a subset of a string to the current builder.
///
@@ -189,7 +246,16 @@ public CSharpCodeBuilder Append(string? value, int startIndex, int count)
///
/// 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.
+ ///
+ /// null, an empty string, or "\0" are ignored; the method returns without appending.
+ /// The following single-character strings receive special treatment:
+ ///
+ /// - "\n", "\r", or "\r\n" — treated as a line terminator; equivalent to calling .
+ /// - "{" or "[" — appended with the current indentation, then the indentation level is incremented and a line terminator is added.
+ /// - "}" or "]" — the indentation level is decremented first; if the current position is mid-line, a line terminator is inserted before the character. The character is then appended with the new indentation level, followed by a line terminator. This behavior is consistent with .
+ ///
+ /// All other strings are appended after applying the current indentation at the start of a new line.
+ ///
public CSharpCodeBuilder Append(string? value)
{
if (string.IsNullOrEmpty(value) || value is "\0")
@@ -205,7 +271,10 @@ public CSharpCodeBuilder Append(string? value)
if (value is "}" or "]")
{
DecrementIndent();
- _ = AppendLine();
+ if (!_isNewline)
+ {
+ _ = AppendLine(); // Ensure we start a new line before the closing brace
+ }
}
EnsureIndented();
@@ -216,6 +285,10 @@ public CSharpCodeBuilder Append(string? value)
IncrementIndent();
_ = AppendLine();
}
+ else if (value is "}" or "]")
+ {
+ _ = AppendLine(); // Newline after closing brace, consistent with char overload
+ }
return this;
}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs
index 5cb118d..1d2245f 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendFormat.cs
@@ -4,7 +4,7 @@
using System.Globalization;
using System.Runtime.CompilerServices;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Appends a formatted string to the current builder using invariant culture.
@@ -45,4 +45,68 @@ public CSharpCodeBuilder AppendFormat(IFormatProvider? provider, string format,
_ = _builder.AppendFormat(provider, format, args);
return this;
}
+
+ ///
+ /// Appends a formattable string to the current builder using invariant culture.
+ ///
+ /// The formattable string to append.
+ /// The current instance to allow for method chaining.
+ /// If is , the method returns without appending anything.
+ public CSharpCodeBuilder AppendFormat(FormattableString? formattable)
+ {
+ if (formattable is null)
+ {
+ return this;
+ }
+
+ EnsureIndented();
+ _ = _builder.Append(formattable.ToString(CultureInfo.InvariantCulture));
+ return this;
+ }
+
+ ///
+ /// Appends a formatted string followed by a line terminator 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 AppendLineFormat(string format, object? arg0) =>
+ AppendFormat(CultureInfo.InvariantCulture, format, arg0).AppendLine();
+
+ ///
+ /// Appends a formatted string followed by a line terminator 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 AppendLineFormat(string format, params object?[] args) =>
+ AppendFormat(CultureInfo.InvariantCulture, format, args).AppendLine();
+
+ ///
+ /// Appends a formatted string followed by a line terminator 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.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineFormat(IFormatProvider? provider, string format, params object?[] args) =>
+ AppendFormat(provider, format, args).AppendLine();
+
+ ///
+ /// Appends a formattable string followed by a line terminator to the current builder using invariant culture.
+ ///
+ /// The formattable string to append.
+ /// The current instance to allow for method chaining.
+ /// If is , only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineFormat(FormattableString? formattable) => AppendFormat(formattable).AppendLine();
}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs
index 1feb663..fd1f07d 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendIf.cs
@@ -1,9 +1,9 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System;
using System.Runtime.CompilerServices;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Appends a boolean value to the current builder if the specified condition is true.
@@ -11,7 +11,7 @@ public partial record CSharpCodeBuilder
/// 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.
+ /// Appends either or based on the value if the condition is .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CSharpCodeBuilder AppendIf(bool condition, bool value) => condition ? Append(value) : this;
@@ -94,6 +94,29 @@ public unsafe CSharpCodeBuilder AppendIf(bool condition, char* value, int length
public CSharpCodeBuilder AppendIf(bool condition, ReadOnlyMemory value, int startIndex, int count) =>
condition ? Append(value, startIndex, count) : this;
+ ///
+ /// Appends a read-only span of characters to the current builder if the specified condition is .
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only span containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, ReadOnlySpan value) => condition ? Append(value) : this;
+
+ ///
+ /// Appends a subset of a read-only span of characters to the current builder if the specified condition is .
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only span containing the characters to append.
+ /// The starting position in the span.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, the method returns without appending anything.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendIf(bool condition, ReadOnlySpan 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.
///
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendInterpolated.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendInterpolated.cs
new file mode 100644
index 0000000..a562af4
--- /dev/null
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendInterpolated.cs
@@ -0,0 +1,181 @@
+#if NET6_0_OR_GREATER
+namespace NetEvolve.CodeBuilder;
+
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+public partial class CSharpCodeBuilder
+{
+ ///
+ /// Appends an interpolated string to the current builder.
+ ///
+ /// The interpolated string handler built by the compiler.
+ /// The current instance to allow for method chaining.
+ ///
+ ///
+ /// builder.AppendInterpolated($"public {typeName} {memberName}");
+ ///
+ ///
+ public CSharpCodeBuilder AppendInterpolated(
+ [InterpolatedStringHandlerArgument("")] ref CSharpInterpolatedStringHandler handler
+ ) => this;
+
+ ///
+ /// Appends an interpolated string followed by a line terminator to the current builder.
+ ///
+ /// The interpolated string handler built by the compiler.
+ /// The current instance to allow for method chaining.
+ ///
+ ///
+ /// builder.AppendLineInterpolated($"public class {className}");
+ ///
+ ///
+ public CSharpCodeBuilder AppendLineInterpolated(
+ [InterpolatedStringHandlerArgument("")] ref CSharpInterpolatedStringHandler handler
+ ) => AppendLine();
+
+ internal void HandlerEnsureIndented() => EnsureIndented();
+
+ internal void HandlerRawAppend(string? value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ _ = _builder.Append(value);
+ }
+ }
+
+ internal void HandlerRawAppend(ReadOnlySpan value)
+ {
+ if (!value.IsEmpty)
+ {
+ _ = _builder.Append(value);
+ }
+ }
+}
+
+///
+/// Custom interpolated string handler for .
+///
+///
+/// This handler is instantiated by the compiler when an interpolated string is passed to
+/// or .
+/// It appends each literal and formatted part directly to the builder, applying indentation before
+/// the first non-empty part on a new line.
+///
+[InterpolatedStringHandler]
+public ref struct CSharpInterpolatedStringHandler
+{
+ private readonly CSharpCodeBuilder _owner;
+ private bool _indentEnsured;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The total length of all literal parts (hint for capacity).
+ /// The number of formatted holes in the interpolated string.
+ /// The to append to.
+ public CSharpInterpolatedStringHandler(int literalLength, int formattedCount, CSharpCodeBuilder builder)
+ {
+ _owner = builder;
+ _indentEnsured = false;
+ }
+
+ private void EnsureIndented()
+ {
+ if (!_indentEnsured)
+ {
+ _owner.HandlerEnsureIndented();
+ _indentEnsured = true;
+ }
+ }
+
+ /// Appends a literal string part of the interpolated string.
+ /// The literal string to append.
+ public void AppendLiteral(string? value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return;
+ }
+
+ EnsureIndented();
+ _owner.HandlerRawAppend(value);
+ }
+
+ /// Appends a formatted value from the interpolated string.
+ /// The type of the value to format.
+ /// The value to append.
+ public void AppendFormatted(T value)
+ {
+ var str = value?.ToString();
+ if (string.IsNullOrEmpty(str))
+ {
+ return;
+ }
+
+ EnsureIndented();
+ _owner.HandlerRawAppend(str);
+ }
+
+ /// Appends a formatted value with a format string from the interpolated string.
+ /// The type of the value to format. Must implement .
+ /// The value to append.
+ /// The format string.
+ public void AppendFormatted(T value, string? format)
+ where T : System.IFormattable
+ {
+ var str = value?.ToString(format, CultureInfo.InvariantCulture);
+ if (string.IsNullOrEmpty(str))
+ {
+ return;
+ }
+
+ EnsureIndented();
+ _owner.HandlerRawAppend(str);
+ }
+
+ /// Appends a formatted value with alignment from the interpolated string.
+ /// The type of the value to format.
+ /// The value to append.
+ /// Minimum width; negative values left-align.
+ public void AppendFormatted(T value, int alignment)
+ {
+ var str = value?.ToString();
+ if (str is null)
+ {
+ return;
+ }
+
+ str = alignment >= 0 ? str.PadLeft(alignment) : str.PadRight(-alignment);
+ EnsureIndented();
+ _owner.HandlerRawAppend(str);
+ }
+
+ /// Appends a formatted value with alignment and format string from the interpolated string.
+ /// The type of the value to format. Must implement .
+ /// The value to append.
+ /// Minimum width; negative values left-align.
+ /// The format string.
+ public void AppendFormatted(T value, int alignment, string? format)
+ where T : System.IFormattable
+ {
+ var str = value?.ToString(format, CultureInfo.InvariantCulture) ?? string.Empty;
+ str = alignment >= 0 ? str.PadLeft(alignment) : str.PadRight(-alignment);
+ EnsureIndented();
+ _owner.HandlerRawAppend(str);
+ }
+
+ /// Appends a value from the interpolated string.
+ /// The span to append.
+ public void AppendFormatted(ReadOnlySpan value)
+ {
+ if (value.IsEmpty)
+ {
+ return;
+ }
+
+ EnsureIndented();
+ _owner.HandlerRawAppend(value);
+ }
+}
+#endif
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs
index b612b70..3079376 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLine.cs
@@ -1,9 +1,9 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System;
using System.Runtime.CompilerServices;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Appends a line terminator to the current builder.
@@ -51,6 +51,27 @@ public CSharpCodeBuilder AppendLine()
public CSharpCodeBuilder AppendLine(ReadOnlyMemory value, int startIndex, int count) =>
Append(value, startIndex, count).AppendLine();
+ ///
+ /// Appends a read-only span of characters followed by a line terminator to the current builder.
+ ///
+ /// The read-only span containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(ReadOnlySpan value) => Append(value).AppendLine();
+
+ ///
+ /// Appends a subset of a read-only span of characters followed by a line terminator to the current builder.
+ ///
+ /// The read-only span containing the characters to append.
+ /// The starting position in the span.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLine(ReadOnlySpan value, int startIndex, int count) =>
+ Append(value, startIndex, count).AppendLine();
+
///
/// Appends an array of characters followed by a line terminator to the current builder.
///
@@ -105,7 +126,7 @@ public CSharpCodeBuilder AppendLine(char[]? value, int startIndex, int charCount
///
/// 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.
+ /// Appends either or 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
index 18e6c6b..bf8827f 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLineIf.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.AppendLineIf.cs
@@ -1,9 +1,9 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System;
using System.Runtime.CompilerServices;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Appends a line terminator to the current builder if the specified condition is true.
@@ -47,6 +47,30 @@ public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlyMemory value
public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlyMemory value, int startIndex, int count) =>
condition ? AppendLine(value, startIndex, count) : this;
+ ///
+ /// Appends a read-only span of characters followed by a line terminator to the current builder if the specified condition is .
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only span containing the characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlySpan value) =>
+ condition ? AppendLine(value) : this;
+
+ ///
+ /// Appends a subset of a read-only span of characters followed by a line terminator to the current builder if the specified condition is .
+ ///
+ /// The condition that determines whether to append the value.
+ /// The read-only span containing the characters to append.
+ /// The starting position in the span.
+ /// The number of characters to append.
+ /// The current instance to allow for method chaining.
+ /// If the span is empty, only the line terminator is appended.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CSharpCodeBuilder AppendLineIf(bool condition, ReadOnlySpan 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.
///
@@ -109,7 +133,7 @@ public CSharpCodeBuilder AppendLineIf(bool condition, char value, int repeatCoun
/// 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.
+ /// Appends either or based on the value if the condition is .
[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
index 036afea..9be24a9 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Clear.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Clear.cs
@@ -1,19 +1,21 @@
namespace NetEvolve.CodeBuilder;
-public partial record CSharpCodeBuilder
+public partial class 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.
+ /// This method removes all characters from the internal ,
+ /// resets the indentation level to zero, and resets the internal newline-tracking state,
+ /// effectively providing a clean slate for building new content.
///
public CSharpCodeBuilder Clear()
{
_ = _builder.Clear();
- _ = Interlocked.Exchange(ref _indentLevel, 0);
+ _indentLevel = 0;
+ _isNewline = true;
return this;
}
@@ -29,10 +31,16 @@ public CSharpCodeBuilder Clear()
/// Unlike automatic indentation that occurs at the start of new lines, this method provides manual control
/// over indentation placement and does not modify the current indentation level.
///
- public CSharpCodeBuilder Intend()
+ public CSharpCodeBuilder Indent()
{
_ = _builder.Append(UseTabs ? '\t' : ' ', UseTabs ? 1 : 4);
return this;
}
+
+ ///
+#pragma warning disable S1133 // Deprecated code should be removed
+ [Obsolete("Use Indent() instead. This method will be removed in a future version.")]
+#pragma warning restore S1133 // Deprecated code should be removed
+ public CSharpCodeBuilder Intend() => Indent();
}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs
index c889591..2119756 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Documentation.cs
@@ -1,9 +1,9 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Appends a single-line XML documentation comment.
@@ -13,7 +13,7 @@ public partial record CSharpCodeBuilder
/// 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}");
+ string.IsNullOrEmpty(content) ? this : EnsureNewLineForXmlDoc().Append("/// ").AppendLine(content);
///
/// Appends an XML documentation summary element.
@@ -30,7 +30,8 @@ public CSharpCodeBuilder AppendXmlDocSummary(string? summary)
return EnsureNewLineForXmlDoc()
.AppendLine("/// ")
- .AppendLine($"/// {summary}")
+ .Append("/// ")
+ .AppendLine(summary)
.AppendLine("/// ");
}
@@ -39,7 +40,7 @@ public CSharpCodeBuilder AppendXmlDocSummary(string? summary)
///
/// 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.
+ /// If is , empty, or every element is or empty, the method returns without appending anything.
public CSharpCodeBuilder AppendXmlDocSummary(IEnumerable? summaryLines)
{
if (summaryLines is null)
@@ -47,16 +48,15 @@ public CSharpCodeBuilder AppendXmlDocSummary(IEnumerable? summaryLines)
return this;
}
- var hasContent = false;
- var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+ CSharpCodeBuilder? builder = null;
foreach (var line in summaryLines.Where(l => !string.IsNullOrEmpty(l)))
{
- builder = builder.AppendLine($"/// {line}");
- hasContent = true;
+ builder ??= EnsureNewLineForXmlDoc().AppendLine("/// ");
+ builder = builder.Append("/// ").AppendLine(line);
}
- return hasContent ? builder.AppendLine("/// ") : this;
+ return builder?.AppendLine("/// ") ?? this;
}
///
@@ -73,7 +73,12 @@ public CSharpCodeBuilder AppendXmlDocParam(string? paramName, string? descriptio
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ return EnsureNewLineForXmlDoc()
+ .Append("/// ")
+ .Append(description)
+ .AppendLine("");
}
///
@@ -111,7 +116,7 @@ public CSharpCodeBuilder AppendXmlDocReturns(string? description)
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ return EnsureNewLineForXmlDoc().Append("/// ").Append(description).AppendLine("");
}
///
@@ -139,7 +144,7 @@ public CSharpCodeBuilder AppendXmlDocRemarks(string? remarks)
///
/// 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.
+ /// If is , empty, or every element is or empty, the method returns without appending anything.
public CSharpCodeBuilder AppendXmlDocRemarks(IEnumerable? remarksLines)
{
if (remarksLines is null)
@@ -147,16 +152,15 @@ public CSharpCodeBuilder AppendXmlDocRemarks(IEnumerable? remarksLines)
return this;
}
- var hasContent = false;
- var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+ CSharpCodeBuilder? builder = null;
foreach (var line in remarksLines.Where(l => !string.IsNullOrEmpty(l)))
{
- builder = builder.AppendLine($"/// {line}");
- hasContent = true;
+ builder ??= EnsureNewLineForXmlDoc().AppendLine("/// ");
+ builder = builder.Append("/// ").AppendLine(line);
}
- return hasContent ? builder.AppendLine("/// ") : this;
+ return builder?.AppendLine("/// ") ?? this;
}
///
@@ -174,7 +178,11 @@ public CSharpCodeBuilder AppendXmlDocException(string? exceptionType, string? de
}
return EnsureNewLineForXmlDoc()
- .AppendLine($"/// {description}");
+ .Append("/// ")
+ .Append(description)
+ .AppendLine("");
}
///
@@ -225,7 +233,8 @@ public CSharpCodeBuilder AppendXmlDocExample(string? example)
return EnsureNewLineForXmlDoc()
.AppendLine("/// ")
- .AppendLine($"/// {example}")
+ .Append("/// ")
+ .AppendLine(example)
.AppendLine("/// ");
}
@@ -234,7 +243,7 @@ public CSharpCodeBuilder AppendXmlDocExample(string? example)
///
/// 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.
+ /// If is , empty, or every element is or empty, the method returns without appending anything.
public CSharpCodeBuilder AppendXmlDocExample(IEnumerable? exampleLines)
{
if (exampleLines is null)
@@ -242,23 +251,22 @@ public CSharpCodeBuilder AppendXmlDocExample(IEnumerable? exampleLines)
return this;
}
- var hasContent = false;
- var builder = EnsureNewLineForXmlDoc().AppendLine("/// ");
+ CSharpCodeBuilder? builder = null;
foreach (var line in exampleLines.Where(l => !string.IsNullOrEmpty(l)))
{
- builder = builder.AppendLine($"/// {line}");
- hasContent = true;
+ builder ??= EnsureNewLineForXmlDoc().AppendLine("/// ");
+ builder = builder.Append("/// ").AppendLine(line);
}
- return hasContent ? builder.AppendLine("/// ") : this;
+ return builder?.AppendLine("/// ") ?? this;
}
///
/// Appends an XML documentation see element for cross-references.
///
/// The cross-reference to another member or type.
- /// If set to true, uses 'href' instead of 'cref' for external links.
+ /// If set to , uses 'href' instead of 'cref' for external links.
/// 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, bool isHref = false)
@@ -268,14 +276,19 @@ public CSharpCodeBuilder AppendXmlDocSee(string? cref, bool isHref = false)
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// ");
+ return EnsureNewLineForXmlDoc()
+ .Append("/// ");
}
///
/// Appends an XML documentation seealso element for see-also references.
///
/// The cross-reference to another member or type.
- /// If set to true, uses 'href' instead of 'cref' for external links.
+ /// If set to , uses 'href' instead of 'cref' for external links.
/// 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, bool isHref = false)
@@ -285,7 +298,12 @@ public CSharpCodeBuilder AppendXmlDocSeeAlso(string? cref, bool isHref = false)
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// ");
+ return EnsureNewLineForXmlDoc()
+ .Append("/// ");
}
///
@@ -301,7 +319,7 @@ public CSharpCodeBuilder AppendXmlDocValue(string? description)
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ return EnsureNewLineForXmlDoc().Append("/// ").Append(description).AppendLine("");
}
///
@@ -318,7 +336,12 @@ public CSharpCodeBuilder AppendXmlDocTypeParam(string? paramName, string? descri
return this;
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// {description}");
+ return EnsureNewLineForXmlDoc()
+ .Append("/// ")
+ .Append(description)
+ .AppendLine("");
}
///
@@ -352,7 +375,7 @@ public CSharpCodeBuilder AppendXmlDocTypeParams(IEnumerable<(string, string)>? t
public CSharpCodeBuilder AppendXmlDocInheritDoc(string? cref = null) =>
string.IsNullOrEmpty(cref)
? EnsureNewLineForXmlDoc().AppendLine("/// ")
- : EnsureNewLineForXmlDoc().AppendLine($"/// ");
+ : EnsureNewLineForXmlDoc().Append("/// ");
///
/// Appends a custom XML documentation element.
@@ -373,14 +396,19 @@ public CSharpCodeBuilder AppendXmlDocCustomElement(
return this;
}
- var attributesPart = string.IsNullOrEmpty(attributes) ? string.Empty : $" {attributes}";
+ var docBuilder = EnsureNewLineForXmlDoc().Append("/// <").Append(elementName);
+
+ if (!string.IsNullOrEmpty(attributes))
+ {
+ _ = docBuilder.Append(' ').Append(attributes);
+ }
if (string.IsNullOrEmpty(content))
{
- return EnsureNewLineForXmlDoc().AppendLine($"/// <{elementName}{attributesPart} />");
+ return docBuilder.AppendLine(" />");
}
- return EnsureNewLineForXmlDoc().AppendLine($"/// <{elementName}{attributesPart}>{content}{elementName}>");
+ return docBuilder.Append(">").Append(content).Append("").Append(elementName).AppendLine(">");
}
///
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs
index 39c4423..4536198 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.EnsureCapacity.cs
@@ -1,6 +1,6 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Ensures that the capacity of the internal is at least the specified value.
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Scope.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Scope.cs
index 7a74544..ae8a233 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Scope.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.Scope.cs
@@ -2,7 +2,7 @@ namespace NetEvolve.CodeBuilder;
using System;
-public partial record CSharpCodeBuilder
+public partial class CSharpCodeBuilder
{
///
/// Creates a scope that automatically manages indentation levels.
@@ -82,14 +82,14 @@ internal ScopeHandler(CSharpCodeBuilder builder)
/// Determines whether the specified object is equal to the current instance.
///
/// The object to compare with the current instance.
- /// Always returns false since ScopeHandler instances should not be compared.
+ /// Always returns since ScopeHandler instances should not be compared.
public override readonly bool Equals(object? obj) => false;
///
/// Determines whether the specified ScopeHandler is equal to the current instance.
///
/// The ScopeHandler to compare with the current instance.
- /// Always returns false since ScopeHandler instances should not be compared.
+ /// Always returns since ScopeHandler instances should not be compared.
public readonly bool Equals(ScopeHandler other) => false;
///
@@ -103,7 +103,7 @@ internal ScopeHandler(CSharpCodeBuilder builder)
///
/// The first instance to compare.
/// The second instance to compare.
- /// Always returns false since ScopeHandler instances should not be compared.
+ /// Always returns since ScopeHandler instances should not be compared.
public static bool operator ==(ScopeHandler _, ScopeHandler __) => false;
///
@@ -111,7 +111,7 @@ internal ScopeHandler(CSharpCodeBuilder builder)
///
/// The first instance to compare.
/// The second instance to compare.
- /// Always returns true since ScopeHandler instances should not be compared.
+ /// Always returns since ScopeHandler instances should not be compared.
public static bool operator !=(ScopeHandler _, ScopeHandler __) => true;
}
}
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs
index 7682b2f..da64ca1 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder._EMPTY_.cs
@@ -1,3 +1,3 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
-public partial record CSharpCodeBuilder { }
+public partial class CSharpCodeBuilder { }
diff --git a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs
index bd4d747..af58825 100644
--- a/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs
+++ b/src/NetEvolve.CodeBuilder/CSharpCodeBuilder.cs
@@ -1,11 +1,11 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System.Text;
///
/// Provides functionality for building C# code strings with proper indentation.
///
-public partial record CSharpCodeBuilder : CodeBuilderBase
+public partial class CSharpCodeBuilder : CodeBuilderBase
{
///
/// Initializes a new instance of the class.
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs
index 9607d11..9374547 100644
--- a/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.EnsureIndented.cs
@@ -1,8 +1,8 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System.Runtime.CompilerServices;
-public partial record CodeBuilderBase
+public partial class CodeBuilderBase
{
///
/// Ensures that indentation is applied if we are at the start of a new line.
@@ -36,24 +36,24 @@ private protected void EnsureIndented(bool deactivate = false)
///
///
/// This method increases the current indentation level, which affects subsequent lines
- /// that are appended to the builder. The operation is thread-safe.
+ /// that are appended to the builder.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void IncrementIndent() => Interlocked.Increment(ref _indentLevel);
+ internal void IncrementIndent() => _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.
+ /// that are appended to the builder. The indentation level will not go below zero.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void DecrementIndent()
{
- if (Interlocked.Decrement(ref _indentLevel) < 0)
+ if (--_indentLevel < 0)
{
- _ = Interlocked.Exchange(ref _indentLevel, 0);
+ _indentLevel = 0;
}
}
}
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs
index 60cffdb..365d9a2 100644
--- a/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.ToString.cs
@@ -1,6 +1,6 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
-public partial record CodeBuilderBase
+public partial class CodeBuilderBase
{
///
/// Returns the string that has been built by this .
diff --git a/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs b/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs
index 6397834..054809b 100644
--- a/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs
+++ b/src/NetEvolve.CodeBuilder/CodeBuilderBase.cs
@@ -1,11 +1,15 @@
-namespace NetEvolve.CodeBuilder;
+namespace NetEvolve.CodeBuilder;
using System.Text;
///
/// Provides the base functionality for building code strings with proper indentation and formatting.
///
-public abstract partial record CodeBuilderBase
+///
+/// This class and its derived types are not thread-safe. All operations on a single instance
+/// must be performed from a single thread.
+///
+public abstract partial class CodeBuilderBase
{
private protected readonly StringBuilder _builder;
private protected int _indentLevel;
@@ -37,6 +41,6 @@ public abstract partial record CodeBuilderBase
///
/// 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.
+ /// to use tabs for indentation; to use spaces.
public bool UseTabs { get; set; }
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingSpaces_Should_ProduceCorrectIndentation.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingSpaces_Should_ProduceCorrectIndentation.verified.txt
index 4a16bd3..adb3ad3 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingSpaces_Should_ProduceCorrectIndentation.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingSpaces_Should_ProduceCorrectIndentation.verified.txt
@@ -8,12 +8,14 @@
Console.WriteLine("Nested");
}
}
+
public void Method2()
{
try{
DoSomething();
- }catch (Exception ex){
+ }
+ catch (Exception ex){
Console.WriteLine($"Error: {ex.Message}");
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingTabs_Should_ProduceCorrectIndentation.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingTabs_Should_ProduceCorrectIndentation.verified.txt
index 94d0ddc..d315382 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingTabs_Should_ProduceCorrectIndentation.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateClassWithFormatting_UsingTabs_Should_ProduceCorrectIndentation.verified.txt
@@ -8,12 +8,14 @@
Console.WriteLine("Nested");
}
}
+
public void Method2()
{
try{
DoSomething();
- }catch (Exception ex){
+ }
+ catch (Exception ex){
Console.WriteLine($"Error: {ex.Message}");
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_MatchSnapshot.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_MatchSnapshot.verified.txt
index d164a1e..e890098 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_MatchSnapshot.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_MatchSnapshot.verified.txt
@@ -8,4 +8,4 @@ namespace MyApplication.Models
public string Id { get; set; }
public string Name { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_ProduceCorrectOutput.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_ProduceCorrectOutput.verified.txt
index 4a96ddd..13e65e4 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_ProduceCorrectOutput.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateCompleteClass_Should_ProduceCorrectOutput.verified.txt
@@ -17,8 +17,8 @@ namespace MyApplication.Models
public Customer(string id)
{
_id = id ?? throw new ArgumentNullException(nameof(id));
-
}
+
///
/// Gets the customer identifier.
///
@@ -34,4 +34,4 @@ namespace MyApplication.Models
///
public string? Email { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateEnum_WithDocumentation_Should_ProduceCorrectOutput.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateEnum_WithDocumentation_Should_ProduceCorrectOutput.verified.txt
index 3a00a9e..3d2a5d7 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateEnum_WithDocumentation_Should_ProduceCorrectOutput.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateEnum_WithDocumentation_Should_ProduceCorrectOutput.verified.txt
@@ -28,4 +28,4 @@ namespace MyApplication.Enums
///
Delivered = 8
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateInterface_WithMultipleMethods_Should_ProduceCorrectOutput.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateInterface_WithMultipleMethods_Should_ProduceCorrectOutput.verified.txt
index b927e3c..32821b7 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateInterface_WithMultipleMethods_Should_ProduceCorrectOutput.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateInterface_WithMultipleMethods_Should_ProduceCorrectOutput.verified.txt
@@ -29,4 +29,4 @@ namespace MyApplication.Services
/// A task representing the asynchronous operation.
Task UpdateCustomerAsync(Customer customer);
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateMethodWithConditionalContent_Should_ProduceCorrectOutput.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateMethodWithConditionalContent_Should_ProduceCorrectOutput.verified.txt
index 9e7e44b..3d28618 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateMethodWithConditionalContent_Should_ProduceCorrectOutput.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateMethodWithConditionalContent_Should_ProduceCorrectOutput.verified.txt
@@ -6,6 +6,5 @@
Console.WriteLine($"Processing complete: {result}");
await Task.CompletedTask;
return result;
-
}
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateReflectionBasedCode_Should_ProduceCorrectOutput.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateReflectionBasedCode_Should_ProduceCorrectOutput.verified.txt
index f4150dc..32ae849 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateReflectionBasedCode_Should_ProduceCorrectOutput.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateReflectionBasedCode_Should_ProduceCorrectOutput.verified.txt
@@ -9,8 +9,8 @@ public class GeneratedEntity
{
_ID = ID;
_CREATEDAT = CREATEDAT;
-
}
+
public int Id => _ID;
public string? Name { get; set; }
@@ -19,5 +19,4 @@ public class GeneratedEntity
public DateTime CreatedAt => _CREATEDAT;
-
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_02b3255120757173.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_02b3255120757173.verified.txt
index 271daf7..83599ec 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_02b3255120757173.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_02b3255120757173.verified.txt
@@ -1,4 +1,4 @@
public class TestClass
{
public void Method() { }
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_b6b4547aad375c78.verified.txt b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_b6b4547aad375c78.verified.txt
index 76924e7..328b349 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_b6b4547aad375c78.verified.txt
+++ b/tests/NetEvolve.CodeBuilder.Tests.Integration/_snapshots/CSharpCodeBuilderTests.GenerateWithDifferentFormats_Should_MatchSnapshots_b6b4547aad375c78.verified.txt
@@ -1,4 +1,4 @@
public class TestClass
{
public void Method() { }
-}
\ No newline at end of file
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs
index 282770b..aeaec1c 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Append.cs
@@ -330,14 +330,16 @@ public async Task Append_String_ClosingBrace_Should_Decrement_Indent_And_Append_
_ = await Assert
.That(builder.ToString())
- .IsEqualTo("{" + Environment.NewLine + " test" + Environment.NewLine + "}");
+ .IsEqualTo("{" + Environment.NewLine + " test" + Environment.NewLine + "}" + Environment.NewLine);
// Verify indent is decremented for next content
_ = builder.Append("after");
_ = await Assert
.That(builder.ToString())
- .IsEqualTo("{" + Environment.NewLine + " test" + Environment.NewLine + "}" + "after");
+ .IsEqualTo(
+ "{" + Environment.NewLine + " test" + Environment.NewLine + "}" + Environment.NewLine + "after"
+ );
}
[Test]
@@ -353,14 +355,16 @@ public async Task Append_String_ClosingBracket_Should_Decrement_Indent_And_Appen
_ = await Assert
.That(builder.ToString())
- .IsEqualTo("[" + Environment.NewLine + " test" + Environment.NewLine + "]");
+ .IsEqualTo("[" + Environment.NewLine + " test" + Environment.NewLine + "]" + Environment.NewLine);
// Verify indent is decremented for next content
_ = builder.Append("after");
_ = await Assert
.That(builder.ToString())
- .IsEqualTo("[" + Environment.NewLine + " test" + Environment.NewLine + "]" + "after");
+ .IsEqualTo(
+ "[" + Environment.NewLine + " test" + Environment.NewLine + "]" + Environment.NewLine + "after"
+ );
}
// New tests for missing branches in Char Append method
@@ -424,4 +428,66 @@ public async Task Append_Char_OpeningBracket_Should_Increment_Indent_And_Append_
_ = await Assert.That(builder.ToString()).IsEqualTo("[" + Environment.NewLine + " test");
}
+
+ [Test]
+ public async Task Append_ReadOnlySpan_NonEmpty_Should_AppendContent()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.Append("hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("hello");
+ }
+
+ [Test]
+ public async Task Append_ReadOnlySpan_Empty_Should_NotAppend()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.Append(ReadOnlySpan.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task Append_ReadOnlySpan_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.Append("hello".AsSpan());
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task Append_ReadOnlySpan_With_StartIndex_And_Count_Should_AppendSubspan()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.Append("hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("ell");
+ }
+
+ [Test]
+ public async Task Append_ReadOnlySpan_Empty_With_Indices_Should_NotAppend()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.Append(ReadOnlySpan.Empty, 0, 0);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task Append_ReadOnlySpan_With_Indentation_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ _ = builder.AppendLine();
+
+ _ = builder.Append("hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine + " hello");
+ }
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs
index a8eba50..62c7e90 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendFormat.cs
@@ -1,6 +1,7 @@
namespace NetEvolve.CodeBuilder.Tests.Unit;
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
public partial class CSharpCodeBuilderTests
@@ -413,4 +414,250 @@ public async Task AppendFormat_WithComplexFormatting_Should_Format_Correctly()
_ = await Assert.That(builder.ToString()).IsEqualTo("Date: 2023-01-15, Value: 000000FF");
}
+
+ // AppendFormat(string format, object? arg0) — shortcut overload (uses InvariantCulture implicitly)
+ // CA1305 is intentionally suppressed for this block: the purpose of these tests is to verify the
+ // no-provider overloads resolve correctly and delegate to InvariantCulture.
+#pragma warning disable CA1305
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Value: {0}", 42);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 42");
+ }
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Value: {0:N2}", 1234.56m);
+
+ // InvariantCulture uses period as decimal separator
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 1,234.56");
+ }
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat("Value: {0}", 42);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendFormat("Value: {0}", 42);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine + " Value: 42");
+ }
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(null!, 42);
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat("Value: {1}", 42);
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ public async Task AppendFormat_SingleArg_NoProvider_Null_Arg_Should_Format_As_Empty()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Value: [{0}]", (object?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: []");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Values: {0}, {1}", 42, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 42, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Values: {0:N2}, {1}", 1234.56m, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 1,234.56, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat("Values: {0}, {1}", 42, "test");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendFormat("Values: {0}, {1}", 42, "test");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine + " Values: 42, test");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Null_Format_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat(null!, 42, "test");
+ });
+
+ _ = await Assert.That(exception.ParamName).IsEqualTo("format");
+ }
+
+ [Test]
+ [SuppressMessage(
+ "Globalization",
+ "CA1305:Specify IFormatProvider",
+ Justification = "Intentionally testing the no-provider overload."
+ )]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Invalid_Format_Should_Throw_FormatException() =>
+ await Assert.ThrowsAsync(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendFormat("Values: {0}, {2}", 42, "test");
+ return Task.CompletedTask;
+ });
+
+ [Test]
+ [SuppressMessage(
+ "Globalization",
+ "CA1305:Specify IFormatProvider",
+ Justification = "Intentionally testing the no-provider overload."
+ )]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Three_Args_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendFormat("Values: {0}, {1}, {2}", 42, "test", true);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Values: 42, test, True");
+ }
+
+ [Test]
+ public async Task AppendFormat_ParamsArgs_NoProvider_With_Format_Specifier_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var date = new DateTime(2023, 6, 15, 0, 0, 0, DateTimeKind.Utc);
+
+ _ = builder.AppendFormat("{0:yyyy-MM-dd}: value={1:X2}", date, 255);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("2023-06-15: value=FF");
+ }
+
+ [Test]
+ [SuppressMessage(
+ "Globalization",
+ "CA1305:Specify IFormatProvider",
+ Justification = "Intentionally testing the no-provider overload."
+ )]
+ public async Task AppendFormat_ParamsArgs_NoProvider_Single_Element_Array_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ object?[] args = [42];
+
+ _ = builder.AppendFormat("Value: {0}", args);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 42");
+ }
+
+#pragma warning restore CA1305
+
+ [Test]
+ public async Task AppendFormat_FormattableString_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var typeName = "string";
+ var memberName = "Name";
+
+ _ = builder.AppendFormat((FormattableString)$"public {typeName} {memberName}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("public string Name");
+ }
+
+ [Test]
+ public async Task AppendFormat_FormattableString_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ var value = 42;
+
+ _ = builder.AppendLine().AppendFormat((FormattableString)$"Value: {value}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine + " Value: 42");
+ }
+
+ [Test]
+ public async Task AppendFormat_FormattableString_Null_Should_Return_Same_Instance_Without_Appending()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendFormat((FormattableString?)null);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendFormat_FormattableString_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var value = 1234.56m;
+
+ _ = builder.AppendFormat((FormattableString)$"{value:N2}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("1,234.56");
+ }
+
+ [Test]
+ public async Task AppendFormat_FormattableString_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var text = "Hello";
+
+ var result = builder.AppendFormat((FormattableString)$"{text}");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs
index f2675d7..cacf52c 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendIf.cs
@@ -329,6 +329,66 @@ public async Task AppendIf_ReadOnlyMemory_With_StartIndex_And_Count_Should_Retur
_ = await Assert.That(result).IsEqualTo(builder);
}
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_Condition_True_Should_Append_Characters()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, "hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("hello");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, "hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_Empty_Condition_True_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, ReadOnlySpan.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendIf(true, "hello".AsSpan());
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_With_StartIndex_And_Count_Condition_True_Should_Append_Subspan()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(true, "hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("ell");
+ }
+
+ [Test]
+ public async Task AppendIf_ReadOnlySpan_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendIf(false, "hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
[Test]
public async Task AppendIf_String_Condition_True_Should_Append_Characters()
{
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendInterpolated.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendInterpolated.cs
new file mode 100644
index 0000000..ad17f71
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendInterpolated.cs
@@ -0,0 +1,132 @@
+#if NET6_0_OR_GREATER
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendInterpolated_LiteralOnly_Should_Append_Correctly()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendInterpolated($"Hello World");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Hello World");
+ }
+
+ [Test]
+ public async Task AppendInterpolated_WithFormattedValue_Should_Append_Correctly()
+ {
+ var builder = new CSharpCodeBuilder();
+ var typeName = "string";
+ var memberName = "Name";
+
+ _ = builder.AppendInterpolated($"public {typeName} {memberName}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("public string Name");
+ }
+
+ [Test]
+ public async Task AppendInterpolated_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ var value = 42;
+
+ _ = builder.AppendLine().AppendInterpolated($"Value: {value}");
+
+ var expected = Environment.NewLine + " Value: 42";
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendInterpolated_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendInterpolated($"Hello");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendInterpolated_Empty_Should_Not_Append_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendInterpolated($"");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineInterpolated_Should_Append_Line_Terminator()
+ {
+ var builder = new CSharpCodeBuilder();
+ var typeName = "MyClass";
+
+ _ = builder.AppendLineInterpolated($"public class {typeName}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("public class MyClass" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineInterpolated_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+ var value = 1;
+
+ _ = builder.AppendLine().AppendLineInterpolated($"Value: {value}");
+
+ var expected = Environment.NewLine + " Value: 1" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineInterpolated_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLineInterpolated($"Hello");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendInterpolated_FormattedValue_With_Format_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder();
+ var value = 1234.56m;
+
+ _ = builder.AppendInterpolated($"{value:N2}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("1,234.56");
+ }
+
+ [Test]
+ public async Task AppendInterpolated_FormattedValue_With_Alignment_Should_PadLeft()
+ {
+ var builder = new CSharpCodeBuilder();
+ var value = 42;
+
+ _ = builder.AppendInterpolated($"{value, 6}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(" 42");
+ }
+
+ [Test]
+ public async Task AppendLineInterpolated_Consecutive_Should_Indent_Each_Line()
+ {
+ var builder = new CSharpCodeBuilder();
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendLineInterpolated($"Line 1").AppendLineInterpolated($"Line 2");
+
+ var expected = Environment.NewLine + " Line 1" + Environment.NewLine + " Line 2" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+}
+#endif
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs
index b9d79fd..bbbcb08 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLine.cs
@@ -256,4 +256,54 @@ public async Task AppendLine_Unsafe_CharPointer_Negative_Length_Should_Append_On
_ = await Assert.That(result).IsEqualTo(builder);
_ = await Assert.That(builderResult).IsEqualTo(Environment.NewLine);
}
+
+ [Test]
+ public async Task AppendLine_ReadOnlySpan_NonEmpty_Should_AppendContentWithNewline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine("hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("hello" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlySpan_Empty_Should_AppendOnlyNewline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine(ReadOnlySpan.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlySpan_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendLine("hello".AsSpan());
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlySpan_With_StartIndex_And_Count_Should_AppendSubspanWithNewline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine("hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("ell" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLine_ReadOnlySpan_Empty_With_Indices_Should_AppendOnlyNewline()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendLine(ReadOnlySpan.Empty, 0, 0);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineFormat.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineFormat.cs
new file mode 100644
index 0000000..1bae044
--- /dev/null
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineFormat.cs
@@ -0,0 +1,155 @@
+namespace NetEvolve.CodeBuilder.Tests.Unit;
+
+using System;
+using System.Globalization;
+
+public partial class CSharpCodeBuilderTests
+{
+ [Test]
+ public async Task AppendLineFormat_OneArgument_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineFormat(CultureInfo.InvariantCulture, "Value: {0}", 42);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 42" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_OneArgument_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineFormat("Value: {0}", (object?)42);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("Value: 42" + Environment.NewLine);
+ }
+
+ // CA1305 is intentionally suppressed: the purpose of this test is to verify that the
+ // no-provider overload resolves correctly and delegates to InvariantCulture.
+#pragma warning disable CA1305
+ [Test]
+ public async Task AppendLineFormat_MultipleArguments_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineFormat("public {0} {1}", "string", "Name");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("public string Name" + Environment.NewLine);
+ }
+#pragma warning restore CA1305
+
+ [Test]
+ public async Task AppendLineFormat_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ _ = builder.AppendLine().AppendLineFormat("Value: {0}", (object?)42);
+
+ var expected = Environment.NewLine + " Value: 42" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineFormat("Value: {0}", (object?)42);
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_WithProvider_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineFormat(CultureInfo.InvariantCulture, "{0:N2}", 1234.56m);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("1,234.56" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_NullFormat_Should_Throw_ArgumentNullException()
+ {
+ var exception = Assert.Throws(() =>
+ {
+ var builder = new CSharpCodeBuilder(10);
+ _ = builder.AppendLineFormat(CultureInfo.InvariantCulture, null!, 42);
+ });
+
+ _ = await Assert.That(exception).IsNotNull();
+ }
+
+ [Test]
+ public async Task AppendLineFormat_Should_Set_IsNewline_True_After_Call()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+
+ _ = builder.AppendLineFormat("Value: {0}", (object?)1).AppendLineFormat("Value: {0}", (object?)2);
+
+ // Both lines are indented: _isNewline=true at builder start, so both calls get indentation applied.
+ var expected = " Value: 1" + Environment.NewLine + " Value: 2" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_FormattableString_Should_Format_Correctly()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var typeName = "string";
+ var memberName = "Name";
+
+ _ = builder.AppendLineFormat((FormattableString)$"public {typeName} {memberName}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("public string Name" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_FormattableString_Should_Apply_Indentation()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ builder.IncrementIndent();
+ var value = 42;
+
+ _ = builder.AppendLine().AppendLineFormat((FormattableString)$"Value: {value}");
+
+ var expected = Environment.NewLine + " Value: 42" + Environment.NewLine;
+ _ = await Assert.That(builder.ToString()).IsEqualTo(expected);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_FormattableString_Null_Should_Append_Only_LineTerminator()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineFormat((FormattableString?)null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_FormattableString_Should_Use_InvariantCulture()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var value = 1234.56m;
+
+ _ = builder.AppendLineFormat((FormattableString)$"{value:N2}");
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("1,234.56" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineFormat_FormattableString_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+ var text = "Hello";
+
+ var result = builder.AppendLineFormat((FormattableString)$"{text}");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs
index 605a41e..8ede0b6 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.AppendLineIf.cs
@@ -491,4 +491,64 @@ public async Task AppendLineIf_Mixed_With_AppendIf_Should_Work_Correctly()
_ = await Assert.That(builder.ToString()).IsEqualTo(expected);
}
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_Condition_True_Should_Append_With_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, "hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("hello" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, "hello".AsSpan());
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_Empty_Condition_True_Should_Append_Only_Newline()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, ReadOnlySpan.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_Should_Return_Same_Instance()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ var result = builder.AppendLineIf(true, "hello".AsSpan());
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_With_StartIndex_And_Count_Condition_True_Should_Append_Subspan()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(true, "hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo("ell" + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendLineIf_ReadOnlySpan_With_StartIndex_And_Count_Condition_False_Should_Not_Append()
+ {
+ var builder = new CSharpCodeBuilder(10);
+
+ _ = builder.AppendLineIf(false, "hello".AsSpan(), 1, 3);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs
index c30b81a..4f3db56 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Clear.cs
@@ -1,4 +1,4 @@
-namespace NetEvolve.CodeBuilder.Tests.Unit;
+namespace NetEvolve.CodeBuilder.Tests.Unit;
using System;
@@ -95,22 +95,22 @@ public async Task Clear_Should_Preserve_Capacity()
}
[Test]
- public async Task Intend_Should_Append_Single_Indentation()
+ public async Task Indent_Should_Append_Single_Indentation()
{
var builder = new CSharpCodeBuilder();
- _ = builder.Intend().Append("Hello");
+ _ = builder.Indent().Append("Hello");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo(" Hello");
}
[Test]
- public async Task Intend_Should_Not_Affect_Indentation_Level()
+ public async Task Indent_Should_Not_Affect_Indentation_Level()
{
var builder = new CSharpCodeBuilder();
- _ = builder.Intend().AppendLine("First");
+ _ = builder.Indent().AppendLine("First");
_ = builder.Append("Second");
var result = builder.ToString();
@@ -119,89 +119,89 @@ public async Task Intend_Should_Not_Affect_Indentation_Level()
}
[Test]
- public async Task Intend_With_Tabs_Should_Append_Tab_Character()
+ public async Task Indent_With_Tabs_Should_Append_Tab_Character()
{
var builder = new CSharpCodeBuilder { UseTabs = true };
- _ = builder.Intend().Append("Hello");
+ _ = builder.Indent().Append("Hello");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo("\tHello");
}
[Test]
- public async Task Intend_With_Spaces_Should_Append_Four_Spaces()
+ public async Task Indent_With_Spaces_Should_Append_Four_Spaces()
{
var builder = new CSharpCodeBuilder { UseTabs = false };
- _ = builder.Intend().Append("Hello");
+ _ = builder.Indent().Append("Hello");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo(" Hello");
}
[Test]
- public async Task Intend_Multiple_Calls_Should_Append_Multiple_Indentations()
+ public async Task Indent_Multiple_Calls_Should_Append_Multiple_Indentations()
{
var builder = new CSharpCodeBuilder();
- _ = builder.Intend().Intend().Intend().Append("Hello");
+ _ = builder.Indent().Indent().Indent().Append("Hello");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo(" Hello"); // 12 spaces (3 * 4)
}
[Test]
- public async Task Intend_Multiple_With_Tabs_Should_Append_Multiple_Tabs()
+ public async Task Indent_Multiple_With_Tabs_Should_Append_Multiple_Tabs()
{
var builder = new CSharpCodeBuilder { UseTabs = true };
- _ = builder.Intend().Intend().Intend().Append("Hello");
+ _ = builder.Indent().Indent().Indent().Append("Hello");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo("\t\t\tHello");
}
[Test]
- public async Task Intend_Should_Return_Builder_For_Chaining()
+ public async Task Indent_Should_Return_Builder_For_Chaining()
{
var builder = new CSharpCodeBuilder();
- var result = builder.Intend();
+ var result = builder.Indent();
_ = await Assert.That(result).IsEqualTo(builder);
}
[Test]
- public async Task Intend_In_Middle_Of_Line_Should_Append_Indentation()
+ public async Task Indent_In_Middle_Of_Line_Should_Append_Indentation()
{
var builder = new CSharpCodeBuilder();
- _ = builder.Append("Hello").Intend().Append("World");
+ _ = builder.Append("Hello").Indent().Append("World");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo("Hello World");
}
[Test]
- public async Task Intend_After_NewLine_Should_Add_Manual_Indentation()
+ public async Task Indent_After_NewLine_Should_Add_Manual_Indentation()
{
var builder = new CSharpCodeBuilder();
_ = builder.AppendLine("First");
- _ = builder.Intend().Append("Second");
+ _ = builder.Indent().Append("Second");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo("First" + Environment.NewLine + " Second");
}
[Test]
- public async Task Intend_With_Automatic_Indentation_Should_Stack()
+ public async Task Indent_With_Automatic_Indentation_Should_Stack()
{
var builder = new CSharpCodeBuilder();
builder.IncrementIndent(); // Set automatic indentation level to 1
- _ = builder.AppendLine().Intend().Append("Hello");
+ _ = builder.AppendLine().Indent().Append("Hello");
var result = builder.ToString();
// Should have both automatic (4 spaces) and manual (4 spaces) indentation
@@ -209,80 +209,105 @@ public async Task Intend_With_Automatic_Indentation_Should_Stack()
}
[Test]
- public async Task Intend_Multiple_Mixed_With_Content_Should_Work()
+ public async Task Indent_Multiple_Mixed_With_Content_Should_Work()
{
var builder = new CSharpCodeBuilder();
_ = builder
- .Intend()
+ .Indent()
.Append("Level 1")
.AppendLine()
- .Intend()
- .Intend()
+ .Indent()
+ .Indent()
.Append("Level 2")
.AppendLine()
- .Intend()
- .Intend()
- .Intend()
+ .Indent()
+ .Indent()
+ .Indent()
.Append("Level 3");
var result = builder.ToString();
- _ = await Assert.That(result).Contains(" Level 1");
- _ = await Assert.That(result).Contains(" Level 2");
- _ = await Assert.That(result).Contains(" Level 3");
+ _ = await Assert
+ .That(result)
+ .IsEqualTo(
+ " Level 1" + Environment.NewLine + " Level 2" + Environment.NewLine + " Level 3"
+ );
}
[Test]
- public async Task Intend_Should_Work_With_Empty_Builder()
+ public async Task Indent_Should_Work_With_Empty_Builder()
{
var builder = new CSharpCodeBuilder();
- _ = builder.Intend();
+ _ = builder.Indent();
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo(" ");
}
[Test]
- public async Task Intend_Should_Work_After_Clear()
+ public async Task Clear_Should_Reset_IsNewline_State()
+ {
+ var builder = new CSharpCodeBuilder();
+ _ = builder.Append("text"); // sets _isNewline to false
+
+ _ = builder.Clear(); // must reset _isNewline to true
+ builder.IncrementIndent();
+ _ = builder.Append("indented");
+
+ var result = builder.ToString();
+ _ = await Assert.That(result).IsEqualTo(" indented");
+ }
+
+ [Test]
+ public async Task Indent_Should_Work_After_Clear()
{
var builder = new CSharpCodeBuilder();
_ = builder.Append("Hello");
_ = builder.Clear();
- _ = builder.Intend().Append("World");
+ _ = builder.Indent().Append("World");
var result = builder.ToString();
_ = await Assert.That(result).IsEqualTo(" World");
}
[Test]
- public async Task Intend_Combined_With_Scope_Should_Add_Extra_Indentation()
+ public async Task Indent_Combined_With_Scope_Should_Add_Extra_Indentation()
{
var builder = new CSharpCodeBuilder();
using (builder.Scope())
{
- _ = builder.Intend().Append("Extra indented");
+ _ = builder.Indent().Append("Extra indented");
}
- var result = builder.ToString();
- // Should have both scope indentation (4 spaces) and manual indentation (4 spaces)
- _ = await Assert.That(result).Contains(" Extra indented"); // 8 spaces
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ Extra indented}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
- public async Task Intend_Combined_With_ScopeLine_Should_Add_Extra_Indentation()
+ public async Task Indent_Combined_With_ScopeLine_Should_Add_Extra_Indentation()
{
var builder = new CSharpCodeBuilder();
using (builder.ScopeLine("public class MyClass"))
{
- _ = builder.Intend().Append("// Extra indented comment");
+ _ = builder.Indent().Append("// Extra indented comment");
}
- var result = builder.ToString();
- // Should have both scope indentation and manual indentation
- _ = await Assert.That(result).Contains(" // Extra indented comment"); // 8 spaces
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ // Extra indented comment}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs
index d5e2b54..39f8891 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Documentation.cs
@@ -44,15 +44,17 @@ public async Task AppendXmlDocSummary_WithSingleLine_Should_AppendSummaryElement
{
var builder = new CSharpCodeBuilder();
- var result = builder.AppendXmlDocSummary("This is a summary").ToString();
+ var result = builder
+ .AppendXmlDocSummary("This is a summary")
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// This is a summary"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// This is a summary
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -63,19 +65,19 @@ public async Task AppendXmlDocSummary_WithMultipleLines_Should_AppendSummaryElem
var builder = new CSharpCodeBuilder();
var summaryLines = new[] { "First line", "Second line", "Third line" };
- var result = builder.AppendXmlDocSummary(summaryLines).ToString();
+ var result = builder
+ .AppendXmlDocSummary(summaryLines)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// First line"
- + Environment.NewLine
- + "/// Second line"
- + Environment.NewLine
- + "/// Third line"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// First line
+ /// Second line
+ /// Third line
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -86,21 +88,45 @@ public async Task AppendXmlDocSummary_WithEmptyAndNullLines_Should_SkipEmptyLine
var builder = new CSharpCodeBuilder();
var summaryLines = new List { "First line", "", null, "Last line" };
- var result = builder.AppendXmlDocSummary(summaryLines.Where(x => x is not null)!).ToString();
+ var result = builder
+ .AppendXmlDocSummary(summaryLines.Where(x => x is not null)!)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// First line"
- + Environment.NewLine
- + "/// Last line"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// First line
+ /// Last line
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ _ = await Assert.That(result).IsEqualTo(expected);
_ = await Assert.That(result).IsEqualTo(expected);
}
+ [Test]
+ public async Task AppendXmlDocSummary_WithOnlyEmptyLines_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+ var summaryLines = new[] { "", "", "" };
+
+ var result = builder.AppendXmlDocSummary(summaryLines).ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSummary_WithEmptyCollection_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocSummary(Array.Empty()).ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
[Test]
public async Task AppendXmlDocParam_WithValidParameters_Should_AppendParamElement()
{
@@ -135,13 +161,13 @@ public async Task AppendXmlDocParams_WithMultipleParameters_Should_AppendAllPara
("param2", "Second parameter"),
};
- var result = builder.AppendXmlDocParams(parameters).ToString();
+ var result = builder.AppendXmlDocParams(parameters).ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// First parameter"
- + Environment.NewLine
- + "/// Second parameter"
- + Environment.NewLine;
+ var expected = """
+ /// First parameter
+ /// Second parameter
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -164,15 +190,17 @@ public async Task AppendXmlDocRemarks_WithSingleLine_Should_AppendRemarksElement
{
var builder = new CSharpCodeBuilder();
- var result = builder.AppendXmlDocRemarks("This is a remark").ToString();
+ var result = builder
+ .AppendXmlDocRemarks("This is a remark")
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// This is a remark"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// This is a remark
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -183,19 +211,19 @@ public async Task AppendXmlDocRemarks_WithMultipleLines_Should_AppendRemarksElem
var builder = new CSharpCodeBuilder();
var remarksLines = new[] { "First remark line", "Second remark line", "Third remark line" };
- var result = builder.AppendXmlDocRemarks(remarksLines).ToString();
+ var result = builder
+ .AppendXmlDocRemarks(remarksLines)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// First remark line"
- + Environment.NewLine
- + "/// Second remark line"
- + Environment.NewLine
- + "/// Third remark line"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// First remark line
+ /// Second remark line
+ /// Third remark line
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -206,34 +234,31 @@ public async Task AppendXmlDocRemarks_WithEmptyAndNullLines_Should_SkipEmptyLine
var builder = new CSharpCodeBuilder();
var remarksLines = new[] { "First remark", "", "Third remark" };
- var result = builder.AppendXmlDocRemarks(remarksLines).ToString();
+ var result = builder
+ .AppendXmlDocRemarks(remarksLines)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// First remark"
- + Environment.NewLine
- + "/// Third remark"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// First remark
+ /// Third remark
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
- public async Task AppendXmlDocRemarks_WithOnlyEmptyLines_Should_AppendOnlyOpeningTag()
+ public async Task AppendXmlDocRemarks_WithOnlyEmptyLines_Should_NotAppendAnything()
{
var builder = new CSharpCodeBuilder();
var remarksLines = new[] { "", "", "" };
var result = builder.AppendXmlDocRemarks(remarksLines).ToString();
- // The current implementation has a bug where it opens the tag but doesn't close it
- // when there are no valid content lines
- var expected = "/// " + Environment.NewLine;
-
- _ = await Assert.That(result).IsEqualTo(expected);
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
}
[Test]
@@ -247,18 +272,14 @@ public async Task AppendXmlDocRemarks_WithNullCollection_Should_NotAppendAnythin
}
[Test]
- public async Task AppendXmlDocRemarks_WithEmptyCollection_Should_AppendOnlyOpeningTag()
+ public async Task AppendXmlDocRemarks_WithEmptyCollection_Should_NotAppendAnything()
{
var builder = new CSharpCodeBuilder();
var remarksLines = Array.Empty();
var result = builder.AppendXmlDocRemarks(remarksLines).ToString();
- // The current implementation has a bug where it opens the tag but doesn't close it
- // when there are no valid content lines
- var expected = "/// " + Environment.NewLine;
-
- _ = await Assert.That(result).IsEqualTo(expected);
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
}
[Test]
@@ -266,15 +287,17 @@ public async Task AppendXmlDocExample_WithContent_Should_AppendExampleElement()
{
var builder = new CSharpCodeBuilder();
- var result = builder.AppendXmlDocExample("var example = new Example();").ToString();
+ var result = builder
+ .AppendXmlDocExample("var example = new Example();")
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ var expected = """
+ ///
+ /// var example = new Example();
+ ///
- var expected =
- "/// "
- + Environment.NewLine
- + "/// var example = new Example();"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -290,19 +313,19 @@ public async Task AppendXmlDocExample_WithMultipleLines_Should_AppendExampleElem
"var result = builder.ToString();",
};
- var result = builder.AppendXmlDocExample(exampleLines).ToString();
+ var result = builder
+ .AppendXmlDocExample(exampleLines)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// var builder = new CSharpCodeBuilder();"
- + Environment.NewLine
- + "/// builder.AppendLine(\"Hello World\");"
- + Environment.NewLine
- + "/// var result = builder.ToString();"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// var builder = new CSharpCodeBuilder();
+ /// builder.AppendLine("Hello World");
+ /// var result = builder.ToString();
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -313,21 +336,43 @@ public async Task AppendXmlDocExample_WithEmptyAndNullLines_Should_SkipEmptyLine
var builder = new CSharpCodeBuilder();
var exampleLines = new[] { "var x = 1;", "", "var y = 2;" };
- var result = builder.AppendXmlDocExample(exampleLines).ToString();
+ var result = builder
+ .AppendXmlDocExample(exampleLines)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// var x = 1;"
- + Environment.NewLine
- + "/// var y = 2;"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// var x = 1;
+ /// var y = 2;
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
+ [Test]
+ public async Task AppendXmlDocExample_WithOnlyEmptyLines_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+ var exampleLines = new[] { "", "", "" };
+
+ var result = builder.AppendXmlDocExample(exampleLines).ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocExample_WithEmptyCollection_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder.AppendXmlDocExample(Array.Empty()).ToString();
+
+ _ = await Assert.That(result).IsEqualTo(string.Empty);
+ }
+
[Test]
public async Task AppendXmlDocSee_WithCref_Should_AppendSeeElement()
{
@@ -339,6 +384,107 @@ public async Task AppendXmlDocSee_WithCref_Should_AppendSeeElement()
_ = await Assert.That(builder.ToString()).IsEqualTo("/// " + Environment.NewLine);
}
+ [Test]
+ public async Task AppendXmlDocSee_WithNullCref_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSee(null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSee_WithIsHrefTrue_Should_UseHrefAttribute()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSee("https://example.com", isHref: true);
+
+ _ = 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.String");
+
+ _ = await Assert.That(result).IsEqualTo(builder);
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_WithNullCref_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSeeAlso(null);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_WithEmptyCref_Should_NotAppendAnything()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSeeAlso(string.Empty);
+
+ _ = await Assert.That(builder.ToString()).IsEqualTo(string.Empty);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_WithIsHrefTrue_Should_UseHrefAttribute()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSeeAlso("https://example.com", isHref: true);
+
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_WithIsHrefFalse_Should_UseCrefAttribute()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ _ = builder.AppendXmlDocSeeAlso("MyNamespace.MyClass", isHref: false);
+
+ _ = await Assert
+ .That(builder.ToString())
+ .IsEqualTo("/// " + Environment.NewLine);
+ }
+
+ [Test]
+ public async Task AppendXmlDocSeeAlso_AfterContent_Should_StartOnNewLine()
+ {
+ var builder = new CSharpCodeBuilder();
+
+ var result = builder
+ .AppendXmlDocSummary("Method summary")
+ .AppendXmlDocSeeAlso("RelatedClass")
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ var expected = """
+ ///
+ /// Method summary
+ ///
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ _ = await Assert.That(result).IsEqualTo(expected);
+ }
+
[Test]
public async Task AppendXmlDocValue_WithDescription_Should_AppendValueElement()
{
@@ -418,27 +564,21 @@ public async Task XmlDocumentationMethods_Should_SupportMethodChaining()
.AppendXmlDocParam("param2", "Second parameter")
.AppendXmlDocReturns("Return value description")
.AppendXmlDocRemarks("Additional remarks")
- .ToString();
-
- 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;
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ var expected = """
+ ///
+ /// Method summary
+ ///
+ /// First parameter
+ /// Second parameter
+ /// Return value description
+ ///
+ /// Additional remarks
+ ///
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -452,17 +592,16 @@ public async Task XmlDocumentationMethods_WithIndentation_Should_RespectIndentat
var result = builder
.AppendXmlDocSummary("Indented summary")
.AppendXmlDocParam("param", "Parameter description")
- .ToString();
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- " /// "
- + Environment.NewLine
- + " /// Indented summary"
- + Environment.NewLine
- + " /// "
- + Environment.NewLine
- + " /// Parameter description"
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// Indented summary
+ ///
+ /// Parameter description
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -477,20 +616,17 @@ public async Task XmlDocumentationMethods_AfterContent_Should_StartOnNewLine()
.AppendXmlDocSummary("Method summary")
.AppendXmlDocParam("param", "Parameter description")
.Append("public void MyMethod(string param) { }")
- .ToString();
-
- var expected =
- "public class MyClass"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Method summary"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Parameter description"
- + Environment.NewLine
- + "public void MyMethod(string param) { }";
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
+
+ var expected = """
+ public class MyClass
+ ///
+ /// Method summary
+ ///
+ /// Parameter description
+ public void MyMethod(string param) { }
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -503,17 +639,16 @@ public async Task XmlDocumentationMethods_AtStartOfBuilder_Should_NotAddExtraNew
var result = builder
.AppendXmlDocSummary("Method summary")
.AppendXmlDocParam("param", "Parameter description")
- .ToString();
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// Method summary"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Parameter description"
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// Method summary
+ ///
+ /// Parameter description
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -527,19 +662,17 @@ public async Task XmlDocumentationMethods_AfterNewLine_Should_NotAddExtraNewLine
.AppendLine("public class MyClass")
.AppendXmlDocSummary("Method summary")
.AppendXmlDocParam("param", "Parameter description")
- .ToString();
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "public class MyClass"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Method summary"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Parameter description"
- + Environment.NewLine;
+ var expected = """
+ public class MyClass
+ ///
+ /// Method summary
+ ///
+ /// Parameter description
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -644,15 +777,17 @@ public async Task AppendXmlDocExceptions_WithValidExceptions_Should_AppendAllExc
("ArgumentOutOfRangeException", "Thrown when value is out of range"),
};
- var result = builder.AppendXmlDocExceptions(exceptions).ToString();
+ var result = builder
+ .AppendXmlDocExceptions(exceptions)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// Thrown when argument is null"
- + Environment.NewLine
- + "/// Thrown when operation is invalid"
- + Environment.NewLine
- + "/// Thrown when value is out of range"
- + Environment.NewLine;
+ var expected = """
+ /// Thrown when argument is null
+ /// Thrown when operation is invalid
+ /// Thrown when value is out of range
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -710,13 +845,16 @@ public async Task AppendXmlDocExceptions_WithInvalidExceptions_Should_SkipInvali
("ValidException", "Another valid exception"),
};
- var result = builder.AppendXmlDocExceptions(exceptions).ToString();
+ var result = builder
+ .AppendXmlDocExceptions(exceptions)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// Valid exception"
- + Environment.NewLine
- + "/// Another valid exception"
- + Environment.NewLine;
+ var expected = """
+ /// Valid exception
+ /// Another valid exception
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -735,21 +873,18 @@ public async Task AppendXmlDocExceptions_Should_SupportMethodChaining()
.AppendXmlDocSummary("Method summary")
.AppendXmlDocExceptions(exceptions)
.AppendXmlDocReturns("Return value")
- .ToString();
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// Method summary"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// Thrown when argument is null"
- + Environment.NewLine
- + "/// Thrown when operation is invalid"
- + Environment.NewLine
- + "/// Return value"
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// Method summary
+ ///
+ /// Thrown when argument is null
+ /// Thrown when operation is invalid
+ /// Return value
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -765,13 +900,16 @@ public async Task AppendXmlDocExceptions_WithIndentation_Should_RespectIndentati
("InvalidOperationException", "Thrown when operation is invalid"),
};
- var result = builder.AppendXmlDocExceptions(exceptions).ToString();
+ var result = builder
+ .AppendXmlDocExceptions(exceptions)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- " /// Thrown when argument is null"
- + Environment.NewLine
- + " /// Thrown when operation is invalid"
- + Environment.NewLine;
+ var expected = """
+ /// Thrown when argument is null
+ /// Thrown when operation is invalid
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -803,13 +941,16 @@ public async Task AppendXmlDocTypeParams_WithMultipleParameters_Should_AppendAll
("U", "Second type parameter"),
};
- var result = builder.AppendXmlDocTypeParams(typeParameters).ToString();
+ var result = builder
+ .AppendXmlDocTypeParams(typeParameters)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// First type parameter"
- + Environment.NewLine
- + "/// Second type parameter"
- + Environment.NewLine;
+ var expected = """
+ /// First type parameter
+ /// Second type parameter
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -862,13 +1003,16 @@ public async Task AppendXmlDocTypeParams_WithInvalidEntries_Should_SkipInvalidEn
("W", "Another valid type parameter"),
};
- var result = builder.AppendXmlDocTypeParams(typeParameters).ToString();
+ var result = builder
+ .AppendXmlDocTypeParams(typeParameters)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// Valid type parameter"
- + Environment.NewLine
- + "/// Another valid type parameter"
- + Environment.NewLine;
+ var expected = """
+ /// Valid type parameter
+ /// Another valid type parameter
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -904,21 +1048,18 @@ public async Task AppendXmlDocTypeParams_Should_SupportMethodChaining()
.AppendXmlDocSummary("Generic class")
.AppendXmlDocTypeParams(typeParameters)
.AppendXmlDocReturns("Return value")
- .ToString();
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- "/// "
- + Environment.NewLine
- + "/// Generic class"
- + Environment.NewLine
- + "/// "
- + Environment.NewLine
- + "/// First type parameter"
- + Environment.NewLine
- + "/// Second type parameter"
- + Environment.NewLine
- + "/// Return value"
- + Environment.NewLine;
+ var expected = """
+ ///
+ /// Generic class
+ ///
+ /// First type parameter
+ /// Second type parameter
+ /// Return value
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
@@ -934,13 +1075,16 @@ public async Task AppendXmlDocTypeParams_WithIndentation_Should_RespectIndentati
("U", "Second type parameter"),
};
- var result = builder.AppendXmlDocTypeParams(typeParameters).ToString();
+ var result = builder
+ .AppendXmlDocTypeParams(typeParameters)
+ .ToString()
+ .Replace("\r\n", "\n", StringComparison.Ordinal);
- var expected =
- " /// First type parameter"
- + Environment.NewLine
- + " /// Second type parameter"
- + Environment.NewLine;
+ var expected = """
+ /// First type parameter
+ /// Second type parameter
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs
index 8b0e745..087923a 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Indentation.cs
@@ -139,15 +139,13 @@ public async Task DecrementIndent_Should_Not_Affect_Existing_Content()
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
+ _ = builder.Append("}"); // This automatically decrements indent and moves to new line
+ _ = builder.Append("}"); // This automatically decrements indent and moves to new line
var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
@@ -158,7 +156,8 @@ public void Method(){
Console.WriteLine("Hello");
}
}
- """;
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
_ = await Assert.That(result).IsEqualTo(expected);
}
diff --git a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Scope.cs b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Scope.cs
index e730e8f..0b58c53 100644
--- a/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Scope.cs
+++ b/tests/NetEvolve.CodeBuilder.Tests.Unit/CSharpCodeBuilderTests.Scope.cs
@@ -26,8 +26,13 @@ public async Task Scope_Should_Append_Opening_Brace()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("{");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -40,8 +45,13 @@ public async Task Scope_Should_Append_Closing_Brace_On_Dispose()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -54,9 +64,13 @@ public async Task Scope_Should_Contain_Both_Braces()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("{");
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -73,9 +87,15 @@ public async Task Scope_Nested_Should_Create_Multiple_Indentation_Levels()
}
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains(" Level 1"); // 4 spaces
- _ = await Assert.That(result).Contains(" Level 2"); // 8 spaces
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ Level 1{
+ Level 2}
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -93,10 +113,15 @@ public async Task Scope_Multiple_Sequential_Should_Reset_Indentation()
_ = builder.Append("Second");
}
- var result = builder.ToString();
- // Both should be at the same indentation level (top level)
- _ = await Assert.That(result).Contains("{");
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ {
+ First}
+ {
+ Second}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -110,7 +135,7 @@ public async Task Scope_With_Tabs_Should_Use_Tab_Indentation()
}
var result = builder.ToString();
- _ = await Assert.That(result).Contains("\tHello");
+ _ = await Assert.That(result).IsEqualTo("{" + Environment.NewLine + "\tHello}" + Environment.NewLine);
}
#endregion
@@ -127,8 +152,14 @@ public async Task ScopeLine_Should_Append_Line_Before_Scope()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("public class MyClass");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -141,8 +172,14 @@ public async Task ScopeLine_Should_Include_Opening_Brace()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("{");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -155,8 +192,14 @@ public async Task ScopeLine_Should_Include_Closing_Brace_On_Dispose()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -169,9 +212,14 @@ public async Task ScopeLine_With_Null_Value_Should_Append_Only_Braces()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("{");
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -184,9 +232,14 @@ public async Task ScopeLine_With_Empty_String_Should_Append_Only_Braces()
// Empty scope
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("{");
- _ = await Assert.That(result).Contains("}");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+
+ {
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -199,9 +252,14 @@ public async Task ScopeLine_With_Content_Should_Format_Class_Structure()
_ = builder.Append("private int _field;");
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("public class MyClass");
- _ = await Assert.That(result).Contains("private int _field;");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ private int _field;}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -217,10 +275,17 @@ public async Task ScopeLine_Nested_Should_Create_Class_Hierarchy()
}
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("namespace MyNamespace");
- _ = await Assert.That(result).Contains("public class OuterClass");
- _ = await Assert.That(result).Contains("public void Method() { }");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ namespace MyNamespace
+ {
+ public class OuterClass
+ {
+ public void Method() { }}
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -233,8 +298,14 @@ public async Task ScopeLine_Should_Apply_Proper_Indentation_To_Content()
_ = builder.Append("public string Name { get; set; }");
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains(" public string Name { get; set; }");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class MyClass
+ {
+ public string Name { get; set; }}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -254,9 +325,18 @@ public async Task ScopeLine_Multiple_Sequential_Should_Create_Multiple_Classes()
_ = builder.Append("public string Name { get; set; }");
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("public class FirstClass");
- _ = await Assert.That(result).Contains("public class SecondClass");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ public class FirstClass
+ {
+ public int Id { get; set; }}
+
+ public class SecondClass
+ {
+ public string Name { get; set; }}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -270,7 +350,16 @@ public async Task ScopeLine_With_Tabs_Should_Use_Tab_Indentation()
}
var result = builder.ToString();
- _ = await Assert.That(result).Contains("\tpublic void Method() { }");
+ _ = await Assert
+ .That(result)
+ .IsEqualTo(
+ "public class MyClass"
+ + Environment.NewLine
+ + "{"
+ + Environment.NewLine
+ + "\tpublic void Method() { }}"
+ + Environment.NewLine
+ );
}
[Test]
@@ -289,11 +378,20 @@ public async Task ScopeLine_Complex_Nested_Structure_Should_Format_Correctly()
}
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("namespace MyApplication");
- _ = await Assert.That(result).Contains(" public class MyClass");
- _ = await Assert.That(result).Contains(" public void MyMethod()");
- _ = await Assert.That(result).Contains(" var x = 10;");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ namespace MyApplication
+ {
+ public class MyClass
+ {
+ public void MyMethod()
+ {
+ var x = 10;}
+ }
+ }
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
[Test]
@@ -319,11 +417,20 @@ public async Task ScopeLine_With_Documentation_Should_Format_Complete_Class()
_ = builder.Append("public string Name { get; set; }");
}
- var result = builder.ToString();
- _ = await Assert.That(result).Contains("/// ");
- _ = await Assert.That(result).Contains("/// Represents a person entity.");
- _ = await Assert.That(result).Contains("public class Person");
- _ = await Assert.That(result).Contains("public string Name { get; set; }");
+ var result = builder.ToString().Replace("\r\n", "\n", StringComparison.Ordinal);
+ var expected = """
+ ///
+ /// Represents a person entity.
+ ///
+ public class Person
+ {
+ ///
+ /// Gets or sets the person's name.
+ ///
+ public string Name { get; set; }}
+
+ """.Replace("\r\n", "\n", StringComparison.Ordinal);
+ _ = await Assert.That(result).IsEqualTo(expected);
}
#endregion