Skip to content

Commit

Permalink
Full nullable review.
Browse files Browse the repository at this point in the history
Support .NET 7 removed.
  • Loading branch information
Bruno de Souza Melo committed Sep 11, 2024
1 parent 4fb1f95 commit d6720f1
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 70 deletions.
2 changes: 1 addition & 1 deletion docs/Publishing.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nuget.exe push -Source "nuvtools" -ApiKey az NuvTools.Validation.8.0.0.nupkg
nuget.exe push -Source "nuvtools" -ApiKey az NuvTools.Validation.8.1.1.nupkg
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@

namespace NuvTools.Validation.Annotations;

public abstract class PasswordComplexityBaseAttribute : ValidationAttribute
public abstract class PasswordComplexityBaseAttribute(int minOccurrences, Func<string> errorMessageAccessor) : ValidationAttribute(errorMessageAccessor)
{
public int MinOccurrences { get; private set; }

public PasswordComplexityBaseAttribute(int minOccurrences, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
MinOccurrences = minOccurrences;
}
public int MinOccurrences { get; private set; } = minOccurrences;

/// <summary>
/// Applies formatting to a specified error message. (Overrides <see cref = "ValidationAttribute.FormatErrorMessage" />)
Expand All @@ -36,7 +30,7 @@ protected void EnsureLegalMinOcorrences()
}
}

