diff --git a/cs/HomeExercises/HomeExercises.csproj b/cs/HomeExercises/HomeExercises.csproj
index ede81aec..6103ad76 100644
--- a/cs/HomeExercises/HomeExercises.csproj
+++ b/cs/HomeExercises/HomeExercises.csproj
@@ -1,7 +1,7 @@
- netcoreapp3.1
+ net7.0
false
HomeExercises
ObjectComparison
@@ -10,11 +10,11 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/cs/HomeExercises/NumberValidatorTests.cs b/cs/HomeExercises/NumberValidatorTests.cs
index a2878113..12be8717 100644
--- a/cs/HomeExercises/NumberValidatorTests.cs
+++ b/cs/HomeExercises/NumberValidatorTests.cs
@@ -5,76 +5,137 @@
namespace HomeExercises
{
+ [TestFixture]
public class NumberValidatorTests
{
- [Test]
- public void Test()
+ [TestCase(-1, 2, true, TestName = "Negative Precision")]
+ [TestCase(2, -1, true, TestName = "Negative Scale")]
+ [TestCase(2, 3, true, TestName = "Precision < Scale")]
+ [TestCase(3, 3, true, TestName = "Precision = Scale")]
+ [TestCase(0, null, true, TestName = "Precision = Zero")]
+ [TestCase(null, 3, true, TestName = "Precision is null")]
+ public void NumberValidator_CreateInvalidNumber_ShouldBeTrowException(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));
+ Action createNumberValidator = () => new NumberValidator(precision, scale, onlyPositive);
+ createNumberValidator.Should().Throw();
+ }
- 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"));
+ [TestCase(3, 2, null, TestName = "OnlyPositive is null")]
+ [TestCase(3, null, true, TestName = "Scale is null")]
+ [TestCase(3, 2, true, TestName = "Scale < Precision")]
+ [TestCase(3, 0, true, TestName = "Scale == 0")]
+ public void NumberValidator_CreateCorrectNumber_ShouldBeNotTrowException(int precision, int scale,
+ bool onlyPositive)
+ {
+ Action createNumberValidator = () => new NumberValidator(precision, scale, onlyPositive);
+ createNumberValidator.Should().NotThrow();
}
- }
- public class NumberValidator
- {
- private readonly Regex numberRegex;
- private readonly bool onlyPositive;
- private readonly int precision;
- private readonly int scale;
+ [TestCase(2, 0, " ", TestName = "number is someWhiteSpaces")]
+ [TestCase(2, 0, "string", TestName = "number is word")]
+ [TestCase(2, 0, "", TestName = "Number is Empty")]
+ [TestCase(2, 0, null, TestName = "Number Is Null")]
+ [TestCase(3, 0, "@20", TestName = "invalid sign. It isn't '-' or '+'")]
+ [TestCase(4, 0, "-+20", TestName = "more than one sign")]
+ [TestCase(4, 2, "20?00", TestName = "invalid separator. It isn't '.' or ','")]
+ [TestCase(4, 2, "20......00", TestName = "more than one separators in a row")]
+ [TestCase(2, 0, "20.", TestName = "Number with separator, but Empty fractional part")]
+ [TestCase(1, 0, "+", TestName = "number with sign but without fractional and integer parts")]
+ [TestCase(4, 1, "2.0.0.0", TestName = "more than one separator")]
+ [TestCase(4, 1, "D75", TestName = "number in is not the correct number system")]
+ [TestCase(4, 1, " 200 ", TestName = "number surrounded by spaces")]
+ [TestCase(4, 1, "\n200\n", TestName = "number surrounded by singles LineFeed")]
+ [TestCase(3, 2, "+.20", TestName = "number without integer part")]
+ [TestCase(8, 6, "20.string", TestName = "fractional part is word")]
+ public void IsValidNumber_IfInvalidTypeValue_ShouldBeFalse(int precision, int scale, string number,
+ bool onlyPositive = true)
+ {
+ AssertIsValidNumber(precision, scale, onlyPositive, number, false);
+ }
- public NumberValidator(int precision, int scale = 0, bool onlyPositive = false)
+ [TestCase(4, 2, true, "+20.00", TestName = "precision == length value, but number with '+'")]
+ [TestCase(4, 2, false, "-20.00", TestName = "precision == length value, but number with '-'")]
+ [TestCase(5, 2, true, "-20.00", TestName = "negative number but onlyPositive flag == true")]
+ [TestCase(3, 1, true, "20.00", TestName = "precision < length number")]
+ [TestCase(4, 0, true, "20.00", TestName = "scale < length fractional part")]
+ public void IsValidNumber_IfIncorrectArgs_ShouldBeFalse(int precision, int scale, bool onlyPositive,
+ string number)
{
- 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);
+ AssertIsValidNumber(precision, scale, onlyPositive, number, false);
}
- public bool IsValidNumber(string value)
+ [TestCase(3, 0, "+20", TestName = "use '+' before number")]
+ [TestCase(3, 1, "20.0", TestName = "used '.' as a sign")]
+ [TestCase(3, 1, "20,0", TestName = "used ',' as a sign")]
+ [TestCase(2, 0, "20", TestName = "number without fractional part")]
+ [TestCase(3, 0, "-20", TestName = "negative number")]
+ public void IsValidNumber_IfCorrectValue_ShouldBeTrue(int precision, int scale, string number,
+ bool onlyPositive = false)
{
- // Проверяем соответствие входного значения формату N(m,k), в соответствии с правилом,
- // описанным в Формате описи документов, направляемых в налоговый орган в электронном виде по телекоммуникационным каналам связи:
- // Формат числового значения указывается в виде N(m.к), где m – максимальное количество знаков в числе, включая знак (для отрицательного числа),
- // целую и дробную часть числа без разделяющей десятичной точки, k – максимальное число знаков дробной части числа.
- // Если число знаков дробной части числа равно 0 (т.е. число целое), то формат числового значения имеет вид N(m).
+ AssertIsValidNumber(precision, scale, onlyPositive, number, true);
+ }
- if (string.IsNullOrEmpty(value))
- return false;
+ [TestCase(4, 2, true, "20.00", TestName = "precision of the number without sign == value Length")]
+ [TestCase(5, 2, null, "-20.00", TestName = "negative number with onlyPositive == null")]
+ [TestCase(21, 1, true, "+20.0", TestName = "precision of the number > value length + sign")]
+ [TestCase(3, 2, true, "20.0", TestName = "scale > fractional part")]
+ [TestCase(3, 1, true, "20.0", TestName = "scale == fractional part")]
+ [TestCase(4, 1, false, "+20.0", TestName = "use '+' without onlyPositive flag")]
+ [TestCase(2, null, true, "20", TestName = "number with Empty Scale")]
+ [TestCase(3, 0, false, "-20", TestName = "precision of the number == value Length + sign")]
+ [TestCase(2, 1, true, "20", TestName = "number without fractional part but scale > 0")]
+ public void IsValidNumber_IfNumberWithCorrectArgs_ShouldBeTrue(int precision, int scale, bool onlyPositive,
+ string number)
+ {
+ AssertIsValidNumber(precision, scale, onlyPositive, number, true);
+ }
- var match = numberRegex.Match(value);
- if (!match.Success)
- return false;
+ private static void AssertIsValidNumber(int precision, int scale, bool onlyPositive, string number,
+ bool expected)
+ {
+ var numberValidator = new NumberValidator(precision, scale, onlyPositive);
+ numberValidator.IsValidNumber(number).Should().Be(expected);
+ }
+ }
+}
- // Знак и целая часть
- var intPart = match.Groups[1].Value.Length + match.Groups[2].Value.Length;
- // Дробная часть
- var fracPart = match.Groups[4].Value.Length;
+public class NumberValidator
+{
+ private readonly Regex numberRegex;
+ private readonly bool onlyPositive;
+ private readonly int precision;
+ private readonly int scale;
- if (intPart + fracPart > precision || fracPart > scale)
- return false;
+ 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("scale must be a non-negative number less or equal than precision");
+ numberRegex = new Regex(@"^([+-]?)(\d+)([.,](\d+))?$", RegexOptions.IgnoreCase);
+ }
- if (onlyPositive && match.Groups[1].Value == "-")
- return false;
- return true;
- }
+ 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/ObjectComparison.cs b/cs/HomeExercises/ObjectComparison.cs
index 44d9aed4..1352b668 100644
--- a/cs/HomeExercises/ObjectComparison.cs
+++ b/cs/HomeExercises/ObjectComparison.cs
@@ -5,41 +5,45 @@ namespace HomeExercises
{
public class ObjectComparison
{
+ private const int MaxTreeHeight = 75;
+
+ [SetUp]
+ public void SetUp()
+ {
+ AssertionOptions.FormattingOptions.MaxDepth = MaxTreeHeight;
+ }
+
[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);
+ actualTsar
+ .Should()
+ .BeEquivalentTo(expectedTsar, options =>
+ options.Excluding(tsar =>
+ tsar.DeclaringType == typeof(Person) && tsar.Name.Equals(nameof(Person.Id))));
}
[Test]
[Description("Альтернативное решение. Какие у него недостатки?")]
+ // размыта зона ответственности этого теста(если тест упадет из-за неверного поля,то не понятно из-за какого конкретно)
+ //Очень негибкий тест:
+ // Любое изменение существующих полей класса Person приводит к ошибке
+ // При любом добавлении новых полей нужно снова изменять этот тест
+ //
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)
+ private static bool AreEqual(Person? actual, Person? expected)
{
if (actual == expected) return true;
if (actual == null || expected == null) return false;
@@ -52,7 +56,7 @@ private bool AreEqual(Person? actual, Person? expected)
}
}
- public class TsarRegistry
+ public abstract class TsarRegistry
{
public static Person GetCurrentTsar()
{
@@ -64,15 +68,17 @@ public static Person GetCurrentTsar()
public class Person
{
- public static int IdCounter = 0;
- public int Age, Height, Weight;
- public string Name;
- public Person? Parent;
+ private static int _idCounter;
+ public readonly int Age;
+ public readonly int Height;
+ public readonly int Weight;
+ public readonly string Name;
+ public readonly Person? Parent;
public int Id;
public Person(string name, int age, int height, int weight, Person? parent)
{
- Id = IdCounter++;
+ Id = _idCounter++;
Name = name;
Age = age;
Height = height;