This commit is contained in:
2024-09-22 17:19:58 +03:00
parent 958c69df4c
commit 1625764e0a
10 changed files with 584 additions and 6 deletions

View File

@@ -6,7 +6,7 @@ namespace ApplicationLayer
{ {
public readonly static Regex EnglishWordRegex = new("^[a-zA-Z]*$"); public readonly static Regex EnglishWordRegex = new("^[a-zA-Z]*$");
public readonly static Regex EnglishPhraseRegex = new(@"^[a-zA-Z№0-9?><;,{}[\]\-_+=!@#$%\^&*|']*$"); public readonly static Regex EnglishPhraseRegex = new(@"^[a-zA-Z №0-9;,\-_+=#*']*$");
public readonly static Regex PhoneNumRegex = new(@"^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$"); public readonly static Regex PhoneNumRegex = new(@"^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$");
} }

View File

@@ -60,7 +60,7 @@ public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel>
.WithMessage("Building of place of work can not be empty") .WithMessage("Building of place of work can not be empty")
.Matches(Constants.EnglishPhraseRegex) .Matches(Constants.EnglishPhraseRegex)
.WithMessage("Place of work building field can contain only english letters, digits and special symbols") .WithMessage("Place of work building field can contain only english letters, digits and special symbols")
.MaximumLength(ConfigurationConstraints.CountryNameLength) .MaximumLength(ConfigurationConstraints.BuildingNumberLength)
.WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}"); .WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}");
} }
} }

View File

@@ -31,7 +31,7 @@ namespace VisaApi.Fakers.Applicants
=> new Passport => new Passport
{ {
Issuer = f.Company.CompanyName(), Issuer = f.Company.CompanyName(),
Number = f.Random.String(ConfigurationConstraints.PasswordLength), Number = f.Random.String(ConfigurationConstraints.PasswordLength, 'a', 'z'),
ExpirationDate = f.Date.Future(4, dateTimeProvider.Now()), ExpirationDate = f.Date.Future(4, dateTimeProvider.Now()),
IssueDate = f.Date.Past(4, dateTimeProvider.Now()) IssueDate = f.Date.Past(4, dateTimeProvider.Now())
}); });

View File

@@ -0,0 +1,24 @@
using ApplicationLayer.InfrastructureServicesInterfaces;
using ApplicationLayer.Services.Applicants.Models;
using Bogus;
using Domains;
namespace VisaApi.Fakers.Applicants.Requests
{
public sealed class PassportModelFaker : Faker<PassportModel>
{
public PassportModelFaker(IDateTimeProvider dateTimeProvider)
{
RuleFor(m => m.Issuer, f => f.Company.CompanyName());
RuleFor(m => m.Number,
f => f.Random.String(ConfigurationConstraints.PassportNumberLength, 'a', 'z'));
RuleFor(m => m.ExpirationDate,
f => f.Date.Future(4, dateTimeProvider.Now()));
RuleFor(m => m.IssueDate,
f => f.Date.Past(4, dateTimeProvider.Now()));
}
}
}

View File

@@ -0,0 +1,25 @@
using ApplicationLayer.Services.Applicants.Models;
using Bogus;
using Domains.ApplicantDomain;
namespace VisaApi.Fakers.Applicants.Requests
{
public sealed class PlaceOfWorkModelFaker : Faker<PlaceOfWorkModel>
{
public PlaceOfWorkModelFaker()
{
RuleFor(m => m.Name, f => f.Company.CompanyName());
RuleFor(m => m.PhoneNum, f => f.Phone.PhoneNumber("###########"));
RuleFor(m => m.Address,
f => new AddressModel
{
Country = f.Address.Country(),
City = f.Address.City(),
Street = f.Address.StreetName(),
Building = f.Address.BuildingNumber()
});
}
}
}

View File

