diff --git a/src/Computer.V2.Tests/FunctionsTests.cs b/src/Computer.V2.Tests/FunctionsTests.cs new file mode 100644 index 0000000..20a024a --- /dev/null +++ b/src/Computer.V2.Tests/FunctionsTests.cs @@ -0,0 +1,178 @@ +using Xunit; +using Computer.V2.Lib; +using Computer.V2.Lib.Exceptions; + +namespace Computer.V2.Tests +{ + public class FunctionsTests + { + [Fact] + public void NormaliseFunc_SimplePolynomial_ReturnsNormalizedForm() + { + // Arrange + string expression = "2*x^2 + 3*x + 1"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("2*x^2", result); + Assert.Contains("3*x", result); + Assert.Contains("1", result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithSameTerms_CombinesTerms() + { + // Arrange + string expression = "x^2 + 2*x^2 + 3*x"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("3*x^2", result); + Assert.Contains("3*x", result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithNegativeTerms_HandlesNegatives() + { + // Arrange + string expression = "x^2 - 2*x + 1"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("1*x^2", result); + Assert.Contains("-2*x", result); + Assert.Contains("1", result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithZeroCoefficient_ExcludesZeroTerms() + { + // Arrange + string expression = "0*x^2 + 3*x + 5"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.DoesNotContain("0*x^2", result); + Assert.Contains("3*x", result); + Assert.Contains("5", result); + } + + [Fact] + public void NormaliseFunc_ConstantExpression_ReturnsConstant() + { + // Arrange + string expression = "42"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Equal("42", result); + } + + [Fact] + public void NormaliseFunc_ExpressionWithoutVariables_CalculatesResult() + { + // Arrange + string expression = "2 + 3 * 4"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Equal("14", result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithImplicitCoefficients_AddsCoefficients() + { + // Arrange + string expression = "x^2 + x + 1"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("1*x^2", result); + Assert.Contains("1*x", result); + } + + [Fact] + public void NormaliseFunc_HighDegreePolynomial_OrdersTermsCorrectly() + { + // Arrange + string expression = "1 + x + x^3 + x^2"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + int posX3 = result.IndexOf("x^3"); + int posX2 = result.IndexOf("x^2"); + int posX = result.IndexOf("*x"); + + Assert.True(posX3 < posX2); + Assert.True(posX2 < posX); + } + + [Fact] + public void NormaliseFunc_InvalidPowerFormat_ThrowsInvalidExpressionException() + { + // Arrange + string expression = "x^-1 + 2"; + + // Act & Assert + Assert.Throws(() => Functions.NormaliseFunc(expression)); + } + + [Theory] + [InlineData("2*x + 3", "2*x+3")] + [InlineData("x^2 - 5*x + 6", "1*x^2-5*x+6")] + [InlineData("-x^2 + 4", "-1*x^2+4")] + public void NormaliseFunc_VariousPolynomials_ReturnsExpectedForm(string input, string expected) + { + // Act + string result = Functions.NormaliseFunc(input); + + // Assert + Assert.Equal(expected, result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithMatrixElements_PreservesMatrixElements() + { + // Arrange + string expression = "x^2 + [1,2]\n[3,4]"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("x^2", result); + Assert.Contains("[1,2]", result); + Assert.Contains("[3,4]", result); + } + + [Fact] + public void NormaliseFunc_PolynomialWithImaginaryNumbers_PreservesImaginaryParts() + { + // Arrange + string expression = "x^2 + 2*i"; + + // Act + string result = Functions.NormaliseFunc(expression); + + // Assert + Assert.Contains("x^2", result); + Assert.Contains("2*i", result); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/Computer.V2.Tests.csproj b/tests/Computer.V2.Tests/Computer.V2.Tests.csproj new file mode 100644 index 0000000..f6a0e8a --- /dev/null +++ b/tests/Computer.V2.Tests/Computer.V2.Tests.csproj @@ -0,0 +1,29 @@ + + + + net9.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/tests/Computer.V2.Tests/ExceptionTests.cs b/tests/Computer.V2.Tests/ExceptionTests.cs new file mode 100644 index 0000000..63008e0 --- /dev/null +++ b/tests/Computer.V2.Tests/ExceptionTests.cs @@ -0,0 +1,117 @@ +using Xunit; +using Computer.V2.Lib.Exceptions; +using System; + +namespace Computer.V2.Tests +{ + public class ExceptionTests + { + [Fact] + public void InvalidExpressionException_WithMessage_SetsMessageCorrectly() + { + // Arrange + string expectedMessage = "Test error message"; + + // Act + var exception = new InvalidExpressionException(expectedMessage); + + // Assert + Assert.Equal(expectedMessage, exception.Message); + Assert.IsAssignableFrom(exception); + } + + [Fact] + public void InvalidMatrixException_WithMessage_SetsMessageCorrectly() + { + // Arrange + string expectedMessage = "Invalid matrix format"; + + // Act + var exception = new InvalidMatrixException(expectedMessage); + + // Assert + Assert.Equal(expectedMessage, exception.Message); + Assert.IsAssignableFrom(exception); + } + + [Fact] + public void InvalidVariableException_DefaultConstructor_SetsDefaultMessage() + { + // Act + var exception = new InvalidVariableException(); + + // Assert + Assert.Equal("Invalid Use of Variables.", exception.Message); + Assert.IsAssignableFrom(exception); + } + + [Fact] + public void InvalidExpressionException_CanBeThrown() + { + // Arrange + string message = "Expression is invalid"; + + // Act & Assert + Assert.Throws(() => + { + throw new InvalidExpressionException(message); + }); + } + + [Fact] + public void InvalidMatrixException_CanBeThrown() + { + // Arrange + string message = "Matrix is invalid"; + + // Act & Assert + Assert.Throws(() => + { + throw new InvalidMatrixException(message); + }); + } + + [Fact] + public void InvalidVariableException_CanBeThrown() + { + // Act & Assert + Assert.Throws(() => + { + throw new InvalidVariableException(); + }); + } + + [Fact] + public void InvalidExpressionException_InheritsFromArgumentException() + { + // Arrange + var exception = new InvalidExpressionException("test"); + + // Act & Assert + Assert.IsType(exception); + Assert.IsAssignableFrom(exception); + } + + [Fact] + public void InvalidMatrixException_InheritsFromException() + { + // Arrange + var exception = new InvalidMatrixException("test"); + + // Act & Assert + Assert.IsType(exception); + Assert.IsAssignableFrom(exception); + } + + [Fact] + public void InvalidVariableException_InheritsFromException() + { + // Arrange + var exception = new InvalidVariableException(); + + // Act & Assert + Assert.IsType(exception); + Assert.IsAssignableFrom(exception); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/MathsTests.cs b/tests/Computer.V2.Tests/MathsTests.cs new file mode 100644 index 0000000..ad7b08d --- /dev/null +++ b/tests/Computer.V2.Tests/MathsTests.cs @@ -0,0 +1,134 @@ +using Xunit; +using Computer.V2.Lib; +using Computer.V2.Lib.Exceptions; + +namespace Computer.V2.Tests +{ + public class MathsTests + { + [Theory] + [InlineData("2+3", "5")] + [InlineData("10-4", "6")] + [InlineData("3*4", "12")] + [InlineData("15/3", "5")] + public void Calculate_BasicOperations_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("2^3", "8")] + [InlineData("4^2", "16")] + [InlineData("5^0", "1")] + public void Calculate_PowerOperations_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + + [Fact] + public void Calculate_WithBrackets_ReturnsCorrectResult() + { + string expression = "(2+3)*4"; + string result = Maths.Calculate(expression); + Assert.Equal("20", result); + } + + [Fact] + public void Calculate_ComplexExpression_ReturnsCorrectResult() + { + string expression = "2*(3+4)-5"; + string result = Maths.Calculate(expression); + Assert.Equal("9", result); + } + + [Fact] + public void Calculate_DivisionByZero_ThrowsInvalidExpressionException() + { + Assert.Throws(() => Maths.Calculate("10/0")); + } + + [Fact] + public void Calculate_InvalidPowerFormat_ThrowsInvalidExpressionException() + { + Assert.Throws(() => Maths.Calculate("2^-1")); + } + + [Fact] + public void Calculate_DoubleAsterisk_ThrowsInvalidExpressionException() + { + Assert.Throws(() => Maths.Calculate("2**3")); + } + + [Theory] + [InlineData("2*i", "2*i")] + [InlineData("3*i+4*i", "7*i")] + [InlineData("5*i-2*i", "3*i")] + public void Calculate_ImaginaryNumbers_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("i^0", "1")] + [InlineData("i^1", "1*i")] + [InlineData("i^2", "-1")] + [InlineData("i^3", "-1*i")] + [InlineData("i^4", "1")] + public void Calculate_ImaginaryPowers_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + + [Theory] + [InlineData(4, 2)] + [InlineData(9, 3)] + [InlineData(16, 4)] + [InlineData(25, 5)] + [InlineData(0, 0)] + public void Sqrt_ValidInput_ReturnsCorrectResult(double input, double expected) + { + double result = Maths.Sqrt(input); + Assert.Equal(expected, result, 4); + } + + [Fact] + public void Sqrt_NegativeInput_ReturnsInput() + { + double input = -4; + double result = Maths.Sqrt(input); + Assert.Equal(input, result); + } + + [Theory] + [InlineData("10%3", "1")] + [InlineData("15%4", "3")] + [InlineData("20%5", "0")] + public void Calculate_ModuloOperation_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + + [Fact] + public void Calculate_NestedBrackets_ReturnsCorrectResult() + { + string expression = "((2+3)*4)-5"; + string result = Maths.Calculate(expression); + Assert.Equal("15", result); + } + + [Theory] + [InlineData("2.5+1.5", "4")] + [InlineData("3.7*2", "7.4")] + [InlineData("10.5/2.1", "5")] + public void Calculate_DecimalNumbers_ReturnsCorrectResult(string expression, string expected) + { + string result = Maths.Calculate(expression); + Assert.Equal(expected, result); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/MatrixTests.cs b/tests/Computer.V2.Tests/MatrixTests.cs new file mode 100644 index 0000000..f09b990 --- /dev/null +++ b/tests/Computer.V2.Tests/MatrixTests.cs @@ -0,0 +1,110 @@ +using Xunit; +using Computer.V2.Lib; +using Computer.V2.Lib.Exceptions; + +namespace Computer.V2.Tests +{ + public class MatrixTests + { + [Fact] + public void MatrixManipulation_WithValidMatrix_ReturnsTrue() + { + // Arrange + string validMatrix = "[1,2,3]\n[4,5,6]"; + + // Act + var result = Matrix.MatrixManipulation(validMatrix); + + // Assert + Assert.True(result.Found); + Assert.Contains("[", result.Value); + } + + [Fact] + public void MatrixManipulation_WithoutMatrix_ReturnsFalse() + { + // Arrange + string nonMatrix = "2 + 3"; + + // Act + var result = Matrix.MatrixManipulation(nonMatrix); + + // Assert + Assert.False(result.Found); + Assert.Equal(nonMatrix, result.Value); + } + + [Fact] + public void MatrixManipulation_WithScalarMultiplication_ReturnsCorrectResult() + { + // Arrange + string scalarMatrix = "2*[1,2]\n[3,4]"; + + // Act + var result = Matrix.MatrixManipulation(scalarMatrix); + + // Assert + Assert.True(result.Found); + Assert.Contains("2", result.Value); + Assert.Contains("4", result.Value); + } + + [Fact] + public void MatrixManipulation_WithInvalidMatrix_ThrowsInvalidMatrixException() + { + // Arrange + string invalidMatrix = "[1,abc,3]\n[4,5,6]"; + + // Act & Assert + Assert.Throws(() => Matrix.MatrixManipulation(invalidMatrix)); + } + + [Fact] + public void MatrixManipulation_WithMatrixMultiplication_ReturnsCorrectResult() + { + // Arrange + string matrixMultiplication = "[1,2]*[3]\n[4]"; + + // Act + var result = Matrix.MatrixManipulation(matrixMultiplication); + + // Assert + Assert.True(result.Found); + // Matrix multiplication: [1,2] * [3;4] = [1*3+2*4] = [11] + Assert.Contains("11", result.Value); + } + + [Fact] + public void MatrixManipulation_WithIncompatibleMatrices_ThrowsInvalidMatrixException() + { + // Arrange + string incompatibleMatrices = "[1,2,3]*[1]\n[2]"; + + // Act & Assert + Assert.Throws(() => Matrix.MatrixManipulation(incompatibleMatrices)); + } + + [Fact] + public void MatrixManipulation_WithMissingSemicolon_ThrowsInvalidMatrixException() + { + // Arrange + string invalidFormat = "[1,2][3,4]"; + + // Act & Assert + Assert.Throws(() => Matrix.MatrixManipulation(invalidFormat)); + } + + [Theory] + [InlineData("[1]")] + [InlineData("[1,2]\n[3,4]")] + [InlineData("[1,2,3]\n[4,5,6]\n[7,8,9]")] + public void MatrixManipulation_WithValidMatrixFormats_ReturnsTrue(string matrix) + { + // Act + var result = Matrix.MatrixManipulation(matrix); + + // Assert + Assert.True(result.Found); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/ParserTests.cs b/tests/Computer.V2.Tests/ParserTests.cs new file mode 100644 index 0000000..7f16808 --- /dev/null +++ b/tests/Computer.V2.Tests/ParserTests.cs @@ -0,0 +1,54 @@ +using Xunit; +using Computer.V2.Lib; +using Computer.V2.Lib.Exceptions; + +namespace Computer.V2.Tests +{ + public class ParserTests + { + [Fact] + public void Parse_VariableAssignment_ShouldStoreVariable() + { + // Arrange + var parser = new Parser(); + // Act + parser.Parse("x = 10"); + var result = parser.Evaluate("x"); + // Assert + Assert.Equal("10", result); + } + + [Fact] + public void Parse_FunctionAssignment_ShouldStoreFunction() + { + // Arrange + var parser = new Parser(); + // Act + parser.Parse("f(x) = x * x"); + var result = parser.Evaluate("f(5)"); + // Assert + Assert.Equal("25", result); + } + + [Fact] + public void Substitute_VariablesInExpression_ShouldReturnExpressionWithValues() + { + // Arrange + var parser = new Parser(); + parser.Parse("x = 3"); + // Act + var substituted = parser.Substitute("x + 2"); + // Assert + Assert.Equal("3 + 2", substituted); + } + + [Fact] + public void Parse_UnknownVariable_ShouldThrowInvalidVariableException() + { + // Arrange + var parser = new Parser(); + // Act & Assert + Assert.Throws(() => parser.Evaluate("y + 2")); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/PolynomialTests.cs b/tests/Computer.V2.Tests/PolynomialTests.cs new file mode 100644 index 0000000..e8005c0 --- /dev/null +++ b/tests/Computer.V2.Tests/PolynomialTests.cs @@ -0,0 +1,159 @@ +using Xunit; +using Computer.V2.Lib; + +namespace Computer.V2.Tests +{ + public class PolynomialTests + { + [Fact] + public void PolySolve_QuadraticWithTwoRealSolutions_ReturnsCorrectSolutions() + { + // Arrange + var polynomial = new Polynomial("x^2 - 5*x + 6 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("Solutions on R", result); + Assert.Contains("2", result); + Assert.Contains("3", result); + } + + [Fact] + public void PolySolve_QuadraticWithComplexSolutions_ReturnsComplexSolutions() + { + // Arrange + var polynomial = new Polynomial("x^2 + 1 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("Solutions C", result); + Assert.Contains("i", result); + } + + [Fact] + public void PolySolve_QuadraticWithOneSolution_ReturnsOneSolution() + { + // Arrange + var polynomial = new Polynomial("x^2 - 2*x + 1 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("A solution on R", result); + Assert.Contains("1", result); + } + + [Fact] + public void PolySolve_LinearEquation_ReturnsCorrectSolution() + { + // Arrange + var polynomial = new Polynomial("2*x - 4 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("Solution on R", result); + Assert.Contains("2", result); + } + + [Fact] + public void PolySolve_LinearEquationWithZeroCoefficient_ReturnsUndefined() + { + // Arrange + var polynomial = new Polynomial("0*x + 5 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("undefined", result); + } + + [Fact] + public void PolySolve_ConstantEquationWithZero_ReturnsAllRealNumbers() + { + // Arrange + var polynomial = new Polynomial("0 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("All real numbers", result); + } + + [Fact] + public void PolySolve_ConstantEquationWithNonZero_ReturnsNoSolution() + { + // Arrange + var polynomial = new Polynomial("5 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("no solutuins", result); + } + + [Fact] + public void PolySolve_HighDegreePolynomial_ReturnsCannotSolve() + { + // Arrange + var polynomial = new Polynomial("x^3 + x^2 + x + 1 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("degree is stricly greater than 2", result); + Assert.Contains("can't solve", result); + } + + [Theory] + [InlineData("x^2 - 4 = 0", "2", "-2")] + [InlineData("x^2 - 9 = 0", "3", "-3")] + [InlineData("2*x^2 - 8 = 0", "2", "-2")] + public void PolySolve_QuadraticEquations_ReturnsExpectedSolutions(string equation, string solution1, string solution2) + { + // Arrange + var polynomial = new Polynomial(equation); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains(solution1, result); + Assert.Contains(solution2, result); + } + + [Fact] + public void PolySolve_NaturalFormConversion_WorksCorrectly() + { + // Arrange + var polynomial = new Polynomial("x*x - 3*x + 2 = 0"); + + // Act + polynomial.PolySolve(); + string result = polynomial.GetOut(); + + // Assert + Assert.Contains("x^2", result.ToLower()); + Assert.Contains("Solutions on R", result); + } + } +} \ No newline at end of file diff --git a/tests/Computer.V2.Tests/StringExtensionsTests.cs b/tests/Computer.V2.Tests/StringExtensionsTests.cs new file mode 100644 index 0000000..16ac666 --- /dev/null +++ b/tests/Computer.V2.Tests/StringExtensionsTests.cs @@ -0,0 +1,133 @@ +using Xunit; +using Computer.V2.Lib.Extensions; +using Computer.V2.Lib.Exceptions; + +namespace Computer.V2.Tests +{ + public class StringExtensionsTests + { + [Theory] + [InlineData("2 + 3")] + [InlineData("x^2 - 5*x + 6")] + [InlineData("(2 + 3) * 4")] + [InlineData("[1,2]\n[3,4]")] + public void Validate_ValidExpressions_DoesNotThrow(string expression) + { + var exception = Record.Exception(() => expression.Validate()); + Assert.Null(exception); + } + + [Fact] + public void Validate_MismatchedBrackets_ThrowsInvalidExpressionException() + { + string expression = "(2 + 3"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_MismatchedSquareBrackets_ThrowsInvalidExpressionException() + { + string expression = "[1,2,3"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_TooManyEqualSigns_ThrowsInvalidExpressionException() + { + string expression = "x == 5"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_TooManyQuestionMarks_ThrowsInvalidExpressionException() + { + string expression = "x ??"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_InvalidOperatorCombination_ThrowsInvalidExpressionException() + { + string expression = "2 +- 3"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_RepeatingOperators_ThrowsInvalidExpressionException() + { + string expression = "2 ++ 3"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_InvalidVariableUsage_ThrowsInvalidExpressionException() + { + string expression = "x y"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_EmptyQuery_ThrowsInvalidExpressionException() + { + string expression = "=?"; + Assert.Throws(() => expression.Validate()); + } + + [Fact] + public void Validate_EmptyAssignment_ThrowsInvalidExpressionException() + { + string expression = "x ="; + Assert.Throws(() => expression.Validate()); + } + + [Theory] + [InlineData("2+3-1", new[] { "2", "+", "3", "-", "1" })] + [InlineData("x=5", new[] { "x", "=", "5" })] + [InlineData("a-b+c", new[] { "a", "-", "b", "+", "c" })] + public void SplitExpression_ValidExpression_ReturnsSplitArray(string expression, string[] expected) + { + string[] result = expression.SplitExpression(); + Assert.Equal(expected.Length, result.Length); + for (int i = 0; i < expected.Length; i++) + { + Assert.Equal(expected[i], result[i]); + } + } + + [Fact] + public void SplitExpression_ExpressionWithDecimalPoints_ConvertsToCommas() + { + string expression = "2.5+3.7"; + string[] result = expression.SplitExpression(); + Assert.Contains("2,5", result); + Assert.Contains("3,7", result); + } + + [Fact] + public void SplitExpression_RemovesSpaces_ReturnsCleanArray() + { + string expression = " 2 + 3 "; + string[] result = expression.SplitExpression(); + Assert.All(result, item => Assert.DoesNotContain(" ", item)); + } + + [Theory] + [InlineData("((2+3))")] + [InlineData("[[1,2],[3,4]]")] + [InlineData("(([1,2]))")] + public void Validate_NestedBrackets_DoesNotThrow(string expression) + { + var exception = Record.Exception(() => expression.Validate()); + Assert.Null(exception); + } + + [Theory] + [InlineData("(]")] + [InlineData("[)")] + [InlineData("([)]")] + public void Validate_MismatchedBracketTypes_ThrowsInvalidExpressionException(string expression) + { + Assert.Throws(() => expression.Validate()); + } + } +} \ No newline at end of file