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

AndreuCodina / CrossValidation / 4276481348

pending completion
4276481348

Pull #19

github

GitHub
Merge f7cee18c5 into 33f23a935
Pull Request #19: General errors by default with That()

320 of 352 branches covered (90.91%)

Branch coverage included in aggregate %.

44 of 44 new or added lines in 4 files covered. (100.0%)

964 of 1032 relevant lines covered (93.41%)

121.08 hits per line

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

96.4
/src/CrossValidation/Validations/ValidValidation.cs
1
using System.Diagnostics;
2
using System.Net;
3
using CrossValidation.Errors;
4
using CrossValidation.Exceptions;
5
using CrossValidation.Resources;
6

7
namespace CrossValidation.Validations;
8

9
public interface IValidValidation<out TField> : IValidation<TField>
10
{
11
    public string? Code { get; set; }
12
    public string? Message { get; set; }
13
    public string? Details { get; set; }
14
    public ICrossError? Error { get; set; }
15
    public string? FieldDisplayName { get; set; }
16
    public HttpStatusCode? HttpStatusCode { get; set; }
17
    bool ExecuteNextValidator { get; set; }
18
    public TField GetFieldValue();
19
    public ValidationContext Context { get; set; }
20
    public string? FieldFullPath { get; set; }
21
    public Type CrossErrorToException { get; set; }
22
    void HandleError(ICrossError error);
23
    void TakeErrorCustomizations(ICrossError error, bool overrideCustomizations);
24

25
    public static IValidation<TField> CreateFromField(
26
        TField fieldValue,
27
        Type crossErrorToException,
28
        bool generalizeError = true,
29
        string? fieldFullPath = null,
30
        ValidationContext? context = null,
31
        int? index = null,
32
        string? parentPath = null,
33
        ICrossError? error = null,
34
        string? message = null,
35
        string? code = null,
36
        string? details = null,
37
        HttpStatusCode? httpStatusCode = null,
38
        string? fieldDisplayName = null)
39
    {
40
        return new ValidValidation<TField>(
171✔
41
            fieldValue: fieldValue,
171✔
42
            crossErrorToException: crossErrorToException,
171✔
43
            generalizeError: generalizeError,
171✔
44
            fieldFullPath: fieldFullPath,
171✔
45
            context: context,
171✔
46
            index: index,
171✔
47
            parentPath: parentPath,
171✔
48
            error: error,
171✔
49
            message: message,
171✔
50
            code: code,
171✔
51
            details: details,
171✔
52
            httpStatusCode: httpStatusCode,
171✔
53
            fieldDisplayName: fieldDisplayName);
171✔
54
    }
55

56
    public static IValidation<TField> CreateFromFieldName(
57
        TField fieldValue,
58
        Type crossErrorToException,
59
        string fieldName,
60
        bool allowFieldNameWithoutModel,
61
        ValidationContext? context = null,
62
        ICrossError? error = null,
63
        string? message = null,
64
        string? code = null,
65
        string? details = null,
66
        HttpStatusCode? httpStatusCode = null,
67
        string? fieldDisplayName = null)
68
    {
69
        if (!allowFieldNameWithoutModel)
85✔
70
        {
71
            if (!fieldName.Contains("."))
83✔
72
            {
73
                throw new ArgumentException("Use Field without a model is not allowed");
1✔
74
            }
75
        }
76

77
        var fieldFullPath = allowFieldNameWithoutModel
84✔
78
            ? fieldName
84✔
79
            : fieldName.Substring(fieldName.IndexOf('.') + 1);
84✔
80
        return new ValidValidation<TField>(
84✔
81
            fieldValue: fieldValue,
84✔
82
            crossErrorToException: crossErrorToException,
84✔
83
            generalizeError: false,
84✔
84
            fieldFullPath: fieldFullPath,
84✔
85
            context: context,
84✔
86
            error: error,
84✔
87
            message: message,
84✔
88
            code: code,
84✔
89
            details: details,
84✔
90
            httpStatusCode: httpStatusCode,
84✔
91
            fieldDisplayName: fieldDisplayName);
84✔
92
    }
93

94
    void Clean();
95
}
96

97
file class ValidValidation<TField> :
98
    Validation<TField>,
99
    IValidValidation<TField>
