diff --git a/cs/Challenge/Challenge.csproj b/cs/Challenge/Challenge.csproj index 0f41e066..a13acb1a 100644 --- a/cs/Challenge/Challenge.csproj +++ b/cs/Challenge/Challenge.csproj @@ -13,6 +13,7 @@ + diff --git a/cs/HomeExercises/HomeExercises.csproj b/cs/HomeExercises/HomeExercises.csproj index ede81aec..26a773ec 100644 --- a/cs/HomeExercises/HomeExercises.csproj +++ b/cs/HomeExercises/HomeExercises.csproj @@ -14,7 +14,8 @@ - + + \ No newline at end of file diff --git a/cs/HomeExercises/NumberValidator.cs b/cs/HomeExercises/NumberValidator.cs new file mode 100644 index 00000000..b357db83 --- /dev/null +++ b/cs/HomeExercises/NumberValidator.cs @@ -0,0 +1,45 @@ +using System; +using System.Text.RegularExpressions; + +namespace HomeExercises +{ + public class NumberValidator + { + private readonly Regex numberRegex; + private readonly bool onlyPositive; + private readonly int precision; + private readonly int scale; + + public NumberValidator(int precision, int scale = 0, bool onlyPositive = false) + { + this.precision = precision; + this.scale = scale; + this.onlyPositive = onlyPositive; + if (precision <= 0) + throw new ArgumentException("precision must be a positive number"); + if (scale < 0 || scale >= precision) + throw new ArgumentException("precision must be a non-negative number less or equal than precision"); + numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase); + } + + public bool IsValidNumber(string value) + { + if (string.IsNullOrEmpty(value)) + return false; + + var match = numberRegex.Match(value); + if (!match.Success) + return false; + + var intPart = match.Groups[1].Value.Length + match.Groups[2].Value.Length; + var fracPart = match.Groups[4].Value.Length; + + if (intPart + fracPart > precision || fracPart > scale) + return false; + + if (onlyPositive && match.Groups[1].Value == "-") + return false; + return true; + } + } +} \ No newline at end of file diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs deleted file mode 100644 index a2878113..00000000 --- a/cs/HomeExercises/NumberValidatorTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using FluentAssertions; -using NUnit.Framework; - -namespace HomeExercises -{ - public class NumberValidatorTests - { - [Test] - public void Test() - { - 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)); - - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("00.00")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-0.00")); - Assert.IsTrue(new NumberValidator(17, 2, true).IsValidNumber("0.0")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+0.00")); - Assert.IsTrue(new NumberValidator(4, 2, true).IsValidNumber("+1.23")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("+1.23")); - Assert.IsFalse(new NumberValidator(17, 2, true).IsValidNumber("0.000")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("-1.23")); - Assert.IsFalse(new NumberValidator(3, 2, true).IsValidNumber("a.sd")); - } - } - - public class NumberValidator - { - private readonly Regex numberRegex; - private readonly bool onlyPositive; - private readonly int precision; - private readonly int scale; - - public NumberValidator(int precision, int scale = 0, bool onlyPositive = false) - { - this.precision = precision; - this.scale = scale; - this.onlyPositive = onlyPositive; - if (precision <= 0) - throw new ArgumentException("precision must be a positive number"); - if (scale < 0 || scale >= precision) - throw new ArgumentException("precision must be a non-negative number less or equal than precision"); - numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase); - } - - public bool IsValidNumber(string value) - { - // Проверяем соответствие входного значения формату N(m,k), в соответствии с правилом, - // описанным в Формате описи документов, направляемых в налоговый орган в электронном виде по телекоммуникационным каналам связи: - // Формат числового значения указывается в виде N(m.к), где m – максимальное количество знаков в числе, включая знак (для отрицательного числа), - // целую и дробную часть числа без разделяющей десятичной точки, k – максимальное число знаков дробной части числа. - // Если число знаков дробной части числа равно 0 (т.е. число целое), то формат числового значения имеет вид N(m). - - if (string.IsNullOrEmpty(value)) - return false; - - var match = numberRegex.Match(value); - if (!match.Success) - return false; - - // Знак и целая часть - var intPart = match.Groups[1].Value.Length + match.Groups[2].Value.Length; - // Дробная часть - var fracPart = match.Groups[4].Value.Length; - - if (intPart + fracPart > precision || fracPart > scale) - return false; - - if (onlyPositive && match.Groups[1].Value == "-") - return false; - return true; - } - } -} \ No newline at end of file diff --git a/cs/HomeExercises/ObjectComparison.cs b/cs/HomeExercises/ObjectComparison.cs index 44d9aed4..804fee89 100644 --- a/cs/HomeExercises/ObjectComparison.cs +++ b/cs/HomeExercises/ObjectComparison.cs @@ -1,76 +1,14 @@ -using FluentAssertions; -using NUnit.Framework; - -namespace HomeExercises +namespace HomeExercises { public class ObjectComparison - { - [Test] - [Description("Проверка текущего царя")] - [Category("ToRefactor")] - public void CheckCurrentTsar() - { - var actualTsar = TsarRegistry.GetCurrentTsar(); - - var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); - - // Перепишите код на использование Fluent Assertions. - Assert.AreEqual(actualTsar.Name, expectedTsar.Name); - Assert.AreEqual(actualTsar.Age, expectedTsar.Age); - Assert.AreEqual(actualTsar.Height, expectedTsar.Height); - Assert.AreEqual(actualTsar.Weight, expectedTsar.Weight); - - Assert.AreEqual(expectedTsar.Parent!.Name, actualTsar.Parent!.Name); - Assert.AreEqual(expectedTsar.Parent.Age, actualTsar.Parent.Age); - Assert.AreEqual(expectedTsar.Parent.Height, actualTsar.Parent.Height); - Assert.AreEqual(expectedTsar.Parent.Parent, actualTsar.Parent.Parent); - } - - [Test] - [Description("Альтернативное решение. Какие у него недостатки?")] - public void CheckCurrentTsar_WithCustomEquality() - { - var actualTsar = TsarRegistry.GetCurrentTsar(); - var expectedTsar = new Person("Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); - - // Какие недостатки у такого подхода? - Assert.True(AreEqual(actualTsar, expectedTsar)); - } - - private bool AreEqual(Person? actual, Person? expected) - { - if (actual == expected) return true; - if (actual == null || expected == null) return false; - return - actual.Name == expected.Name - && actual.Age == expected.Age - && actual.Height == expected.Height - && actual.Weight == expected.Weight - && AreEqual(actual.Parent, expected.Parent); - } - } - - public class TsarRegistry - { - public static Person GetCurrentTsar() - { - return new Person( - "Ivan IV The Terrible", 54, 170, 70, - new Person("Vasili III of Russia", 28, 170, 60, null)); - } - } - - public class Person { public static int IdCounter = 0; public int Age, Height, Weight; public string Name; - public Person? Parent; + public ObjectComparison? Parent; public int Id; - public Person(string name, int age, int height, int weight, Person? parent) + public ObjectComparison(string name, int age, int height, int weight, ObjectComparison? parent) { Id = IdCounter++; Name = name; diff --git a/cs/HomeExercises/tests/NumberValidator_Should.cs b/cs/HomeExercises/tests/NumberValidator_Should.cs new file mode 100644 index 00000000..2a333492 --- /dev/null +++ b/cs/HomeExercises/tests/NumberValidator_Should.cs @@ -0,0 +1,56 @@ +using FluentAssertions; +using NUnit.Framework; +using System; + +namespace HomeExercises.tests +{ + public class NumberValidator_Should + { + [TestCase(-1, 2, false, TestName = "NegativePrecision")] + [TestCase(0, 0, false, TestName = "PrecisionIsZero")] + [TestCase(3, -1, false, TestName = "NegativeScale")] + [TestCase(1, 2, false, TestName = "ScaleIsGreaterThanPrecision")] + [TestCase(1, 1, true, TestName = "PrecisionEqualsScale")] + public void Creation_ShouldThrowArgumentException(int precision, int scale, bool onlyPositive) + { + Action creation = () => new NumberValidator(precision, scale, onlyPositive); + creation.Should().Throw(); + } + [Test] + public void Creation_ShouldNotThrow() + { + Action creation = () => new NumberValidator(1, 0); + creation + .Should() + .NotThrow(); + + } + + [TestCase(3, 2, false, "-+0.0", TestName = "TwoSigns")] + [TestCase(3, 2, false, " -0.0", TestName = "SpaceFirstDigitInNumber")] + [TestCase(3, 2, false, "0,", TestName ="Aren'tDigitsAfterCommas")] + [TestCase(3, 2, false, "0.0.0", TestName = "ThreeDigitsInNumberByTwoDots")] + [TestCase(3, 2, false, "0,0,0", TestName = "ThreeDigitsInNumberByTwoCommas")] + [TestCase(3, 2, false, "00.00", TestName = "NumberPrecisionGreaterThanValidatorPrecision")] + [TestCase(3, 2, false, null, TestName = "NumberNull")] + [TestCase(3, 2, false, "", TestName = "NumberEmpty")] + [TestCase(3, 2, false, "+1.23", TestName = "NumberPrecisionGreaterThanValidatorPrecision")] + [TestCase(3, 2, false, "-1.23", TestName = "NumberNegativeInNumberOnlyPositive")] + [TestCase(17, 2, true, "0.000", TestName = "NumberScaleGreaterThanValidatorScale")] + [TestCase(17, 2, true, "a.sd", TestName = "IncorrectNumberFormatBecauseLettersArePresent")] + public void IsValidNumber_ShouldFalse_When(int precision, int scale, bool onlyPositive, string number) + { + var validator = new NumberValidator(precision, scale, onlyPositive); + validator.IsValidNumber(number).Should().BeFalse(); + } + + [TestCase(17, 2, false, "0.0", TestName = "NumberWithFractionalPart")] + [TestCase(17, 2, false, "0", TestName = "OnlyInteger")] + [TestCase(4, 2, true, "+1.23", TestName = "NumberWithSign")] + public void IsValidNumber_ShouldTrue_When(int precision, int scale, bool onlyPositive, string number) + { + var validator = new NumberValidator(precision, scale); + validator.IsValidNumber(number).Should().BeTrue(); + } + } +} diff --git a/cs/HomeExercises/tests/ObjectComparison_Should.cs b/cs/HomeExercises/tests/ObjectComparison_Should.cs new file mode 100644 index 00000000..89509860 --- /dev/null +++ b/cs/HomeExercises/tests/ObjectComparison_Should.cs @@ -0,0 +1,61 @@ +using FluentAssertions; +using NUnit.Framework; + +namespace HomeExercises.tests +{ + public class ObjectComparison_Should + { + [Test] + [Description("Проверка текущего царя")] + [Category("ToRefactor")] + public void CheckValuesOfTheCurrentTsar() + { + var actualTsar = TsarRegistry.GetCurrentTsar(); + + var expectedTsar = new ObjectComparison("Ivan IV The Terrible", 54, 170, 70, + new ObjectComparison("Vasili III of Russia", 28, 170, 60, null)); + + actualTsar.Should().BeEquivalentTo(expectedTsar, options => options + .Excluding(tsar => + tsar.SelectedMemberInfo.Name == nameof(ObjectComparison.Id) + && tsar.SelectedMemberInfo.DeclaringType == typeof(ObjectComparison))); + } + + [Test] + [Description("Альтернативное решение. Какие у него недостатки?")] + public void CheckCurrentTsar_WithCustomEquality() + { + var actualTsar = TsarRegistry.GetCurrentTsar(); + var expectedTsar = new ObjectComparison("Ivan IV The Terrible", 54, 170, 70, + new ObjectComparison("Vasili III of Russia", 28, 170, 60, null)); + + //Какие недостатки у такого подхода? + //Нужно будет переписывать AreEqual в случае изменения полей ObjectComparison + //Возможна ошибка при написании метода + //Если тест упадет, сообщение об ошибке будет малоинформативным + Assert.True(AreEqual(actualTsar, expectedTsar)); + } + + private bool AreEqual(ObjectComparison? actual, ObjectComparison? expected) + { + if (actual == expected) return true; + if (actual == null || expected == null) return false; + return + actual.Name == expected.Name + && actual.Age == expected.Age + && actual.Height == expected.Height + && actual.Weight == expected.Weight + && AreEqual(actual.Parent, expected.Parent); + } + } + + public class TsarRegistry + { + public static ObjectComparison GetCurrentTsar() + { + return new ObjectComparison( + "Ivan IV The Terrible", 54, 170, 70, + new ObjectComparison("Vasili III of Russia", 28, 170, 60, null)); + } + } +} \ No newline at end of file diff --git a/cs/Samples/Samples.csproj b/cs/Samples/Samples.csproj index c2c8798a..dc0b5716 100644 --- a/cs/Samples/Samples.csproj +++ b/cs/Samples/Samples.csproj @@ -12,7 +12,6 @@ -