@@ -13,7 +13,7 @@ namespace VisaApi.Fakers.VisaApplications
public ReentryPermitFaker(IDateTimeProvider dateTimeProvider) public ReentryPermitFaker(IDateTimeProvider dateTimeProvider)
{ {
RuleFor(p => p.Number, RuleFor(p => p.Number,
f => f.Random.String(ConfigurationConstraints.ReentryPermitNumberLength)); f => f.Random.String(ConfigurationConstraints.ReentryPermitNumberLength, 'a', 'z'));
RuleFor(p => p.ExpirationDate, RuleFor(p => p.ExpirationDate,
f => f.Date.Future(4, dateTimeProvider.Now())); f => f.Date.Future(4, dateTimeProvider.Now()));

View File

@@ -9,7 +9,7 @@ using Xunit;
namespace VisaApi.Tests.Application.Validation.Applicants namespace VisaApi.Tests.Application.Validation.Applicants
{ {
public class NameValidatorTests public class NameModelValidatorTests
{ {
private static IValidator<NameModel> validator = new NameModelValidator(); private static IValidator<NameModel> validator = new NameModelValidator();
private static NameModelFaker faker = new(); private static NameModelFaker faker = new();

View File

@@ -0,0 +1,175 @@
using System.Text;
using ApplicationLayer.InfrastructureServicesInterfaces;
using ApplicationLayer.Services.Applicants.Models;
using ApplicationLayer.Services.Applicants.Models.Validation;
using Domains;
using FluentAssertions;
using FluentValidation;
using VisaApi.Fakers.Applicants.Requests;
using VisaApi.Services;
using Xunit;
namespace VisaApi.Tests.Application.Validation.Applicants
{
public class PassportModelValidatorTests
{
private static IDateTimeProvider dateTimeProvider = new TestDateTimeProvider();
private static IValidator<PassportModel> validator = new PassportModelValidator(dateTimeProvider);
private static PassportModelFaker faker = new(dateTimeProvider);
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for empty number
/// </summary>
[Fact]
private async Task ValidateForEmptyNumberShouldReturnError()
{
var model = faker.Generate();
model.Number = string.Empty;
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Number))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for too long number
/// </summary>
[Fact]
private async Task ValidateForLongNumberShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('d', ConfigurationConstraints.PassportNumberLength + 1);
model.Number = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Number))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for not valid number
/// </summary>
[Fact]
private async Task ValidateForNotValidNumberShouldReturnError()
{
var model = faker.Generate();
model.Number = "&?%$24asd\\]|";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Number))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for empty issuer
/// </summary>
[Fact]
private async Task ValidateForEmptyIssuerShouldReturnError()
{
var model = faker.Generate();
model.Issuer = string.Empty;
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Issuer))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for too long issuer
/// </summary>
[Fact]
private async Task ValidateForLongIssuerShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('d', ConfigurationConstraints.IssuerNameLength + 1);
model.Issuer = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Issuer))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for not valid issuer
/// </summary>
[Fact]
private async Task ValidateForNotValidIssuerShouldReturnError()
{
var model = faker.Generate();
model.Issuer = "&?%$24asd\\]|";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Issuer))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for expired passport
/// </summary>
[Fact]
private async Task ValidateForExpiredPassportShouldReturnError()
{
var model = faker.Generate();
model.ExpirationDate = dateTimeProvider.Now().AddDays(-10);
model.IssueDate = model.ExpirationDate.AddDays(-10);
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.ExpirationDate))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for passport from future
/// </summary>
[Fact]
private async Task ValidateForPassportFromFutureShouldReturnError()
{
var model = faker.Generate();
model.ExpirationDate = dateTimeProvider.Now().AddDays(10);
model.IssueDate = model.ExpirationDate.AddDays(-3);
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.IssueDate))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return error for passport that expired before issue
/// </summary>
[Fact]
private async Task ValidateForPassportExpiredBeforeIssueShouldReturnError()
{
var model = faker.Generate();
model.ExpirationDate = dateTimeProvider.Now().AddDays(10);
model.IssueDate = model.ExpirationDate.AddDays(3);
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.IssueDate))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PassportModel"/> validator that should return no errors for valid passport
/// </summary>
[Fact]
private async Task ValidateForValidPassportShouldReturnNoErrors()
{
var model = faker.Generate();
var result = await validator.ValidateAsync(model);
result.Errors.Should().BeEmpty();
}
}
}

View File

