-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNumberValidatorTests.cs
81 lines (70 loc) · 3.83 KB
/
NumberValidatorTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
using System.Text.RegularExpressions;
using FluentAssertions;
using NUnit.Framework;
namespace HomeExercises
{
public class NumberValidatorTests
{
// NUnit 3.0+ does not have ExpectedException in TestCase
[TestCase(-1, 2, true)]
[TestCase(-1, 2, false)]
public static void AssertThrows(int precision, int scale, bool onlyPositive)
=> Assert.Throws<ArgumentException>(() => new NumberValidator(precision, scale, onlyPositive));
[TestCase(1, 0, true)]
public static void AssertDoesNotThrow(int precision, int scale, bool onlyPositive)
=> Assert.DoesNotThrow(() => new NumberValidator(precision, scale, onlyPositive));
[TestCase(3, 2, true, "-0.00", ExpectedResult = false)]
[TestCase(3, 2, true, "+0.00", ExpectedResult = false)]
[TestCase(3, 2, true, "00.00", ExpectedResult = false)]
[TestCase(3, 2, true, "+1.23", ExpectedResult = false)]
[TestCase(3, 2, true, "-1.23", ExpectedResult = false)]
[TestCase(3, 2, true, "a.sd", ExpectedResult = false)]
[TestCase(4, 2, true, "+1.23", ExpectedResult = true)]
[TestCase(17, 2, true, "0", ExpectedResult = true)]
[TestCase(17, 2, true, "0.0", ExpectedResult = true)]
[TestCase(17, 2, true, "0.000", ExpectedResult = false)]
public static bool ValidateNumber(int precision, int scale, bool onlyPositive, string value)
=> new NumberValidator(precision, scale, onlyPositive).IsValidNumber(value);
}
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;
}
}
}