Files
2026-07-16 06:25:54 +02:00

1348 lines
54 KiB
C#

/* ========================================================================
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System;
using System.Globalization;
using System.Linq;
using NUnit.Framework;
namespace Opc.Ua.SourceGeneration.Templating.Tests
{
/// <summary>
/// Unit tests for the TemplateParser.AppendLiteral method.
/// </summary>
[TestFixture]
[Category("Templating")]
[SetCulture("en-us")]
[SetUICulture("en-us")]
[Parallelizable]
public class TemplateParserTests
{
/// <summary>
/// Tests that AppendLiteral correctly adds an empty string literal without creating any operations.
/// </summary>
[Test]
public void AppendLiteral_EmptyString_AddsNoOperations()
{
// Arrange
var parser = new TemplateParser(0, 0);
// Act
parser.AppendLiteral(string.Empty);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Is.Empty);
}
/// <summary>
/// Tests that AppendLiteral correctly adds a whitespace-only string as a WhiteSpace operation.
/// </summary>
[TestCase(" ")]
[TestCase(" ")]
[TestCase(" ")]
public void AppendLiteral_WhitespaceOnlyString_AddsWhiteSpaceOperation(string whitespace)
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral(whitespace);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.WhiteSpace));
Assert.That(operations[0].Item, Is.EqualTo(whitespace));
Assert.That(operations[0].Offset, Is.Zero);
Assert.That(operations[0].LineNumber, Is.Zero);
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string with a single Unix-style line break.
/// </summary>
[Test]
public void AppendLiteral_StringWithUnixLineBreak_AddsLineBreakOperation()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("Hello\nWorld");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Hello"));
Assert.That(operations[0].Offset, Is.Zero);
Assert.That(operations[0].LineNumber, Is.Zero);
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[1].Item, Is.EqualTo(Environment.NewLine));
Assert.That(operations[1].Offset, Is.EqualTo(5));
Assert.That(operations[1].LineNumber, Is.Zero);
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[2].Item, Is.EqualTo("World"));
Assert.That(operations[2].Offset, Is.Zero);
Assert.That(operations[2].LineNumber, Is.EqualTo(1));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string with a Windows-style line break (\r\n).
/// </summary>
[Test]
public void AppendLiteral_StringWithWindowsLineBreak_AddsLineBreakOperation()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("Hello\r\nWorld");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Hello"));
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[1].Item, Is.EqualTo(Environment.NewLine));
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[2].Item, Is.EqualTo("World"));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string with multiple line breaks.
/// </summary>
[Test]
public void AppendLiteral_StringWithMultipleLineBreaks_AddsMultipleLineBreakOperations()
{
// Arrange
var parser = new TemplateParser(20, 0);
// Act
parser.AppendLiteral("Line1\nLine2\nLine3");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(5));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Line1"));
Assert.That(operations[0].LineNumber, Is.Zero);
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[1].LineNumber, Is.Zero);
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[2].Item, Is.EqualTo("Line2"));
Assert.That(operations[2].LineNumber, Is.EqualTo(1));
Assert.That(operations[3].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[3].LineNumber, Is.EqualTo(1));
Assert.That(operations[4].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[4].Item, Is.EqualTo("Line3"));
Assert.That(operations[4].LineNumber, Is.EqualTo(2));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string that starts with a line break.
/// </summary>
[Test]
public void AppendLiteral_StringStartingWithLineBreak_AddsLineBreakOperationFirst()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("\nContent");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(2));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[0].Item, Is.EqualTo(Environment.NewLine));
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[1].Item, Is.EqualTo("Content"));
Assert.That(operations[1].LineNumber, Is.EqualTo(1));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string that ends with a line break.
/// </summary>
[Test]
public void AppendLiteral_StringEndingWithLineBreak_AddsLineBreakOperationLast()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("Content\n");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(2));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Content"));
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[1].Item, Is.EqualTo(Environment.NewLine));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string with only a line break character.
/// </summary>
[Test]
public void AppendLiteral_OnlyLineBreak_AddsLineBreakOperation()
{
// Arrange
var parser = new TemplateParser(1, 0);
// Act
parser.AppendLiteral("\n");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[0].Item, Is.EqualTo(Environment.NewLine));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string with special characters.
/// </summary>
[TestCase("Hello@World!")]
[TestCase("Test#123$%^")]
[TestCase("Tab\tCharacter")]
public void AppendLiteral_StringWithSpecialCharacters_AddsLiteralOperation(string input)
{
// Arrange
var parser = new TemplateParser(20, 0);
// Act
parser.AppendLiteral(input);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo(input));
}
/// <summary>
/// Tests that AppendLiteral correctly tracks offset across multiple calls.
/// </summary>
[Test]
public void AppendLiteral_MultipleCalls_TracksOffsetCorrectly()
{
// Arrange
var parser = new TemplateParser(20, 0);
// Act
parser.AppendLiteral("Hello");
parser.AppendLiteral(" ");
parser.AppendLiteral("World");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Hello"));
Assert.That(operations[0].Offset, Is.Zero);
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.WhiteSpace));
Assert.That(operations[1].Item, Is.EqualTo(" "));
Assert.That(operations[1].Offset, Is.EqualTo(5));
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[2].Item, Is.EqualTo("World"));
Assert.That(operations[2].Offset, Is.EqualTo(6));
}
/// <summary>
/// Tests that AppendLiteral correctly resets offset after line breaks.
/// </summary>
[Test]
public void AppendLiteral_LineBreakResetsOffset_OffsetIsZeroAfterLineBreak()
{
// Arrange
var parser = new TemplateParser(20, 0);
// Act
parser.AppendLiteral("Hello\nWorld");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Offset, Is.Zero);
Assert.That(operations[1].Offset, Is.EqualTo(5)); // lb
Assert.That(operations[2].Offset, Is.Zero);
}
/// <summary>
/// Tests that AppendLiteral correctly handles a very long string without line breaks.
/// </summary>
[Test]
public void AppendLiteral_VeryLongString_AddsLiteralOperation()
{
// Arrange
var parser = new TemplateParser(10000, 0);
string longString = new('A', 5000);
// Act
parser.AppendLiteral(longString);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo(longString));
Assert.That(operations[0].Item, Has.Length.EqualTo(5000));
}
/// <summary>
/// Tests that AppendLiteral correctly handles mixed content with whitespace and line breaks.
/// </summary>
[Test]
public void AppendLiteral_MixedContentWithWhitespaceAndLineBreaks_AddsMultipleOperations()
{
// Arrange
var parser = new TemplateParser(30, 0);
// Act
parser.AppendLiteral("Hello \nWorld");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Hello "));
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[2].Item, Is.EqualTo("World"));
}
/// <summary>
/// Tests that AppendLiteral correctly handles consecutive line breaks.
/// </summary>
[Test]
public void AppendLiteral_ConsecutiveLineBreaks_AddsMultipleLineBreakOperations()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("\n\n\n");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(3));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[0].LineNumber, Is.Zero);
Assert.That(operations[1].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[1].LineNumber, Is.EqualTo(1));
Assert.That(operations[2].Type, Is.EqualTo(ParsedTemplateString.OpType.LineBreak));
Assert.That(operations[2].LineNumber, Is.EqualTo(2));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a carriage return not followed by newline.
/// </summary>
[Test]
public void AppendLiteral_CarriageReturnWithoutNewline_AddsLiteralOperation()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("Hello\rWorld");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Hello\rWorld"));
}
/// <summary>
/// Tests that AppendLiteral correctly handles a string ending with carriage return.
/// </summary>
[Test]
public void AppendLiteral_StringEndingWithCarriageReturn_AddsLiteralOperation()
{
// Arrange
var parser = new TemplateParser(10, 0);
// Act
parser.AppendLiteral("Content\r");
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Literal));
Assert.That(operations[0].Item, Is.EqualTo("Content\r"));
}
/// <summary>
/// Tests that the TemplateParser constructor initializes correctly with both parameters set to zero.
/// This represents an empty template with no literals or formatted segments.
/// Expected: Parsed property should be initialized with LiteralLength = 0 and FormattedCount = 0.
/// </summary>
[Test]
public void Constructor_BothParametersZero_InitializesParsedCorrectly()
{
// Arrange & Act
var parser = new TemplateParser(0, 0);
// Assert
Assert.That(parser.Parsed, Is.Not.Null);
Assert.That(parser.Parsed.LiteralLength, Is.Zero);
Assert.That(parser.Parsed.FormattedCount, Is.Zero);
}
/// <summary>
/// Tests that the TemplateParser constructor correctly handles various valid combinations of parameters.
/// This includes positive values, zero values, and different combinations.
/// Expected: Parsed property should be initialized with correct LiteralLength and FormattedCount values.
/// </summary>
[TestCase(10, 0, TestName = "Constructor_PositiveLiteralZeroFormatted_InitializesParsedCorrectly")]
[TestCase(0, 5, TestName = "Constructor_ZeroLiteralPositiveFormatted_InitializesParsedCorrectly")]
[TestCase(5, 2, TestName = "Constructor_BothPositive_InitializesParsedCorrectly")]
[TestCase(1, 1, TestName = "Constructor_BothOne_InitializesParsedCorrectly")]
[TestCase(100, 50, TestName = "Constructor_LargePositiveValues_InitializesParsedCorrectly")]
public void Constructor_ValidParameters_InitializesParsedCorrectly(int literalLength, int formattedCount)
{
// Arrange & Act
var parser = new TemplateParser(literalLength, formattedCount);
// Assert
Assert.That(parser.Parsed, Is.Not.Null);
Assert.That(parser.Parsed.LiteralLength, Is.EqualTo(literalLength));
Assert.That(parser.Parsed.FormattedCount, Is.EqualTo(formattedCount));
}
/// <summary>
/// Tests that the TemplateParser constructor throws ArgumentOutOfRangeException when both parameters are negative.
/// This is because the sum would be negative, causing List capacity to be invalid.
/// Expected: ArgumentOutOfRangeException should be thrown.
/// </summary>
[Test]
public void Constructor_BothNegative_ThrowsArgumentOutOfRangeException()
{
// Arrange & Act & Assert
Assert.Throws<ArgumentOutOfRangeException>(() => new TemplateParser(-1, -1));
}
/// <summary>
/// Tests that the TemplateParser constructor throws ArgumentOutOfRangeException when one parameter is negative
/// and the sum of both parameters is negative.
/// Expected: ArgumentOutOfRangeException should be thrown.
/// </summary>
[TestCase(-5, 3, TestName = "Constructor_NegativeLiteralSumNegative_ThrowsArgumentOutOfRangeException")]
[TestCase(2, -10, TestName = "Constructor_NegativeFormattedSumNegative_ThrowsArgumentOutOfRangeException")]
[TestCase(-100, 50, TestName = "Constructor_LargeNegativeLiteralSumNegative_ThrowsArgumentOutOfRangeException")]
public void Constructor_NegativeParametersWithNegativeSum_ThrowsArgumentOutOfRangeException(int literalLength, int formattedCount)
{
// Arrange & Act & Assert
Assert.Throws<ArgumentOutOfRangeException>(() => new TemplateParser(literalLength, formattedCount));
}
/// <summary>
/// Tests that the TemplateParser constructor handles single minimum integer value parameter.
/// Expected: ArgumentOutOfRangeException due to negative capacity.
/// </summary>
[TestCase(
int.MinValue,
0,
TestName = "Constructor_MinValueLiteralZeroFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
0,
int.MinValue,
TestName = "Constructor_ZeroLiteralMinValueFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
int.MaxValue,
0,
TestName = "Constructor_MaxValueLiteralZeroFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
0,
int.MaxValue,
TestName = "Constructor_ZeroLiteralMaxValueFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
int.MaxValue,
int.MaxValue,
TestName = "Constructor_MaxValueLiteralMaxValueFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
ParsedTemplateString.MaxLiteralLength + 1,
0,
TestName = "Constructor_MaxLiteralLengthZeroFormatted_ThrowsArgumentOutOfRangeException")]
[TestCase(
0,
ParsedTemplateString.MaxFormattedCount + 1,
TestName = "Constructor_ZeroMaxFormattedLengthFormatted_ThrowsArgumentOutOfRangeException")]
public void Constructor_SingleMinValueParameter_ThrowsArgumentOutOfRangeException(
int literalLength,
int formattedCount)
{
// Arrange & Act & Assert
Assert.Throws<ArgumentOutOfRangeException>(() => new TemplateParser(literalLength, formattedCount));
}
/// <summary>
/// Tests that AppendFormatted correctly handles various integer values.
/// </summary>
[TestCase(0, "0", TestName = "AppendFormatted_IntegerZero_AddsValueOperation")]
[TestCase(42, "42", TestName = "AppendFormatted_IntegerPositive_AddsValueOperation")]
[TestCase(-42, "-42", TestName = "AppendFormatted_IntegerNegative_AddsValueOperation")]
[TestCase(int.MaxValue, "2147483647", TestName = "AppendFormatted_IntegerMaxValue_AddsValueOperation")]
[TestCase(int.MinValue, "-2147483648", TestName = "AppendFormatted_IntegerMinValue_AddsValueOperation")]
public void AppendFormatted_Integer_AddsValueOperation(int value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles various long values.
/// </summary>
[TestCase(0L, "0", TestName = "AppendFormatted_LongZero_AddsValueOperation")]
[TestCase(42L, "42", TestName = "AppendFormatted_LongPositive_AddsValueOperation")]
[TestCase(-42L, "-42", TestName = "AppendFormatted_LongNegative_AddsValueOperation")]
[TestCase(long.MaxValue, "9223372036854775807", TestName = "AppendFormatted_LongMaxValue_AddsValueOperation")]
[TestCase(long.MinValue, "-9223372036854775808", TestName = "AppendFormatted_LongMinValue_AddsValueOperation")]
public void AppendFormatted_Long_AddsValueOperation(long value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles various double values including special values.
/// </summary>
[TestCase(0.0, "0", TestName = "AppendFormatted_DoubleZero_AddsValueOperation")]
[TestCase(42.5, "42.5", TestName = "AppendFormatted_DoublePositive_AddsValueOperation")]
[TestCase(-42.5, "-42.5", TestName = "AppendFormatted_DoubleNegative_AddsValueOperation")]
[TestCase(double.MaxValue, "1.7976931348623", TestName = "AppendFormatted_DoubleMaxValue_AddsValueOperation")]
[TestCase(double.MinValue, "-1.7976931348623", TestName = "AppendFormatted_DoubleMinValue_AddsValueOperation")]
[TestCase(double.NaN, "NaN", TestName = "AppendFormatted_DoubleNaN_AddsValueOperation")]
[TestCase(double.PositiveInfinity, "Infinity", TestName = "AppendFormatted_DoublePositiveInfinity_AddsValueOperation")]
[TestCase(double.NegativeInfinity, "-Infinity", TestName = "AppendFormatted_DoubleNegativeInfinity_AddsValueOperation")]
public void AppendFormatted_Double_AddsValueOperation(double value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Does.StartWith(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles various float values including special values.
/// </summary>
[TestCase(0.0f, "0", TestName = "AppendFormatted_FloatZero_AddsValueOperation")]
[TestCase(42.5f, "42.5", TestName = "AppendFormatted_FloatPositive_AddsValueOperation")]
[TestCase(-42.5f, "-42.5", TestName = "AppendFormatted_FloatNegative_AddsValueOperation")]
[TestCase(float.MaxValue, "3.402823", TestName = "AppendFormatted_FloatMaxValue_AddsValueOperation")]
[TestCase(float.MinValue, "-3.402823", TestName = "AppendFormatted_FloatMinValue_AddsValueOperation")]
[TestCase(float.NaN, "NaN", TestName = "AppendFormatted_FloatNaN_AddsValueOperation")]
[TestCase(float.PositiveInfinity, "Infinity", TestName = "AppendFormatted_FloatPositiveInfinity_AddsValueOperation")]
[TestCase(float.NegativeInfinity, "-Infinity", TestName = "AppendFormatted_FloatNegativeInfinity_AddsValueOperation")]
public void AppendFormatted_Float_AddsValueOperation(float value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Does.StartWith(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles decimal values.
/// </summary>
[TestCase("0", "0", TestName = "AppendFormatted_DecimalZero_AddsValueOperation")]
[TestCase("42.5", "42.5", TestName = "AppendFormatted_DecimalPositive_AddsValueOperation")]
[TestCase("-42.5", "-42.5", TestName = "AppendFormatted_DecimalNegative_AddsValueOperation")]
public void AppendFormatted_Decimal_AddsValueOperation(string valueString, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
decimal value = decimal.Parse(valueString, CultureInfo.InvariantCulture);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles decimal boundary values.
/// </summary>
[Test]
public void AppendFormatted_DecimalMaxValue_AddsValueOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
const decimal value = decimal.MaxValue;
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(decimal.MaxValue.ToString(CultureInfo.InvariantCulture)));
}
/// <summary>
/// Tests that AppendFormatted correctly handles decimal minimum value.
/// </summary>
[Test]
public void AppendFormatted_DecimalMinValue_AddsValueOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
const decimal value = decimal.MinValue;
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(decimal.MinValue.ToString(CultureInfo.InvariantCulture)));
}
/// <summary>
/// Tests that AppendFormatted correctly handles boolean values.
/// </summary>
[TestCase(true, "True", TestName = "AppendFormatted_BooleanTrue_AddsValueOperation")]
[TestCase(false, "False", TestName = "AppendFormatted_BooleanFalse_AddsValueOperation")]
public void AppendFormatted_Boolean_AddsValueOperation(bool value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles string values and adds Token operation.
/// </summary>
[TestCase("TestValue", TestName = "AppendFormatted_StringNormal_AddsTokenOperation")]
[TestCase("", TestName = "AppendFormatted_StringEmpty_AddsTokenOperation")]
[TestCase(" ", TestName = "AppendFormatted_StringSingleSpace_AddsTokenOperation")]
[TestCase(" ", TestName = "AppendFormatted_StringMultipleSpaces_AddsTokenOperation")]
[TestCase("\t", TestName = "AppendFormatted_StringTab_AddsTokenOperation")]
[TestCase("\n", TestName = "AppendFormatted_StringNewline_AddsTokenOperation")]
[TestCase("\r\n", TestName = "AppendFormatted_StringCRLF_AddsTokenOperation")]
public void AppendFormatted_String_AddsTokenOperation(string value)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Token));
Assert.That(operations[0].Item, Is.EqualTo(value));
}
/// <summary>
/// Tests that AppendFormatted correctly handles very long strings.
/// </summary>
[Test]
public void AppendFormatted_VeryLongString_AddsTokenOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
string value = new('A', 10000);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Token));
Assert.That(operations[0].Item, Is.EqualTo(value));
Assert.That(operations[0].Item, Has.Length.EqualTo(10000));
}
/// <summary>
/// Tests that AppendFormatted correctly handles strings with special characters.
/// </summary>
[Test]
public void AppendFormatted_StringWithSpecialCharacters_AddsTokenOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
const string value = "Hello\0World\u0001\u001F";
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Token));
Assert.That(operations[0].Item, Is.EqualTo(value));
}
/// <summary>
/// Tests that AppendFormatted correctly handles byte values.
/// </summary>
[TestCase((byte)0, "0", TestName = "AppendFormatted_ByteZero_AddsValueOperation")]
[TestCase((byte)42, "42", TestName = "AppendFormatted_BytePositive_AddsValueOperation")]
[TestCase(byte.MaxValue, "255", TestName = "AppendFormatted_ByteMaxValue_AddsValueOperation")]
[TestCase(byte.MinValue, "0", TestName = "AppendFormatted_ByteMinValue_AddsValueOperation")]
public void AppendFormatted_Byte_AddsValueOperation(byte value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles short values.
/// </summary>
[TestCase((short)0, "0", TestName = "AppendFormatted_ShortZero_AddsValueOperation")]
[TestCase((short)42, "42", TestName = "AppendFormatted_ShortPositive_AddsValueOperation")]
[TestCase((short)-42, "-42", TestName = "AppendFormatted_ShortNegative_AddsValueOperation")]
[TestCase(short.MaxValue, "32767", TestName = "AppendFormatted_ShortMaxValue_AddsValueOperation")]
[TestCase(short.MinValue, "-32768", TestName = "AppendFormatted_ShortMinValue_AddsValueOperation")]
public void AppendFormatted_Short_AddsValueOperation(short value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles char values.
/// </summary>
[TestCase('A', "A", TestName = "AppendFormatted_CharLetter_AddsValueOperation")]
[TestCase('0', "0", TestName = "AppendFormatted_CharDigit_AddsValueOperation")]
[TestCase(' ', " ", TestName = "AppendFormatted_CharSpace_AddsValueOperation")]
[TestCase('\n', "\n", TestName = "AppendFormatted_CharNewline_AddsValueOperation")]
[TestCase('\0', "\0", TestName = "AppendFormatted_CharNull_AddsValueOperation")]
public void AppendFormatted_Char_AddsValueOperation(char value, string expectedString)
{
// Arrange
var parser = new TemplateParser(0, 1);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(expectedString));
}
/// <summary>
/// Tests that AppendFormatted correctly handles Guid values.
/// </summary>
[Test]
public void AppendFormatted_Guid_AddsValueOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
var value = Guid.Parse("12345678-1234-1234-1234-123456789012");
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(value.ToString()));
}
/// <summary>
/// Tests that AppendFormatted correctly handles DateTime values.
/// </summary>
[Test]
public void AppendFormatted_DateTime_AddsValueOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
var value = new DateTime(2025, 1, 15, 12, 30, 45);
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo(value.ToString(CultureInfo.InvariantCulture)));
}
/// <summary>
/// Tests that AppendFormatted correctly handles custom object with overridden ToString.
/// </summary>
[Test]
public void AppendFormatted_CustomObject_AddsValueOperation()
{
// Arrange
var parser = new TemplateParser(0, 1);
var value = new CustomTestObject("TestName");
// Act
parser.AppendFormatted(value);
// Assert
var operations = parser.Parsed.Operations.ToList();
Assert.That(operations, Has.Count.EqualTo(1));
Assert.That(operations[0].Type, Is.EqualTo(ParsedTemplateString.OpType.Value));
Assert.That(operations[0].Item, Is.EqualTo("CustomTestObject: TestName"));
}
/// <summary>
/// Helper class for testing custom object ToString behavior.
/// </summary>
private sealed class CustomTestObject
{
private readonly string m_name;
public CustomTestObject(string name)
{
m_name = name;
}
public override string ToString()
{
return $"CustomTestObject: {m_name}";
}
}
/// <summary>
/// Tests that GetFormattedText returns an empty string when the parser is empty with no literals or formatted items.
/// </summary>
[Test]
public void GetFormattedText_EmptyParser_ReturnsEmptyString()
{
// Arrange
var parser = new TemplateParser(0, 0);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo(string.Empty));
}
/// <summary>
/// Tests that GetFormattedText returns the correct string when the parser contains only literals.
/// </summary>
[Test]
public void GetFormattedText_OnlyLiterals_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 0);
parser.AppendLiteral("Hello");
parser.AppendLiteral(" ");
parser.AppendLiteral("World");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Hello World"));
}
/// <summary>
/// Tests that GetFormattedText returns the correct formatted string when the parser contains only formatted items.
/// </summary>
[Test]
public void GetFormattedText_OnlyFormattedItems_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(0, 2);
parser.AppendFormatted(42);
parser.AppendFormatted(3.14);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("423.14"));
}
/// <summary>
/// Tests that GetFormattedText returns the correct string when the parser contains a mix of literals and formatted items.
/// </summary>
[Test]
public void GetFormattedText_MixedContent_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(6, 1);
parser.AppendLiteral("Hello ");
parser.AppendFormatted("World");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Hello World"));
}
/// <summary>
/// Tests that GetFormattedText handles special characters in literals correctly.
/// </summary>
[Test]
public void GetFormattedText_SpecialCharactersInLiterals_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(20, 0);
parser.AppendLiteral("Special: @#$%^&*()");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Special: @#$%^&*()"));
}
/// <summary>
/// Tests that GetFormattedText handles whitespace-only literals correctly.
/// </summary>
[Test]
public void GetFormattedText_WhitespaceOnlyLiterals_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 0);
parser.AppendLiteral(" ");
parser.AppendLiteral("\t");
parser.AppendLiteral(" ");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo(" \t "));
}
/// <summary>
/// Tests that GetFormattedText handles line breaks in literals correctly.
/// </summary>
[Test]
public void GetFormattedText_LiteralsWithLineBreaks_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(20, 0);
parser.AppendLiteral("Line 1\nLine 2\nLine 3");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo($"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"));
}
/// <summary>
/// Tests that GetFormattedText handles Windows-style line breaks correctly.
/// </summary>
[Test]
public void GetFormattedText_LiteralsWithWindowsLineBreaks_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(20, 0);
parser.AppendLiteral("Line 1\r\nLine 2\r\nLine 3");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo($"Line 1{Environment.NewLine}Line 2{Environment.NewLine}Line 3"));
}
/// <summary>
/// Tests that GetFormattedText handles multiple formatted items with different types correctly.
/// </summary>
[Test]
public void GetFormattedText_MultipleFormattedItemsWithDifferentTypes_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 4);
parser.AppendLiteral("Integer: ");
parser.AppendFormatted(42);
parser.AppendLiteral(", Double: ");
parser.AppendFormatted(3.14);
parser.AppendLiteral(", String: ");
parser.AppendFormatted("Test");
parser.AppendLiteral(", Bool: ");
parser.AppendFormatted(true);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Integer: 42, Double: 3.14, String: Test, Bool: True"));
}
/// <summary>
/// Tests that GetFormattedText uses InvariantCulture for formatting numeric values.
/// </summary>
[Test]
public void GetFormattedText_NumericValues_UsesInvariantCulture()
{
// Arrange
var parser = new TemplateParser(5, 1);
parser.AppendLiteral("Value: ");
parser.AppendFormatted(1234.56);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Value: 1234.56"));
Assert.That(result, Does.Contain("."));
Assert.That(result, Does.Not.Contain(","));
}
/// <summary>
/// Tests that GetFormattedText handles empty string literals correctly.
/// </summary>
[Test]
public void GetFormattedText_EmptyStringLiterals_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 1);
parser.AppendLiteral(string.Empty);
parser.AppendFormatted("Value");
parser.AppendLiteral(string.Empty);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Value"));
}
/// <summary>
/// Tests that GetFormattedText handles negative numbers correctly.
/// </summary>
[Test]
public void GetFormattedText_NegativeNumbers_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(5, 2);
parser.AppendLiteral("Neg: ");
parser.AppendFormatted(-42);
parser.AppendLiteral(", ");
parser.AppendFormatted(-3.14);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Neg: -42, -3.14"));
}
/// <summary>
/// Tests that GetFormattedText handles zero values correctly.
/// </summary>
[Test]
public void GetFormattedText_ZeroValues_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(5, 2);
parser.AppendLiteral("Zero: ");
parser.AppendFormatted(0);
parser.AppendLiteral(", ");
parser.AppendFormatted(0.0);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Zero: 0, 0"));
}
/// <summary>
/// Tests that GetFormattedText handles int.MaxValue correctly.
/// </summary>
[Test]
public void GetFormattedText_IntMaxValue_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(5, 1);
parser.AppendLiteral("Max: ");
parser.AppendFormatted(int.MaxValue);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo($"Max: {int.MaxValue}"));
}
/// <summary>
/// Tests that GetFormattedText handles int.MinValue correctly.
/// </summary>
[Test]
public void GetFormattedText_IntMinValue_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(5, 1);
parser.AppendLiteral("Min: ");
parser.AppendFormatted(int.MinValue);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo($"Min: {int.MinValue}"));
}
/// <summary>
/// Tests that GetFormattedText handles double.NaN correctly.
/// </summary>
[Test]
public void GetFormattedText_DoubleNaN_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(5, 1);
parser.AppendLiteral("NaN: ");
parser.AppendFormatted(double.NaN);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("NaN: NaN"));
}
/// <summary>
/// Tests that GetFormattedText handles double.PositiveInfinity correctly.
/// </summary>
[Test]
public void GetFormattedText_DoublePositiveInfinity_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 1);
parser.AppendLiteral("Infinity: ");
parser.AppendFormatted(double.PositiveInfinity);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Infinity: Infinity"));
}
/// <summary>
/// Tests that GetFormattedText handles double.NegativeInfinity correctly.
/// </summary>
[Test]
public void GetFormattedText_DoubleNegativeInfinity_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 1);
parser.AppendLiteral("NegInf: ");
parser.AppendFormatted(double.NegativeInfinity);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("NegInf: -Infinity"));
}
/// <summary>
/// Tests that GetFormattedText handles empty string formatted items correctly.
/// </summary>
[Test]
public void GetFormattedText_EmptyStringFormattedItem_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(10, 1);
parser.AppendLiteral("Value: ");
parser.AppendFormatted(string.Empty);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Value: "));
}
/// <summary>
/// Tests that GetFormattedText handles very long strings correctly.
/// </summary>
[Test]
public void GetFormattedText_VeryLongString_ReturnsCorrectString()
{
// Arrange
string longString = new('A', 10000);
var parser = new TemplateParser(longString.Length, 0);
parser.AppendLiteral(longString);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo(longString));
Assert.That(result, Has.Length.EqualTo(10000));
}
/// <summary>
/// Tests that GetFormattedText handles complex multi-line templates correctly.
/// </summary>
[Test]
public void GetFormattedText_ComplexMultiLineTemplate_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(50, 3);
parser.AppendLiteral("Name: ");
parser.AppendFormatted("John");
parser.AppendLiteral("\nAge: ");
parser.AppendFormatted(30);
parser.AppendLiteral("\nScore: ");
parser.AppendFormatted(95.5);
// Act
string result = parser.GetFormattedText();
// Assert
string expectedResult = $"Name: John{Environment.NewLine}Age: 30{Environment.NewLine}Score: 95.5";
Assert.That(result, Is.EqualTo(expectedResult));
}
/// <summary>
/// Tests that GetFormattedText handles Unicode characters correctly.
/// </summary>
[Test]
public void GetFormattedText_UnicodeCharacters_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(20, 0);
parser.AppendLiteral("Unicode: 你好 🌍 ñ");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Unicode: 你好 🌍 ñ"));
}
/// <summary>
/// Tests that GetFormattedText handles tab characters correctly.
/// </summary>
[Test]
public void GetFormattedText_TabCharacters_ReturnsCorrectString()
{
// Arrange
var parser = new TemplateParser(20, 0);
parser.AppendLiteral("Col1\tCol2\tCol3");
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo("Col1\tCol2\tCol3"));
}
/// <summary>
/// Tests that GetFormattedText handles boolean values correctly.
/// </summary>
[TestCase(true, "True")]
[TestCase(false, "False")]
public void GetFormattedText_BooleanValues_ReturnsCorrectString(bool value, string expected)
{
// Arrange
var parser = new TemplateParser(5, 1);
parser.AppendLiteral("Bool: ");
parser.AppendFormatted(value);
// Act
string result = parser.GetFormattedText();
// Assert
Assert.That(result, Is.EqualTo($"Bool: {expected}"));
}
}
}