100
{
101
    private string? _code;
102
    private string? _message;
103
    private string? _details;
104
    private ICrossError? _error;
105
    private string? _fieldDisplayName;
106
    private HttpStatusCode? _httpStatusCode;
107

108
    public TField FieldValue { get; set; }
723✔
109
    public ValidationContext Context { get; set; }
7,552✔
110
    public string? FieldFullPath { get; set; }
262✔
111
    public Type CrossErrorToException { get; set; }
509✔
112

113
    public string? Code
114
    {
115
        get
116
        {
117
            if (Context.Code is not null)
343✔
118
            {
119
                return Context.Code;
10✔
120
            }
121

122
            return _code;
333✔
123
        }
124
        set
125
        {
126
            if (Context.Code is not null)
230✔
127
            {
128
                return;
6✔
129
            }
130

131
            _code = value;
224✔
132
        }
224✔
133
    }
134

135
    public string? Message
136
    {
137
        get
138
        {
139
            if (Context.Message is not null)
221✔
140
            {
141
                return Context.Message;
10✔
142
            }
143

144
            return _message;
211✔
145
        }
146
        set
147
        {
148
            if (Context.Message is not null)
213✔
149
            {
150
                return;
6✔
151
            }
152

153
            _message = value;
207✔
154
        }
207✔
155
    }
156

157
    public string? Details
158
    {
159
        get
160
        {
161
            if (Context.Details is not null)
197✔
162
            {
163
                return Context.Details;
7✔
164
            }
165

166
            return _details;
190✔
167
        }
168
        set
169
        {
170
            if (Context.Details is not null)
203✔
171
            {
172
                return;
6✔
173
            }
174

175
            _details = value;
197✔
176
        }
197✔
177
    }
178

179
    public ICrossError? Error
180
    {
181
        get
182
        {
183
            if (Context.Error is not null)
165✔
184
            {
185
                return Context.Error;
4✔
186
            }
187

188
            return _error;
161✔
189
        }
190
        set
191
        {
192
            if (Context.Error is not null)
175✔
193
            {
194
                return;
3✔
195
            }
196

197
            _error = value;
172✔
198
        }
172✔
199
    }
200

201
    public string? FieldDisplayName
202
    {
203
        get
204
        {
205
            if (Context.FieldDisplayName is not null)
209✔
206
            {
207
                return Context.FieldDisplayName;
10✔
208
            }
209

210
            return _fieldDisplayName;
199✔
211
        }
212
        set
213
        {
214
            if (Context.FieldDisplayName is not null)
462✔
215
            {
216
                return;
8✔
217
            }
218

219
            _fieldDisplayName = value;
454✔
220
        }
454✔
221
    }
222

223
    public HttpStatusCode? HttpStatusCode
224
    {
225
        get
226
        {
227
            if (Context.HttpStatusCode is not null)
198✔
228
            {
229
                return Context.HttpStatusCode;
7✔
230
            }
231

232
            return _httpStatusCode;
191✔
233
        }
234
        set
235
        {
236
            if (Context.HttpStatusCode is not null)
200✔
237
            {
238
                return;
6✔
239
            }
240

241
            _httpStatusCode = value;
194✔
242
        }
194✔
243
    }
244

245
    public bool ExecuteNextValidator { get; set; } = true;
887✔
246

247
    public ValidValidation(
255✔
248
        TField fieldValue,
255✔
249
        Type crossErrorToException,
255✔
250
        bool generalizeError,
255✔
251
        string? fieldFullPath = null,
255✔
252
        ValidationContext? context = null,
255✔
253
        int? index = null,
255✔
254
        string? parentPath = null,
255✔
255
        ICrossError? error = null,
255✔
256
        string? message = null,
255✔
257
        string? code = null,
255✔
258
        string? details = null,
255✔
259
        HttpStatusCode? httpStatusCode = null,
255✔
260
        string? fieldDisplayName = null)
255✔
261
    {
262
        FieldValue = fieldValue;
255✔
263
        CrossErrorToException = crossErrorToException;
255✔
264
        Context = context ?? new ValidationContext();
255✔
265
        FieldDisplayName = null;
255✔
266
        FieldFullPath = fieldFullPath;
255✔
267
        Context.GeneralizeError = generalizeError;
255✔
268

269
        var indexRepresentation = Context.FieldName is not null && index is not null
255✔
270
            ? $"[{index}]"
255✔
271
            : null;
255✔
272
        string? parentPathValue = null;
255✔
273

274
        if (parentPath is not null)
255!
275
        {
276
            parentPathValue = parentPath;
×
277
        }
278
        else if (Context.ParentPath is not null)
255✔
279
        {
280
            parentPathValue = Context.ParentPath;
8✔
281
        }
282

283
        if (parentPathValue is not null)
255✔
284
        {
285
            parentPathValue += ".";
8✔
286
        }
287

288
        Context.FieldName = parentPathValue + fieldFullPath + indexRepresentation;
255✔
289

290
        if (Context.FieldName is "")
255✔
291
        {
292
            Context.FieldName = null;
107✔
293
        }
294

295
        Context.Error = error;
255✔
296
        Context.Message = message;
255✔
297
        Context.Code = code;
255✔
298
        Context.Details = details;
255✔
299
        Context.HttpStatusCode = httpStatusCode;
255✔
300
        Context.FieldDisplayName = fieldDisplayName;
255✔
301
    }
255✔
302

303
    public TField GetFieldValue()
304
    {
305
        return FieldValue;
336✔
306
    }
307

308
    public void TakeErrorCustomizations(ICrossError error, bool overrideCustomizations)
309
    {
310
        if (!overrideCustomizations)
38✔
311
        {
312
            return;
4✔
313
        }
314

315
        Code = error.Code ?? Code;
34✔
316
        Message = error.Message ?? Message;
34✔
317
        Details = error.Details ?? Details;
34✔
318
        HttpStatusCode = error.HttpStatusCode ?? HttpStatusCode;
34✔
319
        FieldDisplayName = error.FieldDisplayName ?? FieldDisplayName;
34✔
320
    }
34✔
321

322
    public void HandleError(ICrossError error)
323
    {
324
        var errorToAdd = Error ?? error;
122✔
325
        AddError(errorToAdd);
122✔
326

327
        if (Context is {ValidationMode: ValidationMode.StopValidationOnFirstError})
122✔
328
        {
329
            if (Context.ErrorsCollected!.Count == 1)
88✔
330
            {
331
                throw Context.ErrorsCollected[0].ToException();
88✔
332
            }
333
        }
334
    }
34✔
335

336
    public override TField Instance()
337
    {
338
        return FieldValue;
6✔
339
    }
340

341
    public override TInstance Instance<TInstance>(Func<TField, TInstance> fieldToInstance)
342
    {
343
        try
344
        {
345
            return fieldToInstance(FieldValue);
4✔
346
        }
347
        catch (CrossException e)
4✔
348
        {
349
            e.Error.FieldName = null;
4✔
350
            e.Error.FieldValue = null;
4✔
351
            e.Error.PlaceholderValues = null;
4✔
352
            e.Error.CrossErrorToException = CrossErrorToException;
4✔
353
            TakeErrorCustomizations(e.Error, overrideCustomizations: false);
4✔
354
            HandleError(e.Error);
4✔
355
            throw new UnreachableException();
×
356
        }
357
    }
×
358

359
    public void Clean()
360
    {
361
        Code = null;
141✔
362
        Message = null;
141✔
363
        Details = null;
141✔
364
        Error = null;
141✔
365
        HttpStatusCode = null;
141✔
366
        FieldDisplayName = null;
141✔
367
        ExecuteNextValidator = true;
141✔
368
    }
141✔
369

370
    private void AddError(ICrossError error)
371
    {
372
        AddCustomizationsToError(error);
122✔
373
        Context.ErrorsCollected ??= new List<ICrossError>();
122✔
374
        error.AddPlaceholderValues();
122✔
375
        Context.ErrorsCollected.Add(error);
122✔
376
    }
122✔
377

378
    private void AddCustomizationsToError(ICrossError error)
379
    {
380
        error.FieldName = Context.FieldName;
122✔
381
        error.FieldDisplayName = GetFieldDisplayNameToFill(error);
122✔
382
        error.FieldValue = FieldValue;
122✔
383
        
384
        if (Code is not null)
122✔
385
        {
386
            error.Code = Code;
34✔
387
        }
388
        else if (Context.GeneralizeError)
88✔
389
        {
390
            error.Code = nameof(ErrorResource.General);
34✔
391
        }
392
        else
393
        {
394
            error.Code = error.Code;
54✔
395
        }
396
        
397
        error.Message = GetMessageToFill(error);
122✔
398
        error.Details = Details ?? error.Details;
122✔
399
        error.HttpStatusCode = HttpStatusCode ?? error.HttpStatusCode;
122✔
400
    }
122✔
401

402
    private string? GetMessageToFill(ICrossError error)
403
    {
404
        if (Message is not null)
122✔
405
        {
406
            return Message;
25✔
407
        }
408

409
        if (Code is not null)
97✔
410
        {
411
            // if (Context.GeneralizeError)
412
            // {
413
            //     return CrossValidationOptions.GetMessageFromCode(nameof(ErrorResource.General));
414
            // }
415
            
416
            return CrossValidationOptions.GetMessageFromCode(Code);
20✔
417
        }
418

419
        if (error.Message is not null)
77✔
420
        {
421
            if (Context.GeneralizeError)
72✔
422
            {
423
                return CrossValidationOptions.GetMessageFromCode(nameof(ErrorResource.General));
25✔
424
            }
425
            
426
            return error.Message;
47✔
427
        }
428

429
        if (error.Code is not null)
5!
430
        {
431
            if (Context.GeneralizeError)
5!
432
            {
433
                return CrossValidationOptions.GetMessageFromCode(nameof(ErrorResource.General));
5✔
434
            }
435
            
436
            return CrossValidationOptions.GetMessageFromCode(error.Code);
×
437
        }
438

439
        return null;
×
440
    }
441

442
    private string GetFieldDisplayNameToFill(ICrossError error)
443
    {
444
        if (FieldDisplayName is not null)
122✔
445
        {
446
            return FieldDisplayName;
10✔
447
        }
448

449
        if (error.FieldDisplayName is not null)
112!
450
        {
451
            return error.FieldDisplayName;
×
452
        }
453

454
        return error.FieldName!;
112✔
455
    }
456
}
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