From a866e4a535a28614b20d8374e67340036b556f8d Mon Sep 17 00:00:00 2001 From: PavelMartinelli Date: Tue, 21 Oct 2025 20:44:35 +0500 Subject: [PATCH 1/5] ObjectComparison completed --- .../1. ObjectComparison/ObjectComparison.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index d544c47..39d3cec 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using NUnit.Framework.Legacy; +using FluentAssertions; namespace HomeExercise.Tasks.ObjectComparison; public class ObjectComparison @@ -14,16 +15,13 @@ public void CheckCurrentTsar() var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, new Person("Vasili III of Russia", 28, 170, 60, null)); - // Перепишите код на использование Fluent Assertions. - ClassicAssert.AreEqual(actualTsar.Name, expectedTsar.Name); - ClassicAssert.AreEqual(actualTsar.Age, expectedTsar.Age); - ClassicAssert.AreEqual(actualTsar.Height, expectedTsar.Height); - ClassicAssert.AreEqual(actualTsar.Weight, expectedTsar.Weight); - - ClassicAssert.AreEqual(expectedTsar.Parent!.Name, actualTsar.Parent!.Name); - ClassicAssert.AreEqual(expectedTsar.Parent.Age, actualTsar.Parent.Age); - ClassicAssert.AreEqual(expectedTsar.Parent.Height, actualTsar.Parent.Height); - ClassicAssert.AreEqual(expectedTsar.Parent.Parent, actualTsar.Parent.Parent); + // Преимущества решение с FluentAssertions: + // - Легко расширяем при добавлении новых свойств в Person + // - Автоматически проверяем все свойства, включая вложенные объекты + // - При несовпадении конкретного свойства будет выдана информация какое именно свойство не совпало + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options + .Excluding(p => p.Id) + .Excluding(p => p.Parent.Id)); } [Test] @@ -34,10 +32,11 @@ public void CheckCurrentTsar_WithCustomEquality() var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, new Person("Vasili III of Russia", 28, 170, 60, null)); - // Какие недостатки у такого подхода? + // Недостатки подхода с CustomEquality: + // - Нет детальной информации о том, какое именно свойство не совпало + // - При добавлении новых свойств в Person нужно менять метод AreEqual ClassicAssert.True(AreEqual(actualTsar, expectedTsar)); } - private bool AreEqual(Person? actual, Person? expected) { if (actual == expected) return true; From 4431c5e963a830c1a6fd87242ebdfbefab126cc4 Mon Sep 17 00:00:00 2001 From: PavelMartinelli Date: Thu, 23 Oct 2025 16:21:06 +0500 Subject: [PATCH 2/5] NumberValidator completed --- .../NumberValidatorTests.cs | 118 +++++++++++++++--- 1 file changed, 98 insertions(+), 20 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 950c9bc..30a0939 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -1,4 +1,4 @@ - +using FluentAssertions; using NUnit.Framework; using NUnit.Framework.Legacy; @@ -7,25 +7,103 @@ namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [Test] - public void Test() + [TestCase(-1, 2, true)] + [TestCase(0, 0, false)] + [TestCase(1, -1, false)] + [TestCase(1, 2, false)] + [TestCase(1, 1, false)] + public void Constructor_WhenInvalidArgs_Throws(int precision, int scale, bool onlyPositive) { - Assert.Throws(() => new NumberValidator(-1, 2, true)); - Assert.DoesNotThrow(() => new NumberValidator(1, 0, true)); - Assert.Throws(() => new NumberValidator(-1, 2, false)); - Assert.DoesNotThrow(() => new NumberValidator(1, 0, true)); - - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("00.00")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-0.00")); - ClassicAssert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+0.00")); - ClassicAssert.IsTrue(new NumberValidator(4, 2, true).IsValidNumber("+1.23")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+1.23")); - ClassicAssert.IsFalse(new NumberValidator(17, 2, true).IsValidNumber("0.000")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-1.23")); - ClassicAssert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("a.sd")); + Action act = () => new NumberValidator(precision, scale, onlyPositive); + act.Should().Throw(); + } + + [TestCase(1, 0, true)] + [TestCase(2, 1, false)] + public void Constructor_WhenValidArgs_Success(int precision, int scale, bool onlyPositive) + { + Action act = () => new NumberValidator(precision, scale, onlyPositive); + act.Should().NotThrow(); + } + + [TestCase("0", 17, 2, true)] + [TestCase("0.0", 17, 2, true)] + [TestCase("+1.23", 4, 2, true)] + [TestCase("-1.23", 4, 2, false)] + [TestCase("123.4", 4, 1, true)] + [TestCase("1.2", 4, 1, true)] + [TestCase("12", 2, 0, true)] + [TestCase("11.234", 5, 4, true)] + [TestCase("11,234", 5, 4, true)] + [TestCase("1.234", 5, 3, true)] + public void IsValid_WhenValidNumbers_ReturnTrue(string value, int precision, int scale, bool onlyPositive) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(value).Should().BeTrue(); + } + + [TestCase("", 1, 0, false)] + [TestCase(null, 1, 0, false)] + [TestCase("a.sd", 3, 2, true)] + [TestCase("00.00", 3, 2, true)] + [TestCase("+0.00", 3, 2, true)] + [TestCase("0.000", 17, 2, true)] + [TestCase("-1.23", 3, 2, true)] + [TestCase("-0.00", 3, 2, true)] + [TestCase("123", 2, 0, true)] + [TestCase("-123", 3, 0, false)] + [TestCase("+12.34", 4, 2, true)] + [TestCase("1.234", 6, 2, true)] + [TestCase("-123.4", 4, 1, false)] + [TestCase("-123.456", 10, 2, false)] + [TestCase("123.", 4, 2, true)] + [TestCase("1.23a4", 10, 7, true)] + [TestCase("t", 4, 3, true)] + [TestCase("b.0", 4, 3, true)] + [TestCase("1.2b34", 10, 7, true)] + [TestCase("12.", 10, 7, true)] + [TestCase("-123", 5, 2, true)] + [TestCase("-1.23", 5, 4, true)] + public void IsValid_WhenInvalidNumbers_ReturnFalse(string value, int precision, int scale, bool onlyPositive) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(value).Should().BeFalse(); + } + + [TestCase(5, 2, "-123")] + [TestCase(5, 4, "-1.23")] + [TestCase(3, 2, "-1.23")] + public void IsValid_WhenNegativeWhenPositiveOnly_ReturnFalse(int precision, int scale, string value) + { + var validator = new NumberValidator(precision, scale, true); + validator.IsValidNumber(value).Should().BeFalse(); + } + + [TestCase(2, 0, "12", true)] + [TestCase(2, 1, "123", false)] + [TestCase(3, 0, "-12", true)] + [TestCase(3, 1, "-123", false)] + public void IsValid_IntegerBounds_Expected(int precision, int scale, string value, bool expected) + { + var validator = new NumberValidator(precision, scale, false); + validator.IsValidNumber(value).Should().Be(expected); + } + + [TestCase(8, 4, "12.34", true)] + [TestCase(5, 4, "11.234", true)] + [TestCase(7, 3, "1.234", true)] + [TestCase(8, 4, "+123,4567", true)] + [TestCase(4, 2, "+12.34", false)] + [TestCase(6, 2, "1.234", false)] + [TestCase(5, 4, "-12.3", true)] + [TestCase(8, 4, "-1234.567", true)] + [TestCase(12, 4, "-123.4567", true)] + [TestCase(6, 3, "-12,345", true)] + [TestCase(4, 1, "-123,4", false)] + [TestCase(10, 2, "-123.456", false)] + public void IsValid_DecimalBounds_Expected(int precision, int scale, string value, bool expected) + { + var validator = new NumberValidator(precision, scale, false); + validator.IsValidNumber(value).Should().Be(expected); } } \ No newline at end of file From a13a972f33123a06a70ffa6862972e7223ba96b6 Mon Sep 17 00:00:00 2001 From: PavelMartinelli Date: Tue, 28 Oct 2025 17:49:04 +0500 Subject: [PATCH 3/5] fix ObjectComparison --- .../1. ObjectComparison/ObjectComparison.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs index 39d3cec..01d641f 100644 --- a/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs +++ b/Testing/Basic/Homework/1. ObjectComparison/ObjectComparison.cs @@ -7,8 +7,7 @@ public class ObjectComparison { [Test] [Description("Проверка текущего царя")] - [Category("ToRefactor")] - public void CheckCurrentTsar() + public void GetCurrentTsar_WhenComparingWithExpected_ShouldBeEquivalent() { var actualTsar = TsarRegistry.GetCurrentTsar(); @@ -17,11 +16,9 @@ public void CheckCurrentTsar() // Преимущества решение с FluentAssertions: // - Легко расширяем при добавлении новых свойств в Person - // - Автоматически проверяем все свойства, включая вложенные объекты + // - Автоматически проверяем все свойства, включая вложенные объекты до 10 уровней вложенности (по умолчанию) // - При несовпадении конкретного свойства будет выдана информация какое именно свойство не совпало - actualTsar.Should().BeEquivalentTo(expectedTsar, options => options - .Excluding(p => p.Id) - .Excluding(p => p.Parent.Id)); + actualTsar.ShouldBeEquivalentToPerson(expectedTsar); } [Test] @@ -35,6 +32,7 @@ public void CheckCurrentTsar_WithCustomEquality() // Недостатки подхода с CustomEquality: // - Нет детальной информации о том, какое именно свойство не совпало // - При добавлении новых свойств в Person нужно менять метод AreEqual + // - Риск переполнения стека при большом уровне вложенности ClassicAssert.True(AreEqual(actualTsar, expectedTsar)); } private bool AreEqual(Person? actual, Person? expected) @@ -49,3 +47,15 @@ private bool AreEqual(Person? actual, Person? expected) && AreEqual(actual.Parent, expected.Parent); } } + +public static class PersonAssertions +{ + public static void ShouldBeEquivalentToPerson(this Person actual, Person expected) + { + actual.Should().BeEquivalentTo(expected, options => options + .Excluding(field => + field.DeclaringType == typeof(Person) && + field.Name == nameof(Person.Id)) + .AllowingInfiniteRecursion()); + } +} \ No newline at end of file From 758ae1707a6d4ece6e1b7b47b426029a6c0ccb77 Mon Sep 17 00:00:00 2001 From: PavelMartinelli Date: Tue, 28 Oct 2025 17:50:10 +0500 Subject: [PATCH 4/5] fix NumberValidatorTests --- .../NumberValidatorTests.cs | 123 ++++++++---------- 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 30a0939..32ca0a7 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -1,109 +1,92 @@ using FluentAssertions; using NUnit.Framework; -using NUnit.Framework.Legacy; namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [TestCase(-1, 2, true)] - [TestCase(0, 0, false)] - [TestCase(1, -1, false)] - [TestCase(1, 2, false)] - [TestCase(1, 1, false)] - public void Constructor_WhenInvalidArgs_Throws(int precision, int scale, bool onlyPositive) + [TestCase(-1, 2, true, TestName = "precision is negative")] + [TestCase(0, 0, false, TestName = "precision is zero")] + [TestCase(1, -1, false, TestName = "scale is negative")] + [TestCase(1, 2, false, TestName = "scale greater than precision")] + [TestCase(1, 1, false, TestName = "scale equals precision")] + public void Constructor_WhenInvalidArgs_ThrowsArgumentException(int precision, int scale, bool onlyPositive) { Action act = () => new NumberValidator(precision, scale, onlyPositive); act.Should().Throw(); } - [TestCase(1, 0, true)] - [TestCase(2, 1, false)] + [TestCase(1, 0, true, TestName = "valid precision and scale")] + [TestCase(2, 1, false, TestName = "scale less than precision")] public void Constructor_WhenValidArgs_Success(int precision, int scale, bool onlyPositive) { Action act = () => new NumberValidator(precision, scale, onlyPositive); act.Should().NotThrow(); } - [TestCase("0", 17, 2, true)] - [TestCase("0.0", 17, 2, true)] - [TestCase("+1.23", 4, 2, true)] - [TestCase("-1.23", 4, 2, false)] - [TestCase("123.4", 4, 1, true)] - [TestCase("1.2", 4, 1, true)] - [TestCase("12", 2, 0, true)] - [TestCase("11.234", 5, 4, true)] - [TestCase("11,234", 5, 4, true)] - [TestCase("1.234", 5, 3, true)] - public void IsValid_WhenValidNumbers_ReturnTrue(string value, int precision, int scale, bool onlyPositive) + [TestCase("0", 4, 2, true, TestName = "integer zero")] + [TestCase("0.0", 4, 2, true, TestName = "fractional zero")] + [TestCase("+1.23", 4, 2, true, TestName = "positive with sign")] + [TestCase("-1.23", 4, 2, false, TestName = "negative when allowed")] + [TestCase("123.4", 4, 1, true, TestName = "precision equals number length")] + [TestCase("11,234", 5, 4, true, TestName = "comma separator")] + public void IsValidNumber_WhenValidNumbers_ReturnTrue(string value, int precision, int scale, bool onlyPositive) { var validator = new NumberValidator(precision, scale, onlyPositive); validator.IsValidNumber(value).Should().BeTrue(); } - [TestCase("", 1, 0, false)] - [TestCase(null, 1, 0, false)] - [TestCase("a.sd", 3, 2, true)] - [TestCase("00.00", 3, 2, true)] - [TestCase("+0.00", 3, 2, true)] - [TestCase("0.000", 17, 2, true)] - [TestCase("-1.23", 3, 2, true)] - [TestCase("-0.00", 3, 2, true)] - [TestCase("123", 2, 0, true)] - [TestCase("-123", 3, 0, false)] - [TestCase("+12.34", 4, 2, true)] - [TestCase("1.234", 6, 2, true)] - [TestCase("-123.4", 4, 1, false)] - [TestCase("-123.456", 10, 2, false)] - [TestCase("123.", 4, 2, true)] - [TestCase("1.23a4", 10, 7, true)] - [TestCase("t", 4, 3, true)] - [TestCase("b.0", 4, 3, true)] - [TestCase("1.2b34", 10, 7, true)] - [TestCase("12.", 10, 7, true)] - [TestCase("-123", 5, 2, true)] - [TestCase("-1.23", 5, 4, true)] - public void IsValid_WhenInvalidNumbers_ReturnFalse(string value, int precision, int scale, bool onlyPositive) + [TestCase("", 1, 0, false, TestName = "empty string")] + [TestCase(null, 1, 0, false, TestName = "null value")] + [TestCase("01.23", 3, 2, true, TestName = "leading zeros")] + [TestCase("+0.00", 3, 2, true, TestName = "sign with zero")] + [TestCase("-1.23", 3, 2, true, TestName = "negative when positive only")] + [TestCase("1.2a", 3, 2, true, TestName = "invalid character in fraction")] + [TestCase("-123", 4, 0, true, TestName = "negative integer when positive only")] + [TestCase("-1.23", 4, 2, true, TestName = "negative fractional when positive only")] + [TestCase("123.", 3, 0, true, TestName = "missing fractional part")] + [TestCase(".123", 4, 3, true, TestName = "missing integer part")] + [TestCase("++1.23", 5, 2, true, TestName = "multiple signs")] + [TestCase("1.2.3", 3, 2, true, TestName = "multiple separators")] + [TestCase("1/23", 3, 2, true, TestName = "invalid separator")] + public void IsValidNumber_WhenInvalidNumbers_ReturnFalse(string value, int precision, int scale, bool onlyPositive) { var validator = new NumberValidator(precision, scale, onlyPositive); validator.IsValidNumber(value).Should().BeFalse(); } - [TestCase(5, 2, "-123")] - [TestCase(5, 4, "-1.23")] - [TestCase(3, 2, "-1.23")] - public void IsValid_WhenNegativeWhenPositiveOnly_ReturnFalse(int precision, int scale, string value) + [TestCase("12", 2, 0, false, TestName = "integer fits precision")] + [TestCase("-1", 2, 0, false, TestName = "negative integer fits precision")] + public void IsValidNumber_WhenIntegerBoundsValid_ReturnsTrue(string value, int precision, int scale, bool onlyPositive) { - var validator = new NumberValidator(precision, scale, true); + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(value).Should().BeTrue(); + } + + [TestCase("123", 2, 1, false, TestName = "integer exceeds precision")] + [TestCase("-12", 2, 1, false, TestName = "negative integer exceeds precision")] + public void IsValidNumber_WhenIntegerBoundsInvalid_ReturnsFalse(string value, int precision, int scale, bool onlyPositive) + { + var validator = new NumberValidator(precision, scale, onlyPositive); validator.IsValidNumber(value).Should().BeFalse(); } - [TestCase(2, 0, "12", true)] - [TestCase(2, 1, "123", false)] - [TestCase(3, 0, "-12", true)] - [TestCase(3, 1, "-123", false)] - public void IsValid_IntegerBounds_Expected(int precision, int scale, string value, bool expected) + [TestCase("12.34", 8, 4, false, TestName = "fraction fits scale")] + [TestCase("11.234", 5, 4, false, TestName = "fraction fits precision and scale")] + [TestCase("-12.3", 5, 4, false, TestName = "negative fraction fits bounds")] + public void IsValidNumber_WhenFractionalBoundsValid_ReturnsTrue(string value, int precision, int scale, bool onlyPositive) { - var validator = new NumberValidator(precision, scale, false); - validator.IsValidNumber(value).Should().Be(expected); + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(value).Should().BeTrue(); } - [TestCase(8, 4, "12.34", true)] - [TestCase(5, 4, "11.234", true)] - [TestCase(7, 3, "1.234", true)] - [TestCase(8, 4, "+123,4567", true)] - [TestCase(4, 2, "+12.34", false)] - [TestCase(6, 2, "1.234", false)] - [TestCase(5, 4, "-12.3", true)] - [TestCase(8, 4, "-1234.567", true)] - [TestCase(12, 4, "-123.4567", true)] - [TestCase(6, 3, "-12,345", true)] - [TestCase(4, 1, "-123,4", false)] - [TestCase(10, 2, "-123.456", false)] - public void IsValid_DecimalBounds_Expected(int precision, int scale, string value, bool expected) + [TestCase("+12.34", 4, 2, false, TestName = "signed number exceeds precision")] + [TestCase("1.234", 6, 2, false, TestName = "fraction exceeds scale")] + [TestCase("-123,4", 4, 1, false, TestName = "negative number exceeds precision")] + public void IsValidNumber_WhenFractionalBoundsInvalid_ReturnsFalse(string value, int precision, int scale, bool onlyPositive) { - var validator = new NumberValidator(precision, scale, false); - validator.IsValidNumber(value).Should().Be(expected); + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(value).Should().BeFalse(); } } \ No newline at end of file From c4d47b940f3f37fa306a89acc2efb517a61d94ca Mon Sep 17 00:00:00 2001 From: PavelMartinelli Date: Wed, 29 Oct 2025 13:07:08 +0500 Subject: [PATCH 5/5] fix2 NumberValidatorTests --- .../NumberValidatorTests.cs | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs index 32ca0a7..88ff3f5 100644 --- a/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs +++ b/Testing/Basic/Homework/2. NumberValidator/NumberValidatorTests.cs @@ -6,11 +6,25 @@ namespace HomeExercise.Tasks.NumberValidator; [TestFixture] public class NumberValidatorTests { - [TestCase(-1, 2, true, TestName = "precision is negative")] - [TestCase(0, 0, false, TestName = "precision is zero")] - [TestCase(1, -1, false, TestName = "scale is negative")] - [TestCase(1, 2, false, TestName = "scale greater than precision")] - [TestCase(1, 1, false, TestName = "scale equals precision")] + public static IEnumerable InvalidConstructorArgsTestCases() + { + foreach (var onlyPositive in new[] { true, false }) + { + yield return new TestCaseData(0, 1, onlyPositive) + .SetName($"precision is zero onlyPositive={onlyPositive}"); + yield return new TestCaseData(-1, 2, onlyPositive) + .SetName($"precision is negative onlyPositive={onlyPositive}"); + yield return new TestCaseData(1, -1, onlyPositive) + .SetName($"scale is negative onlyPositive={onlyPositive}"); + yield return new TestCaseData(1, 2, onlyPositive) + .SetName($"scale greater than precision onlyPositive={onlyPositive}"); + yield return new TestCaseData(1, 1, onlyPositive) + .SetName($"scale equals precision onlyPositive={onlyPositive}"); + } + } + + [Test] + [TestCaseSource(nameof(InvalidConstructorArgsTestCases))] public void Constructor_WhenInvalidArgs_ThrowsArgumentException(int precision, int scale, bool onlyPositive) { Action act = () => new NumberValidator(precision, scale, onlyPositive); @@ -27,6 +41,8 @@ public void Constructor_WhenValidArgs_Success(int precision, int scale, bool onl [TestCase("0", 4, 2, true, TestName = "integer zero")] [TestCase("0.0", 4, 2, true, TestName = "fractional zero")] + [TestCase("+0.0", 3, 2, true, TestName = "sign with zero")] + [TestCase("01.23", 4, 2, true, TestName = "leading zeros")] [TestCase("+1.23", 4, 2, true, TestName = "positive with sign")] [TestCase("-1.23", 4, 2, false, TestName = "negative when allowed")] [TestCase("123.4", 4, 1, true, TestName = "precision equals number length")] @@ -38,13 +54,17 @@ public void IsValidNumber_WhenValidNumbers_ReturnTrue(string value, int precisio } [TestCase("", 1, 0, false, TestName = "empty string")] + [TestCase(" 123", 4, 0, true, TestName = "leading space before number")] + [TestCase("123 ", 4, 0, true, TestName = "trailing space after number")] + [TestCase(" 123 ", 5, 0, true, TestName = "spaces both sides")] + [TestCase("1.2\n3", 4, 2, true, TestName = "special character inside")] + [TestCase("\n1.23", 4, 2, true, TestName = "special character before")] [TestCase(null, 1, 0, false, TestName = "null value")] - [TestCase("01.23", 3, 2, true, TestName = "leading zeros")] - [TestCase("+0.00", 3, 2, true, TestName = "sign with zero")] - [TestCase("-1.23", 3, 2, true, TestName = "negative when positive only")] - [TestCase("1.2a", 3, 2, true, TestName = "invalid character in fraction")] + [TestCase("abc", 3, 0, true, TestName = "non-digit string")] + [TestCase("1a.2", 3, 2, true, TestName = "invalid character in integer part")] + [TestCase("1.2a", 3, 2, true, TestName = "invalid character in fraction part")] + [TestCase("-1.23", 4, 2, true, TestName = "negative fraction when positive only")] [TestCase("-123", 4, 0, true, TestName = "negative integer when positive only")] - [TestCase("-1.23", 4, 2, true, TestName = "negative fractional when positive only")] [TestCase("123.", 3, 0, true, TestName = "missing fractional part")] [TestCase(".123", 4, 3, true, TestName = "missing integer part")] [TestCase("++1.23", 5, 2, true, TestName = "multiple signs")] @@ -64,8 +84,8 @@ public void IsValidNumber_WhenIntegerBoundsValid_ReturnsTrue(string value, int p validator.IsValidNumber(value).Should().BeTrue(); } - [TestCase("123", 2, 1, false, TestName = "integer exceeds precision")] - [TestCase("-12", 2, 1, false, TestName = "negative integer exceeds precision")] + [TestCase("123", 2, 0, false, TestName = "integer exceeds precision")] + [TestCase("-12", 2, 0, false, TestName = "negative integer exceeds precision")] public void IsValidNumber_WhenIntegerBoundsInvalid_ReturnsFalse(string value, int precision, int scale, bool onlyPositive) { var validator = new NumberValidator(precision, scale, onlyPositive);