< Summary

Line coverage
93%
Covered lines: 45
Uncovered lines: 3
Coverable lines: 48
Total lines: 592
Line coverage: 93.7%
Branch coverage
73%
Covered branches: 47
Total branches: 64
Branch coverage: 73.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: HexColor()100%11100%
File 1: ColumnId()100%11100%
File 2: .ctor(...)100%11100%
File 2: Validate(...)71.66%616093.18%
File 2: GetString(...)100%44100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/obj/Release/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs

File '/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/obj/Release/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs' does not exist (any more).

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Orders/Grid/OrdersGridComputedColumns.cs

#LineLine coverage
 1using System.Text.Json;
 2using System.Text.RegularExpressions;
 3
 4namespace OzonOrdersWeb.WebServices.Orders.Grid;
 5
 6/// <summary>
 7/// Проверка JSON настройки <c>computedColumns</c> перед сохранением: лимиты, формулы (та же грамматика, что на клиенте)
 8/// ссылки только на поля, разрешённые пользователю, правила цвета — как формулы над <c>value</c>.
 9/// </summary>
 10public static partial class OrdersGridComputedColumns
 11{
 12    public const int MaxColumns = 30;
 13    public const int MaxNameLength = 60;
 14    public const int MaxColorRules = 5;
 15
 316    public sealed class ValidationException(string message) : Exception(message);
 17
 18    [GeneratedRegex("^#[0-9a-fA-F]{6}$")]
 19    private static partial Regex HexColor();
 20
 21    [GeneratedRegex("^c_[a-z0-9]{3,16}$")]
 22    private static partial Regex ColumnId();
 23
 24    /// <summary>Бросает <see cref="ValidationException"/> с человекочитаемым сообщением.</summary>
 25    public static void Validate(string? json, IEnumerable<string> allowedColumns)
 26    {
 427        if (string.IsNullOrWhiteSpace(json)) return;
 28
 29        JsonDocument doc;
 830        try { doc = JsonDocument.Parse(json); }
 031        catch (JsonException) { throw new ValidationException("Некорректный JSON вычисляемых столбцов."); }
 32
 433        using (doc)
 34        {
 435            if (doc.RootElement.ValueKind != JsonValueKind.Array) throw new ValidationException("Ожидается массив столбц
 436            var count = doc.RootElement.GetArrayLength();
 437            if (count > MaxColumns) throw new ValidationException($"Не больше {MaxColumns} вычисляемых столбцов.");
 38
 39            // Поля доступны и по ключу, и по русскому названию (в формуле — [Название]).
 440            var fields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 6841            foreach (var f in OrdersGridFormulaFields.ForAllowed(allowedColumns))
 42            {
 3043                fields[f.Key] = f.Type;
 3044                fields[f.Label] = f.Type;
 45            }
 446            var ids = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
 47
 1348            foreach (var item in doc.RootElement.EnumerateArray())
 49            {
 450                if (item.ValueKind != JsonValueKind.Object) throw new ValidationException("Столбец должен быть объектом.
 451                var id = GetString(item, "id");
 552                if (id is null || !ColumnId().IsMatch(id)) throw new ValidationException("Некорректный идентификатор сто
 353                if (!ids.Add(id)) throw new ValidationException("Повторяющийся идентификатор столбца.");
 54
 355                var name = GetString(item, "name")?.Trim();
 356                if (string.IsNullOrEmpty(name)) throw new ValidationException("У столбца нет названия.");
 357                if (name.Length > MaxNameLength) throw new ValidationException($"Название «{name[..20]}…» длиннее {MaxNa
 58
 359                var formula = GetString(item, "formula");
 60                try
 61                {
 362                    OrdersGridFormula.Validate(formula ?? string.Empty, fields);
 263                }
 164                catch (OrdersGridFormula.FormulaException ex)
 65                {
 166                    throw new ValidationException($"Столбец «{name}»: {ex.Message} (позиция {ex.Position + 1}).");
 67                }
 68
 269                var ownColor = GetString(item, "color");
 270                if (ownColor != null && !HexColor().IsMatch(ownColor)) throw new ValidationException($"Столбец «{name}»:
 71
 272                if (item.TryGetProperty("group", out var group) && group.ValueKind == JsonValueKind.Object)
 73                {
 274                    var color = GetString(group, "color");
 375                    if (color != null && !HexColor().IsMatch(color)) throw new ValidationException($"Столбец «{name}»: ц
 176                    var groupName = GetString(group, "name");
 177                    if (groupName != null && groupName.Length > MaxNameLength) throw new ValidationException($"Столбец «
 78                }
 79
 180                if (item.TryGetProperty("colors", out var colors) && colors.ValueKind == JsonValueKind.Array)
 81                {
 182                    if (colors.GetArrayLength() > MaxColorRules) throw new ValidationException($"Столбец «{name}»: не бо
 183                    var ruleFields = new Dictionary<string, string>(fields, StringComparer.OrdinalIgnoreCase) { ["value"
 484                    foreach (var rule in colors.EnumerateArray())
 85                    {
 186                        var when = GetString(rule, "when");
 287                        try { OrdersGridFormula.Validate(when ?? string.Empty, ruleFields); }
 088                        catch (OrdersGridFormula.FormulaException ex) { throw new ValidationException($"Столбец «{name}»
 189                        var bg = GetString(rule, "bg");
 190                        var fg = GetString(rule, "fg");
 191                        if ((bg != null && !HexColor().IsMatch(bg)) || (fg != null && !HexColor().IsMatch(fg)))
 092                            throw new ValidationException($"Столбец «{name}»: цвет правила должен быть в виде #rrggbb.")
 93                    }
 94                }
 95            }
 96        }
 197    }
 98
 99    private static string? GetString(JsonElement obj, string name)
 18100        => obj.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.String ? v.GetString() : null;
 101}