@@ -0,0 +1,354 @@
using System.Text;
using ApplicationLayer.Services.Applicants.Models;
using ApplicationLayer.Services.Applicants.Models.Validation;
using Domains;
using FluentAssertions;
using FluentValidation;
using VisaApi.Fakers.Applicants.Requests;
using Xunit;
namespace VisaApi.Tests.Application.Validation.Applicants
{
public class PlaceOfWorkModelValidatorTests
{
private static IValidator<PlaceOfWorkModel> validator = new PlaceOfWorkModelValidator();
private static PlaceOfWorkModelFaker faker = new();
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty phone num
/// </summary>
[Fact]
private async Task ValidateForEmptyPhoneNumShouldReturnError()
{
var model = faker.Generate();
model.PhoneNum = string.Empty;
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.PhoneNum))
.Should().NotBeEmpty();
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for long phone num
/// </summary>
[Fact]
private async Task ValidateForLongPhoneNumShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('8', ConfigurationConstraints.PhoneNumberLength + 1);
model.PhoneNum = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.PhoneNum))
.Should().NotBeEmpty();
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for short phone num
/// </summary>
[Fact]
private async Task ValidateForShortPhoneNumShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('8', ConfigurationConstraints.PhoneNumberMinLength - 1);
model.PhoneNum = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.PhoneNum))
.Should()
.HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid phone num
/// </summary>
[Fact]
private async Task ValidateForNotValidPhoneNumShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('a', ConfigurationConstraints.PhoneNumberMinLength);
model.PhoneNum = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.PhoneNum))
.Should()
.HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should throw exception for null address
/// </summary>
[Fact]
private async Task ValidateForEmptyAddressShouldThrow()
{
var model = faker.Generate();
model.Address = null!;
NullReferenceException? result = null;
try
{
await validator.ValidateAsync(model);
}
catch (Exception e)
{
result = e as NullReferenceException;
}
result.Should().NotBeNull();
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty Country
/// </summary>
[Fact]
private async Task ValidateForEmptyCountryShouldReturnError()
{
var model = faker.Generate();
model.Address.Country = "";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Country")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for too long Country
/// </summary>
[Fact]
private async Task ValidateForLongCountryShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('a', ConfigurationConstraints.CountryNameLength + 1);
model.Address.Country = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Country")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid Country
/// </summary>
[Fact]
private async Task ValidateForNotValidCountryShouldReturnError()
{
var model = faker.Generate();
model.Address.Country = "|&%";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Country")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty City
/// </summary>
[Fact]
private async Task ValidateForEmptyCityShouldReturnError()
{
var model = faker.Generate();
model.Address.City = "";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.City")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for too long city
/// </summary>
[Fact]
private async Task ValidateForLongCityShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('a', ConfigurationConstraints.CityNameLength + 1);
model.Address.City = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.City")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid city
/// </summary>
[Fact]
private async Task ValidateForNotValidCityShouldReturnError()
{
var model = faker.Generate();
model.Address.City = "|&%";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.City")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty street
/// </summary>
[Fact]
private async Task ValidateForEmptyStreetShouldReturnError()
{
var model = faker.Generate();
model.Address.Street = "";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Street")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for too long street
/// </summary>
[Fact]
private async Task ValidateForLongStreetShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('a', ConfigurationConstraints.StreetNameLength + 1);
model.Address.Street = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Street")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid street
/// </summary>
[Fact]
private async Task ValidateForNotValidStreetShouldReturnError()
{
var model = faker.Generate();
model.Address.Street = "|&%";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Street")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty building /// </summary>
[Fact]
private async Task ValidateForEmptyBuildingShouldReturnError()
{
var model = faker.Generate();
model.Address.Building = "";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Building")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for too long building
/// </summary>
[Fact]
private async Task ValidateForLongBuildingShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('a', ConfigurationConstraints.BuildingNumberLength + 1);
model.Address.Building = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Building")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid building
/// </summary>
[Fact]
private async Task ValidateForNotValidBuildingShouldReturnError()
{
var model = faker.Generate();
model.Address.Building = "|&%";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == "Address.Building")
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for empty name
/// </summary>
[Fact]
private async Task ValidateForEmptyNameShouldReturnError()
{
var model = faker.Generate();
model.Name = "";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Name))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for too long name
/// </summary>
[Fact]
private async Task ValidateForTooLongNameShouldReturnError()
{
var model = faker.Generate();
var stringBuilder = new StringBuilder();
stringBuilder.Append('g', ConfigurationConstraints.PlaceOfWorkNameLength + 1);
model.Name = stringBuilder.ToString();
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Name))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return error for not valid name
/// </summary>
[Fact]
private async Task ValidateForNotValidNameShouldReturnError()
{
var model = faker.Generate();
model.Name = "@$%&|";
var result = await validator.ValidateAsync(model);
result.Errors.Where(error => error.PropertyName == nameof(model.Name))
.Should().HaveCount(1);
}
/// <summary>
/// Test for <see cref="PlaceOfWorkModel"/> validator that should return no errors for valid model
/// </summary>
[Fact]
private async Task ValidateForValidShouldReturnNoErrors()
{
var model = faker.Generate();
var result = await validator.ValidateAsync(model);
result.Errors.Should().BeEmpty();
}
}
}