• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ParadoxGameConverters / Fronter.NET / 21076776262

16 Jan 2026 06:31PM UTC coverage: 22.878% (-0.1%) from 23.007%
21076776262

Pull #930

github

web-flow
Merge 48476d2af into db6583dcd
Pull Request #930: Reduce allocations in DateSelector.TextValue setter

143 of 770 branches covered (18.57%)

Branch coverage included in aggregate %.

0 of 31 new or added lines in 1 file covered. (0.0%)

3 existing lines in 1 file now uncovered.

717 of 2989 relevant lines covered (23.99%)

8.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.43
/Fronter.NET/Models/Configuration/Options/DateSelector.cs
1
using Avalonia.Data;
2
using commonItems;
3
using ReactiveUI;
4
using System;
5
using System.Globalization;
6

7
namespace Fronter.Models.Configuration.Options;
8

9
internal sealed class DateSelector : ReactiveObject {
10
        public DateSelector(BufferedReader reader) {
12✔
11
                var parser = new Parser();
6✔
12
                RegisterKeys(parser);
6✔
13
                parser.ParseStream(reader);
6✔
14
        }
6✔
15
        private void RegisterKeys(Parser parser) {
6✔
16
                parser.RegisterKeyword("editable", reader => Editable = string.Equals(reader.GetString(), "true", StringComparison.OrdinalIgnoreCase));
12✔
17
                parser.RegisterKeyword("value", reader => {
12✔
18
                        var valueStr = reader.GetString();
6✔
19
                        if (string.IsNullOrWhiteSpace(valueStr)) {
12✔
20
                                Value = null;
6✔
21
                        } else {
6✔
22
                                Value = new Date(valueStr);
×
23
                        }
×
24
                });
12✔
25
                parser.RegisterKeyword("minDate", reader => MinDate = new Date(reader.GetString()).ToDateTimeOffset());
12✔
26
                parser.RegisterKeyword("maxDate", reader => MaxDate = new Date(reader.GetString()).ToDateTimeOffset());
12✔
27
                parser.RegisterKeyword("tooltip", reader => Tooltip = reader.GetString());
12✔
28
                parser.RegisterRegex(CommonRegexes.Catchall, ParserHelpers.IgnoreAndLogItem);
6✔
29
        }
6✔
30

31
        public bool Editable { get; private set; } = true; // editable unless disabled
12✔
32
        public DateTimeOffset MinDate { get; set; } = DateTimeOffset.MinValue;
12✔
33
        public DateTimeOffset MaxDate { get; set; } = DateTimeOffset.MaxValue;
12✔
34

35
        public DateTimeOffset? DateTimeOffsetValue {
36
                get;
3✔
37
                set => this.RaiseAndSetIfChanged(ref field, value);
15✔
38
        }
39

40
        public Date? Value {
41
                get {
2✔
42
                        if (DateTimeOffsetValue is null) {
3✔
43
                                return null;
1✔
44
                        }
45

46
                        var offsetValue = DateTimeOffsetValue.Value;
1✔
47
                        return new Date(offsetValue);
1✔
48
                }
2✔
49
                set {
15✔
50
                        if (value is null) {
22✔
51
                                DateTimeOffsetValue = null;
7✔
52
                        } else {
15✔
53
                                DateTimeOffsetValue = value.Value.ToDateTimeOffset();
8✔
54
                        }
8✔
55
                }
15✔
56
        }
57

58
        public string? TextValue {
59
                get => Value?.ToString();
×
60
                set {
×
61
                        if (string.IsNullOrWhiteSpace(value)) {
×
62
                                DateTimeOffsetValue = null;
×
63
                        } else {
×
NEW
64
                                ValidateDateString(value);
×
65

66
                                DateTimeOffsetValue = new Date(value).ToDateTimeOffset();
×
67
                        }
×
68
                        this.RaisePropertyChanged(nameof(TextValue));
×
69
                }
×
70
        }
71

NEW
72
        private static void ValidateDateString(string value) {
×
NEW
73
                int segmentCount = 0;
×
NEW
74
                ReadOnlySpan<char> span = value.AsSpan();
×
75

NEW
76
                int start = 0;
×
NEW
77
                for (int i = 0; i <= span.Length; i++) {
×
NEW
78
                        bool atEnd = i == span.Length;
×
NEW
79
                        if (!atEnd && span[i] != '.') {
×
NEW
80
                                continue;
×
81
                        }
82

NEW
83
                        var segment = span.Slice(start, i - start).Trim();
×
NEW
84
                        start = i + 1;
×
85

NEW
86
                        if (segment.Length == 0) {
×
NEW
87
                                continue;
×
88
                        }
89

NEW
90
                        segmentCount++;
×
NEW
91
                        switch (segmentCount) {
×
92
                                case 1:
NEW
93
                                        ValidateYearSpan(segment);
×
NEW
94
                                        break;
×
95
                                case 2:
NEW
96
                                        ValidateMonthSpan(segment);
×
NEW
97
                                        break;
×
98
                                case 3:
NEW
99
                                        ValidateDaySpan(segment);
×
NEW
100
                                        return; // matches previous behavior: validate first 3 non-empty segments only
×
101
                        }
NEW
102
                }
×
103

NEW
104
                if (segmentCount == 0) {
×
NEW
105
                        throw new DataValidationException($"'{value}' is not a valid date, it should be in the format YYYY.MM.DD.");
×
106
                }
NEW
107
        }
×
108

NEW
109
        private static void ValidateYearSpan(ReadOnlySpan<char> value) {
×
NEW
110
                if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out _)) {
×
UNCOV
111
                        throw new DataValidationException($"'{value}' is not a valid integer.");
×
112
                }
113
        }
×
114

NEW
115
        private static void ValidateMonthSpan(ReadOnlySpan<char> value) {
×
NEW
116
                if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var month)) {
×
UNCOV
117
                        throw new DataValidationException($"'{value}' is not a valid integer.");
×
118
                }
119
                if (month is < 1 or > 12) {
×
120
                        throw new DataValidationException($"'{value}' is not a valid month, it should be between 1 and 12.");
×
121
                }
122
        }
×
123

NEW
124
        private static void ValidateDaySpan(ReadOnlySpan<char> value) {
×
NEW
125
                if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var day)) {
×
UNCOV
126
                        throw new DataValidationException($"'{value}' is not a valid integer.");
×
127
                }
128
                if (day is < 1 or > 31) {
×
129
                        throw new DataValidationException($"'{value}' is not a valid day, it should be between 1 and 31.");
×
130
                }
131
        }
×
132

133
        public string? Tooltip { get; private set; }
6✔
134

135
        public bool UseDatePicker {
136
                get;
×
137
                set => this.RaiseAndSetIfChanged(ref field, value);
×
138
        } = false;
6✔
139

140
        public void ToggleUseDatePicker() {
×
141
                UseDatePicker = !UseDatePicker;
×
142
        }
×
143
        public void ClearValue() {
×
144
                TextValue = null;
×
145
        }
×
146
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc