< Summary

Information
Class: Chronicis.Api.Services.ArticleValidationService
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Services/ArticleValidationService.cs
Line coverage
100%
Covered lines: 29
Uncovered lines: 0
Coverable lines: 29
Total lines: 100
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ValidateCreateAsync()100%44100%
ValidateUpdateAsync()100%44100%
ValidateDeleteAsync()100%22100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Api/Services/ArticleValidationService.cs

#LineLine coverage
 1using Chronicis.Api.Data;
 2using Chronicis.Shared.DTOs;
 3using Microsoft.EntityFrameworkCore;
 4
 5namespace Chronicis.Api.Services;
 6
 7public class ArticleValidationService : IArticleValidationService
 8{
 9    private readonly ChronicisDbContext _context;
 10
 1611    public ArticleValidationService(ChronicisDbContext context)
 12    {
 1613        _context = context;
 1614    }
 15
 16    public async Task<ValidationResult> ValidateCreateAsync(ArticleCreateDto dto)
 17    {
 418        var result = new ValidationResult();
 19
 20        // Parent must exist if specified
 421        if (dto.ParentId.HasValue)
 22        {
 223            var parentExists = await _context.Articles
 224                .AnyAsync(a => a.Id == dto.ParentId.Value);
 25
 226            if (!parentExists)
 27            {
 128                result.AddError("ParentId", "Parent article does not exist");
 29            }
 30        }
 31
 432        return result;
 433    }
 34
 35    public async Task<ValidationResult> ValidateUpdateAsync(Guid articleId, ArticleUpdateDto dto)
 36    {
 537        var result = new ValidationResult();
 38
 39        // Article must exist
 540        var articleExists = await _context.Articles
 541            .AnyAsync(a => a.Id == articleId);
 42
 543        if (!articleExists)
 44        {
 145            result.AddError("Id", "Article not found");
 46        }
 47
 48        // Title is required
 549        if (string.IsNullOrWhiteSpace(dto.Title))
 50        {
 351            result.AddError("Title", "Title is required");
 52        }
 53
 554        return result;
 555    }
 56
 57    public async Task<ValidationResult> ValidateDeleteAsync(Guid articleId)
 58    {
 359        var result = new ValidationResult();
 60
 61        // Article must exist
 362        var article = await _context.Articles
 363            .Include(a => a.Children)
 364            .FirstOrDefaultAsync(a => a.Id == articleId);
 65
 366        if (article == null)
 67        {
 168            result.AddError("Id", "Article not found");
 169            return result;
 70        }
 71
 272        return result;
 373    }
 74}
 75
 76/// <summary>
 77/// Represents the result of a validation operation.
 78/// </summary>
 79public class ValidationResult
 80{
 81    private readonly Dictionary<string, List<string>> _errors = new();
 82
 83    public bool IsValid => _errors.Count == 0;
 84
 85    public IReadOnlyDictionary<string, List<string>> Errors => _errors;
 86
 87    public void AddError(string field, string message)
 88    {
 89        if (!_errors.ContainsKey(field))
 90        {
 91            _errors[field] = new List<string>();
 92        }
 93        _errors[field].Add(message);
 94    }
 95
 96    public string GetFirstError()
 97    {
 98        return _errors.Values.FirstOrDefault()?.FirstOrDefault() ?? "Validation failed";
 99    }
 100}