protected static bool IsValidValue(object value)
protected static bool IsValidValue(object? value)
{
return value != null
&& value is string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@

namespace NuvTools.Validation.Annotations;

public class PasswordComplexityCapitalLettersAttribute : PasswordComplexityBaseAttribute
public class PasswordComplexityCapitalLettersAttribute(int minOccurrences) : PasswordComplexityBaseAttribute(minOccurrences, () => Messages.XMustContainAtLeastYCapitalLetters)
{
public PasswordComplexityCapitalLettersAttribute(int minOccurrences)
: base(minOccurrences, () => Messages.XMustContainAtLeastYCapitalLetters)
{
}

public override bool IsValid(object value)
public override bool IsValid(object? value)
{
EnsureLegalMinOcorrences();

// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
if (!IsValidValue(value)) return true;

string str = value as string;
string str = (string)value!;

return Regex.Matches(str, @"[A-Z]").Count >= MinOccurrences;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@

namespace NuvTools.Validation.Annotations;

public class PasswordComplexityDigitsAttribute : PasswordComplexityBaseAttribute
public class PasswordComplexityDigitsAttribute(int minOccurrences) : PasswordComplexityBaseAttribute(minOccurrences, () => Messages.XMustContainAtLeastYDigits)
{
public PasswordComplexityDigitsAttribute(int minOccurrences)
: base(minOccurrences, () => Messages.XMustContainAtLeastYDigits)
{
}

public override bool IsValid(object value)
public override bool IsValid(object? value)
{
EnsureLegalMinOcorrences();

// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
if (!IsValidValue(value)) return true;

string str = value as string;
string str = (string)value!;

return Regex.Matches(str, @"[0-9]").Count >= MinOccurrences;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@

namespace NuvTools.Validation.Annotations;

public class PasswordComplexityLowerCaseLettersAttribute : PasswordComplexityBaseAttribute
public class PasswordComplexityLowerCaseLettersAttribute(int minOccurrences) : PasswordComplexityBaseAttribute(minOccurrences, () => Messages.XMustContainAtLeastYLowerCaseLetters)
{
public PasswordComplexityLowerCaseLettersAttribute(int minOccurrences)
: base(minOccurrences, () => Messages.XMustContainAtLeastYLowerCaseLetters)
{
}

public override bool IsValid(object value)
public override bool IsValid(object? value)
{
EnsureLegalMinOcorrences();

// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
if (!IsValidValue(value)) return true;

string str = value as string;
string str = (string)value!;

return Regex.Matches(str, @"[a-z]").Count >= MinOccurrences;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@

namespace NuvTools.Validation.Annotations;

public class StringValueBaseAttribute : ValidationAttribute
public class StringValueBaseAttribute(Func<string> errorMessageAccessor) : ValidationAttribute(errorMessageAccessor)
{
public StringValueBaseAttribute(Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
}

/// <summary>
/// Applies formatting to a specified error message. (Overrides <see cref = "ValidationAttribute.FormatErrorMessage" />)
Expand All @@ -20,7 +16,7 @@ public override string FormatErrorMessage(string name)
return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
}

protected static bool IsValidValue(object value)
protected static bool IsValidValue(object? value)
{
return value != null
&& value is string
Expand Down
4 changes: 2 additions & 2 deletions src/NuvTools.Validation/Brazil/Annotations/CNPJAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ public CNPJAttribute()
{
}

public override bool IsValid(object value)
public override bool IsValid(object? value)
{
// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
if (!IsValidValue(value)) return true;

string str = value as string;
string str = (string)value!;

return Validator.IsCNPJ(str);
}
Expand Down
4 changes: 2 additions & 2 deletions src/NuvTools.Validation/Brazil/Annotations/CPFttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ public CPFAttribute()
{
}

public override bool IsValid(object value)
public override bool IsValid(object? value)
{
// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
if (!IsValidValue(value)) return true;

string str = value as string;
string str = (string)value!;

return Validator.IsCPF(str);
}
Expand Down
15 changes: 15 additions & 0 deletions src/NuvTools.Validation/Brazil/Validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,19 @@ public static bool IsMobileNumber(this string mobileNumber, bool clearMask = tru
return match.Success;
}

/// <summary>
/// Validates Zip Code number
/// </summary>
/// <param name="zipCode">Zip Code.</param>
/// <param name="clearMask">Clear mask before validate.</param>
/// <returns></returns>
public static bool IsZipCodeNumber(this string zipCode, bool clearMask = true)
{
zipCode = zipCode.GetNumbersOnly();

if (zipCode.Length != 8) return false;

return true;
}

}
5 changes: 3 additions & 2 deletions src/NuvTools.Validation/NuvTools.Validation.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7;net8</TargetFrameworks>
<TargetFrameworks>net8</TargetFrameworks>
<LangVersion>latest</LangVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>Nuv Tools</Authors>
Expand All @@ -10,7 +10,7 @@
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>NuvTools.Validation.snk</AssemblyOriginatorKeyFile>
<Description>Validation library for Web, Desktop and Mobile (MAUI) applications.</Description>
<Version>8.1.0</Version>
<Version>8.1.1</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<PackageIcon>icon.png</PackageIcon>
Expand All @@ -23,6 +23,7 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>NuvTools Validators CPF CNPJ</PackageTags>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
15 changes: 10 additions & 5 deletions src/NuvTools.Validation/RegexPattern.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.ComponentModel;

namespace NuvTools.Validation;

/// <summary>
Expand All @@ -10,10 +8,17 @@ public static class RegexPattern
/// <summary>
/// Regex pattern for e-mail address validation.
/// </summary>
public const string EmailAddress = @"^([a-z0-9_\-])([a-z0-9_\-\.]*)@(\[((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}|((([a-z0-9\-]+)\.)+))([a-z]{2,}|(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\])$";
public const string EMAIL_ADDRESS = @"^([a-z0-9_\-])([a-z0-9_\-\.]*)@(\[((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}|((([a-z0-9\-]+)\.)+))([a-z]{2,}|(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\])$";

private const string BASE64_CONTENT_OPTIONAL = "(?<content>(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4}))";

/// <summary>
/// Regex to validate Base64 and extract using content label.
/// </summary>
public const string BASE64_CONTENT = $@"^{BASE64_CONTENT_OPTIONAL}$";

/// <summary>
/// Regex to validate and extract informations (type, extension and content) from base64 file.
/// Regex to validate and extract informations (type, extension and content) from Data URI Base64.
/// </summary>
public const string Base64File = @"data:(?<type>.+?/(?<extension>.+?));(?<base>.+),(?<content>.+)";
public const string BASE64_DATAURI = $@"^data:(?<type>.+?/(?<extension>.+?));(?<base>.+),{BASE64_CONTENT_OPTIONAL}$";
}
28 changes: 13 additions & 15 deletions src/NuvTools.Validation/Validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,22 @@ public static class Validator
/// </summary>
/// <param name="value">E-mail address</param>
/// <returns></returns>
public static bool IsEmail(this string value) => Regex.IsMatch(value, RegexPattern.EmailAddress);
public static bool IsEmail(this string value) => Regex.IsMatch(value, RegexPattern.EMAIL_ADDRESS);

public static List<string> Validate<T>(this T obj)
public static List<string>? Validate<T>(this T obj)
{
ArgumentNullException.ThrowIfNull(obj, nameof(obj));
ValidationContext context = new(obj, serviceProvider: null, items: null);
List<ValidationResult> results = new();
List<ValidationResult> results = [];
bool isValid = System.ComponentModel.DataAnnotations.Validator.TryValidateObject(obj, context, results, true);

if (isValid == false)
{
List<string> errors = new();
foreach (var validationResult in results)
errors.Add(validationResult.ErrorMessage);
if (isValid) return null;

return errors;
}
List<string> errors = [];
foreach (var validationResult in results)
errors.Add(validationResult.ErrorMessage!);

return null;
return errors;
}

/// <summary>
Expand All @@ -57,7 +55,7 @@ public static bool IsIntNumber(this string input, bool positiveOnly = false)
{
// Try to parse the input string as int
if (int.TryParse(input, out int number))
return positiveOnly ? int.IsPositive(number) : true;
return !positiveOnly || int.IsPositive(number);

// Return false if parsing fails or number is negative
return false;
Expand All @@ -73,7 +71,7 @@ public static bool IsLongNumber(this string input, bool positiveOnly = false)
{
// Try to parse the input string as long
if (long.TryParse(input, out long number))
return positiveOnly ? long.IsPositive(number) : true;
return !positiveOnly || long.IsPositive(number);

// Return false if parsing fails or number is negative
return false;
Expand All @@ -86,11 +84,11 @@ public static bool IsLongNumber(this string input, bool positiveOnly = false)
/// <param name="positiveOnly">If only positive numbers is valid.</param>
/// <param name="provider">An object that supplies culture-specific parsing information about s.</param>
/// <returns>True if the input is a valid decimal number, otherwise false.</returns>
public static bool IsDecimalNumber(this string input, bool positiveOnly = false, IFormatProvider provider = null)
public static bool IsDecimalNumber(this string input, bool positiveOnly = false, IFormatProvider? provider = null)
{
// Try to parse the input string as a decimal
if (decimal.TryParse(input, System.Globalization.NumberStyles.Number | System.Globalization.NumberStyles.AllowDecimalPoint, provider, out decimal number))
return positiveOnly ? decimal.IsPositive(number) : true;
return !positiveOnly || decimal.IsPositive(number);

return false;
}
Expand Down
10 changes: 10 additions & 0 deletions tests/NuvTools.Validation.Test/Brazil/BrazilValidatorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ public void ValidateMobileNumber()
Assert.That(!"21866664444".IsMobileNumber());
}

[Test()]
public void ValidateZipCode()
{
Assert.That("71065-100".IsZipCodeNumber());
Assert.That("88999232".IsZipCodeNumber());
Assert.That(!"(21) 95555-7777".IsZipCodeNumber());
Assert.That(!"95.555-777".IsZipCodeNumber());
Assert.That(!"error".IsZipCodeNumber());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<Version>8.1.0</Version>
<Authors>Nuv Tools</Authors>
<Copyright>Copyright © 2024 Nuv Tools</Copyright>
<PackageProjectUrl>https://nuvtools.com</PackageProjectUrl>
Expand All @@ -12,9 +11,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
</ItemGroup>

<ItemGroup>
Expand Down
30 changes: 30 additions & 0 deletions tests/NuvTools.Validation.Test/ValidatorExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NUnit.Framework;
using System.Globalization;
using System.Text.RegularExpressions;

namespace NuvTools.Validation.Tests;

Expand Down Expand Up @@ -47,4 +48,33 @@ public void ValidateIsDecimalNumber()
Assert.That("83289988074".IsDecimalNumber());
}


[Test()]
public void ValidateDataURIBase64()
{
string dataURIBase64 = "data:text/plain;base64,TnV2IFRvb2xz";

Regex regex = new(RegexPattern.BASE64_DATAURI);
var result = regex.Match(dataURIBase64);

Assert.That(result.Groups["type"].Value == "text/plain");
Assert.That(result.Groups["extension"].Value == "plain");
Assert.That(result.Groups["content"].Value == "TnV2IFRvb2xz");
}

[Test()]
public void ValidateBase64()
{
string base64Content = "TnV2IFRvb2xz";

Regex regex = new(RegexPattern.BASE64_CONTENT);
var result = regex.Match(base64Content);

Assert.That(result.Groups["content"].Value == "TnV2IFRvb2xz");

var restultB = regex.IsMatch(base64Content + "A");

Assert.That(!restultB);
}

}

0 comments on commit d6720f1

Please sign in to comment.