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

AndreuCodina / CrossValidation / 4276507683

pending completion
4276507683

Pull #19

github

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

310 of 352 branches covered (88.07%)

Branch coverage included in aggregate %.

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

947 of 1032 relevant lines covered (91.76%)

113.42 hits per line

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

96.04
/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>(
149✔
41
            fieldValue: fieldValue,
149✔
42
            crossErrorToException: crossErrorToException,
149✔
43
            generalizeError: generalizeError,
149✔
44
            fieldFullPath: fieldFullPath,
149✔
45
            context: context,
149✔
46
            index: index,
149✔
47
            parentPath: parentPath,
149✔
48
            error: error,
149✔
49
            message: message,
149✔
50
            code: code,
149✔
51
            details: details,
149✔
52
            httpStatusCode: httpStatusCode,
149✔
53
            fieldDisplayName: fieldDisplayName);
149✔
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)
80✔
70
        {
71
            if (!fieldName.Contains("."))
78✔
72
            {
73
                throw new ArgumentException("Use Field without a model is not allowed");
1✔
74
            }
75
        }
76

77
        var fieldFullPath = allowFieldNameWithoutModel
79✔
78
            ? fieldName
79✔
79
            : fieldName.Substring(fieldName.IndexOf('.') + 1);
79✔
80
        return new ValidValidation<TField>(
79✔
81
            fieldValue: fieldValue,
79✔
82
            crossErrorToException: crossErrorToException,
79✔
83
            generalizeError: false,
79✔
84
            fieldFullPath: fieldFullPath,
79✔
85
            context: context,
79✔
86
            error: error,
79✔
87
            message: message,
79✔
88
            code: code,
79✔
89
            details: details,
79✔
90
            httpStatusCode: httpStatusCode,
79✔
91
            fieldDisplayName: fieldDisplayName);
79✔
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; }
645✔
109
    public ValidationContext Context { get; set; }
6,814✔
110
    public string? FieldFullPath { get; set; }
235✔
111
    public Type CrossErrorToException { get; set; }
458✔
112

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

419
        if (error.Message is not null)
69✔
420
        {
421
            if (Context.GeneralizeError)
64✔
422
            {
423
                return CrossValidationOptions.GetMessageFromCode(nameof(ErrorResource.General));
19✔
424
            }
425
            
426
            return error.Message;
45✔
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)
105✔
445
        {
446
            return FieldDisplayName;
10✔
447
        }
448

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

454
        return error.FieldName!;
95✔
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