(feat): adding common extension methods and tests
This commit is contained in:
parent
522a9d4a43
commit
c91a4f4776
@ -3,7 +3,7 @@ using MongoDB.Bson.IO;
|
|||||||
using MongoDB.Bson.Serialization;
|
using MongoDB.Bson.Serialization;
|
||||||
using Core.Abstractions;
|
using Core.Abstractions;
|
||||||
|
|
||||||
namespace PecMgr.DataProviders.Converters {
|
namespace DataProviders.Converters {
|
||||||
|
|
||||||
public class EnumerationSerializer<T> : IBsonSerializer<T> where T : Enumeration {
|
public class EnumerationSerializer<T> : IBsonSerializer<T> where T : Enumeration {
|
||||||
private T Deserialize(IBsonReader reader) => Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader));
|
private T Deserialize(IBsonReader reader) => Enumeration.FromValue<T>(BsonSerializer.Deserialize<int>(reader));
|
||||||
|
|||||||
14
webapi/Extensions/Extensions.csproj
Normal file
14
webapi/Extensions/Extensions.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
45
webapi/Extensions/HttpRequestExtensions.cs
Normal file
45
webapi/Extensions/HttpRequestExtensions.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Extensions {
|
||||||
|
public static class HttpRequestExtensions {
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<string> GetHeader(this HttpRequest request, string name) {
|
||||||
|
var headers = request.Headers[name].ToList();
|
||||||
|
return headers != null ? headers : new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return clean JWT Bearer token from Authorisation Header
|
||||||
|
/// </summary>
|
||||||
|
public static string? GeBearerToken(this HttpRequest request) {
|
||||||
|
var header = request.GetHeader("Authorization").FirstOrDefault();
|
||||||
|
return header !=null
|
||||||
|
? header.Replace("Bearer ", "")
|
||||||
|
: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns JWT Bearer token Vault path from custom AuthorizationPath Header
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string? GetBearerPath(this HttpRequest request) {
|
||||||
|
var header = request.GetHeader("AuthorizationPath").FirstOrDefault();
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
webapi/Extensions/IEquatableExtensions.cs
Normal file
66
webapi/Extensions/IEquatableExtensions.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ExtensionMethods {
|
||||||
|
public static class IEquatableExtensions {
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="item1"></param>
|
||||||
|
/// <param name="item2"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool Eq<T>(this IEquatable<T>? item1, T? item2) {
|
||||||
|
if ((item1 == null && item2 != null) || (item1 != null && item2 == null))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (item1 == null && item2 == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (item1 != null && item2 != null) {
|
||||||
|
var result = item1.Equals(item2);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="list1"></param>
|
||||||
|
/// <param name="list2"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool EnumerableEq<T>(this IEnumerable<IEquatable<T>>? list1, IEnumerable<IEquatable<T>>? list2) {
|
||||||
|
if ((list1 == null && list2 != null) || (list1 != null && list2 == null))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (list1 == null && list2 == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (list1 != null && list2 != null && list1.Count() == list2.Count()) {
|
||||||
|
|
||||||
|
var diffDic = list2.GroupBy(x => x.GetHashCode()).ToDictionary(g => g.Key, g => g.Count());
|
||||||
|
|
||||||
|
for (int i = 0; i < list1.Count(); i++) {
|
||||||
|
var obj = (T)list1.ElementAt(i);
|
||||||
|
var objHash = obj.GetHashCode();
|
||||||
|
|
||||||
|
if (diffDic.ContainsKey(objHash))
|
||||||
|
diffDic[objHash] = diffDic[objHash] - 1;
|
||||||
|
else
|
||||||
|
diffDic.Add(objHash, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !diffDic.Any(x => x.Value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
webapi/Extensions/ObjectExtensions.cs
Normal file
20
webapi/Extensions/ObjectExtensions.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ExtensionMethods {
|
||||||
|
public static class ObjectExtensions {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts object to json string
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToJson<T>(this T obj) {
|
||||||
|
return JsonSerializer.Serialize(obj, new JsonSerializerOptions {
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
345
webapi/Extensions/StringExtensions.cs
Normal file
345
webapi/Extensions/StringExtensions.cs
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace ExtensionMethods {
|
||||||
|
public static class StringExtensions {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SQL Like implementation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <param name="wildcardedText"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool Like(this string text, string wildcardedText) {
|
||||||
|
text = text ?? "";
|
||||||
|
wildcardedText = wildcardedText ?? "";
|
||||||
|
|
||||||
|
return Regex.IsMatch(text, wildcardedText.WildcardToRegular(), RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts wildcarded string tgo regex
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string WildcardToRegular(this string value) =>
|
||||||
|
$"^{Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*")}$";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VB.Net Left implementation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Left(this string s, int count) {
|
||||||
|
return s.Substring(0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VB.Net Right implementation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Right(this string s, int count) {
|
||||||
|
return s.Substring(s.Length - count, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VB.Net Mid implementation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Mid(this string s, int index, int count) {
|
||||||
|
return s.Substring(index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VB.Net ToInteger implementation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int ToInteger(this string s) {
|
||||||
|
var integerValue = 0;
|
||||||
|
int.TryParse(s, out integerValue);
|
||||||
|
return integerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VB.Net IsInteger implementations
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsInteger(this string s) => new Regex("^-[0-9]+$|^[0-9]+$").Match(s).Success;
|
||||||
|
|
||||||
|
public static StringBuilder Prepend(this StringBuilder sb, string content) => sb.Insert(0, content);
|
||||||
|
|
||||||
|
public static T ToEnum<T>(this string input) where T : struct {
|
||||||
|
var result = default(T);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
bool parseSucceeded = Enum.TryParse(input, true, out result);
|
||||||
|
|
||||||
|
if (parseSucceeded)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// se fallisce il parse per valore proviamo ad usare il DisplayAttribute.Name
|
||||||
|
var enumType = typeof(T);
|
||||||
|
|
||||||
|
foreach (T enumItem in Enum.GetValues(enumType)) {
|
||||||
|
var att = enumType.GetMember(enumItem.ToString())[0]
|
||||||
|
.GetCustomAttributes(typeof(DisplayAttribute), false).SingleOrDefault();
|
||||||
|
|
||||||
|
var displayName = ((DisplayAttribute)att).GetName();
|
||||||
|
|
||||||
|
if (input.Equals(displayName, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
return enumItem;
|
||||||
|
}
|
||||||
|
throw new NotSupportedException($"Cannot parse the value '{input}' for {enumType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? ToNullableEnum<T>(this string input) where T : struct => !string.IsNullOrWhiteSpace(input) ? input.ToEnum<T>() : default(T?);
|
||||||
|
|
||||||
|
public static string ToNull(this string s) => !string.IsNullOrWhiteSpace(s) ? s : null;
|
||||||
|
|
||||||
|
public static string NullIfEmptyString(this string s) => s.ToNull();
|
||||||
|
|
||||||
|
public static long ToLong(this string s) {
|
||||||
|
if (!long.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out long result))
|
||||||
|
result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long? ToNullableLong(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToLong() : default(long?);
|
||||||
|
|
||||||
|
public static int ToInt(this string s) {
|
||||||
|
if (!int.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out int result))
|
||||||
|
result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int? ToNullableInt(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToInt() : default(int?);
|
||||||
|
|
||||||
|
public static uint ToUint(this string s) {
|
||||||
|
if (!uint.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out uint result))
|
||||||
|
result = !string.IsNullOrWhiteSpace(s) ? (uint)s.ToUpper().GetHashCode() : default;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint? ToNullableUint(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToUint() : default(uint?);
|
||||||
|
|
||||||
|
public static decimal ToDecimal(this string s) {
|
||||||
|
if (!int.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out int result))
|
||||||
|
result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal? ToNullableDecimal(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDecimal() : default(decimal?);
|
||||||
|
|
||||||
|
public static double ToDouble(this string s) {
|
||||||
|
if (!double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out double result))
|
||||||
|
result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double? ToNullableDouble(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDouble() : default(double?);
|
||||||
|
|
||||||
|
#region DateTime
|
||||||
|
public static DateTime ToDate(this string s, string[] formats) {
|
||||||
|
return DateTime.TryParseExact(s, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime datetime)
|
||||||
|
? DateTime.SpecifyKind(datetime, DateTimeKind.Utc)
|
||||||
|
: throw new ApplicationException($"the date [{s}] is not in required format: [{formats[0]}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime ToDate(this string s) => s.ToDate(new string[] { "dd/MM/yyyy" });
|
||||||
|
|
||||||
|
public static DateTime? ToNullableDate(this string s) => !string.IsNullOrEmpty(s) ? s.ToDate() : default(DateTime?);
|
||||||
|
|
||||||
|
public static DateTime? ToNullableDate(this string s, string[] formats) => !string.IsNullOrEmpty(s) ? s.ToDate(formats) : default(DateTime?);
|
||||||
|
|
||||||
|
public static DateTime ToDateTime(this string s, string[] formats) {
|
||||||
|
if (s == "Now")
|
||||||
|
return DateTime.Now;
|
||||||
|
else if (s == "Today")
|
||||||
|
return DateTime.Today;
|
||||||
|
|
||||||
|
DateTime result;
|
||||||
|
|
||||||
|
if (!DateTime.TryParseExact(s, formats, new DateTimeFormatInfo(), DateTimeStyles.None, out result))
|
||||||
|
throw new ApplicationException(string.Format("unable to parse exact date from value [{0}] with formats [{1}]", s, string.Join(", ", formats)));
|
||||||
|
|
||||||
|
return DateTime.SpecifyKind(result, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime ToDateTime(this string s) => s.ToDateTime(new string[] { "dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy HH:mm", "yyyy-MM-dd'T'HH:mm:ss'Z'" });
|
||||||
|
|
||||||
|
public static DateTime? ToNullableDateTime(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDateTime() : default(DateTime?);
|
||||||
|
|
||||||
|
public static DateTime? ToNullableDateTime(this string s, string[] formats) => !string.IsNullOrWhiteSpace(s) ? s.ToDateTime(formats) : default(DateTime?);
|
||||||
|
#endregion
|
||||||
|
public static bool ToBool(this string s) => new string[] { "ok", "yes", "y", "true", "1" }.Any(x => string.Equals(x, s, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
|
||||||
|
public static bool? ToNullableBool(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToBool() : default(bool?);
|
||||||
|
|
||||||
|
public static Guid ToGuid(this string text) {
|
||||||
|
if (Guid.TryParse(text, out var value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
using var md5 = MD5.Create();
|
||||||
|
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(text.ToUpper()));
|
||||||
|
return new Guid(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid? ToNullableGuid(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToGuid() : default(Guid?);
|
||||||
|
|
||||||
|
public static string[] StringSplit(this string s, char c) {
|
||||||
|
return s.Split(c).Select(x => x.Trim()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToTitle(this string s) {
|
||||||
|
if (!string.IsNullOrWhiteSpace(s)) {
|
||||||
|
var tmp = s.ToCharArray();
|
||||||
|
tmp[0] = char.ToUpper(tmp[0]);
|
||||||
|
s = new string(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Uri> ExtractUrls(this string s) {
|
||||||
|
var urls = new List<Uri>();
|
||||||
|
|
||||||
|
foreach (Match match in Regex.Matches(s, @"(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])")) {
|
||||||
|
if (Uri.TryCreate(match.Value, UriKind.Absolute, out Uri uri)) {
|
||||||
|
urls.Add(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return urls.Distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Format(this string s, params object[] args) => string.Format(s, args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds elipsis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Excerpt(this string s, int length = 60) =>
|
||||||
|
string.IsNullOrEmpty(s) || s.Length < length ? s : s.Substring(0, length - 3) + "...";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts JSON string to object
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T? ToObject<T>(this string s) => JsonSerializer.Deserialize<T>(s, new JsonSerializerOptions {
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adapted from .Net [EmailAddres] model validation attribute
|
||||||
|
/// https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs,17f9a2457ddc8d93
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsValidEmail(this string? s) {
|
||||||
|
Regex CreateRegEx() {
|
||||||
|
const string pattern = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$";
|
||||||
|
const RegexOptions options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
|
||||||
|
|
||||||
|
// Set explicit regex match timeout, sufficient enough for email parsing
|
||||||
|
// Unless the global REGEX_DEFAULT_MATCH_TIMEOUT is already set
|
||||||
|
TimeSpan matchTimeout = TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (AppDomain.CurrentDomain.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") == null) {
|
||||||
|
return new Regex(pattern, options, matchTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// Fallback on error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy fallback (without explicit match timeout)
|
||||||
|
return new Regex(pattern, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This attribute provides server-side email validation equivalent to jquery validate,
|
||||||
|
// and therefore shares the same regular expression. See unit tests for examples.
|
||||||
|
var _regex = CreateRegEx();
|
||||||
|
|
||||||
|
if (s == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return s != null && _regex.Match(s).Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert HTML string to Plain Text without external libraries
|
||||||
|
/// https://docs.microsoft.com/en-us/answers/questions/594274/convert-html-text-to-plain-text-in-c.html
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="htmlCode"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string HTMLToPlainText(this string htmlCode) {
|
||||||
|
|
||||||
|
// Remove new lines since they are not visible in HTML
|
||||||
|
htmlCode = htmlCode.Replace("\n", " ");
|
||||||
|
|
||||||
|
// Remove tab spaces
|
||||||
|
htmlCode = htmlCode.Replace("\t", " ");
|
||||||
|
|
||||||
|
// Remove multiple white spaces from HTML
|
||||||
|
htmlCode = Regex.Replace(htmlCode, "\\s+", " ");
|
||||||
|
|
||||||
|
// Remove HEAD tag
|
||||||
|
htmlCode = Regex.Replace(htmlCode, "<head.*?</head>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||||
|
|
||||||
|
// Remove any JavaScript
|
||||||
|
htmlCode = Regex.Replace(htmlCode, "<script.*?</script>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||||
|
|
||||||
|
// Replace special characters like &, <, >, " etc.
|
||||||
|
StringBuilder sbHTML = new StringBuilder(htmlCode);
|
||||||
|
|
||||||
|
// Note: There are many more special characters, these are just
|
||||||
|
// most common. You can add new characters in this arrays if needed
|
||||||
|
string[] OldWords = {" ", "&", """, "<", ">", "®", "©", "•", "™","'"};
|
||||||
|
string[] NewWords = { " ", "&", "\"", "<", ">", "®", "©", "•", "™", "\'" };
|
||||||
|
|
||||||
|
for (int i = 0; i < OldWords.Length; i++) {
|
||||||
|
sbHTML.Replace(OldWords[i], NewWords[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there are line breaks (<br>) or paragraph (<p>)
|
||||||
|
sbHTML.Replace("<br>", "\n<br>");
|
||||||
|
sbHTML.Replace("<br ", "\n<br ");
|
||||||
|
sbHTML.Replace("<p ", "\n<p ");
|
||||||
|
|
||||||
|
// Finally, remove all HTML tags and return plain text
|
||||||
|
var plainText = Regex.Replace(sbHTML.ToString(), "<[^>]*>", "");
|
||||||
|
|
||||||
|
// Remove external new lines
|
||||||
|
plainText = plainText.Trim();
|
||||||
|
|
||||||
|
return plainText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
webapi/Tests/Core/Abstractions/ConfigurationBase.cs
Normal file
61
webapi/Tests/Core/Abstractions/ConfigurationBase.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
using CoreTests.Core;
|
||||||
|
|
||||||
|
namespace Tests.CoreTests.Abstractions {
|
||||||
|
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||||
|
public abstract class ConfigurationBase {
|
||||||
|
|
||||||
|
protected IConfiguration _configuration;
|
||||||
|
|
||||||
|
protected ServiceCollection ServiceCollection = new ServiceCollection();
|
||||||
|
|
||||||
|
protected ServiceProvider ServiceProvider { get => ServiceCollection.BuildServiceProvider(); }
|
||||||
|
|
||||||
|
public ConfigurationBase() {
|
||||||
|
_configuration = InitConfig();
|
||||||
|
ConfigureServices(ServiceCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void ConfigureServices(IServiceCollection services);
|
||||||
|
|
||||||
|
private IConfiguration InitConfig() {
|
||||||
|
var aspNetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||||
|
var currentDirectory = Directory.GetCurrentDirectory();
|
||||||
|
|
||||||
|
var configurationBuilder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(aspNetCoreEnvironment) && new FileInfo(Path.Combine(currentDirectory, $"appsettings.{aspNetCoreEnvironment}.json")).Exists)
|
||||||
|
configurationBuilder.AddJsonFile($"appsettings.{aspNetCoreEnvironment}.json", true);
|
||||||
|
else if (new FileInfo(Path.Combine(currentDirectory, "appsettings.json")).Exists)
|
||||||
|
configurationBuilder.AddJsonFile("appsettings.json", true, true);
|
||||||
|
else
|
||||||
|
throw new FileNotFoundException($"Unable to find appsetting.json in {currentDirectory}");
|
||||||
|
|
||||||
|
//var builtConfig = configurationBuilder.Build();
|
||||||
|
//var vaultOptions = builtConfig.GetSection("Vault");
|
||||||
|
|
||||||
|
//configurationBuilder.AddVault(options => {
|
||||||
|
// options.Address = vaultOptions["Address"];
|
||||||
|
|
||||||
|
// options.UnsealKeys = vaultOptions.GetSection("UnsealKeys").Get<List<string>>();
|
||||||
|
|
||||||
|
// options.AuthMethod = EnumerationStringId.FromValue<AuthenticationMethod>(vaultOptions["AuthMethod"]);
|
||||||
|
// options.AppRoleAuthMethod = vaultOptions.GetSection("AppRoleAuthMethod").Get<AppRoleAuthMethod>();
|
||||||
|
// options.TokenAuthMethod = vaultOptions.GetSection("TokenAuthMethod").Get<TokenAuthMethod>();
|
||||||
|
|
||||||
|
// options.MountPath = vaultOptions["MountPath"];
|
||||||
|
// options.SecretType = vaultOptions["SecretType"];
|
||||||
|
|
||||||
|
// options.ConfigurationMappings = vaultOptions.GetSection("ConfigurationMappings").Get<Dictionary<string, string>>();
|
||||||
|
//});
|
||||||
|
|
||||||
|
return configurationBuilder.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
webapi/Tests/Core/Attributes/DefaultPriorityAttribute.cs
Normal file
23
webapi/Tests/Core/Attributes/DefaultPriorityAttribute.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Tests.CoreTests.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the priority value which will be assigned
|
||||||
|
/// to tests in this class which don't have a <see cref="PriorityAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||||
|
public class DefaultPriorityAttribute : Attribute
|
||||||
|
{
|
||||||
|
public DefaultPriorityAttribute(int priority)
|
||||||
|
{
|
||||||
|
Priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Priority { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
27
webapi/Tests/Core/Attributes/PriorityAttribute.cs
Normal file
27
webapi/Tests/Core/Attributes/PriorityAttribute.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Tests.CoreTests.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Indicates relative priority of tests for execution. Tests with the same
|
||||||
|
/// priority are run in alphabetical order. </para>
|
||||||
|
///
|
||||||
|
/// <para>Tests with no priority attribute
|
||||||
|
/// are assigned a priority of <see cref="int.MaxValue"/>,
|
||||||
|
/// unless the class has a <see cref="DefaultPriorityAttribute"/>.</para>
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||||
|
public class PriorityAttribute : Attribute
|
||||||
|
{
|
||||||
|
public PriorityAttribute(int priority)
|
||||||
|
{
|
||||||
|
Priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Priority { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
webapi/Tests/Core/CoreTests.csproj
Normal file
26
webapi/Tests/Core/CoreTests.csproj
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.17.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\DataProviders\DataProviders.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
19
webapi/Tests/Core/FakeServices/MessageFakeService.cs
Normal file
19
webapi/Tests/Core/FakeServices/MessageFakeService.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//using DomainResults.Common;
|
||||||
|
|
||||||
|
//using Core.Domain;
|
||||||
|
//using MsgProvider;
|
||||||
|
|
||||||
|
//namespace CoreTests.FakeServices {
|
||||||
|
// public class MessageFakeService : IMessageService, IDisposable {
|
||||||
|
// public IDomainResult Connect(MailServerConnection conn, string userName, string password) {
|
||||||
|
// return IDomainResult.Success();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public IDomainResult Send(byte[] bytes) {
|
||||||
|
// return IDomainResult.Success();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// public void Dispose() { }
|
||||||
|
// }
|
||||||
|
////}
|
||||||
70
webapi/Tests/Core/FakeServices/ObjectStorageFakeService.cs
Normal file
70
webapi/Tests/Core/FakeServices/ObjectStorageFakeService.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//using DomainResults.Common;
|
||||||
|
|
||||||
|
//using Microsoft.Extensions.Logging;
|
||||||
|
//using Core.Enumerations;
|
||||||
|
//using ObjectStorageProvider;
|
||||||
|
|
||||||
|
|
||||||
|
//namespace CoreTests.FakeServices {
|
||||||
|
// public class ObjectStorageFakeService : IObjectStorageFileService {
|
||||||
|
|
||||||
|
// private readonly ILogger<ObjectStorageFakeService> _logger;
|
||||||
|
// private Dictionary<string, Dictionary<string, byte[]>> _collection;
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// Dictionary<bucketName, Dictionary<objectName, content)>
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="logger"></param>
|
||||||
|
// /// <param name="collection">Dictionary<objectName, (bucketName, content)></param>
|
||||||
|
// public ObjectStorageFakeService(
|
||||||
|
// ILogger<ObjectStorageFakeService> logger,
|
||||||
|
// Dictionary<string, Dictionary<string, byte[]>> collection
|
||||||
|
// ) {
|
||||||
|
// _logger = logger;
|
||||||
|
// _collection = collection;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public (byte[]?, IDomainResult) FileDownload(string bucketName, string objectName) =>
|
||||||
|
// FileDownloadAsync(bucketName, objectName).Result;
|
||||||
|
|
||||||
|
// public Task<(byte[]?, IDomainResult)> FileDownloadAsync(string bucketName, string objectName) =>
|
||||||
|
// Task.Run(() => {
|
||||||
|
// Dictionary<string, byte[]>? bucket;
|
||||||
|
// _collection.TryGetValue(bucketName, out bucket);
|
||||||
|
|
||||||
|
// if (bucket == null)
|
||||||
|
// return IDomainResult.Failed<byte[]?>();
|
||||||
|
|
||||||
|
// byte[]? content;
|
||||||
|
// bucket.TryGetValue(objectName, out content);
|
||||||
|
|
||||||
|
// if (content == null)
|
||||||
|
// return IDomainResult.Failed<byte[]?>();
|
||||||
|
|
||||||
|
// return IDomainResult.Success(content);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// public (string?, IDomainResult) FileUpload(string bucketName, byte[] bytes, string contentType, string location = "us-east-1", bool force = false) {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public (string?, IDomainResult) FileUpload(string bucketName, byte[] bytes, FileExtension fileExtension, string location = "us-east-1", bool force = false) =>
|
||||||
|
// FileUploadAsync(bucketName, bytes, fileExtension, location, force).Result;
|
||||||
|
|
||||||
|
// public Task<(string?, IDomainResult)> FileUploadAsync(string bucketName, byte[] bytes, string contentType, string location = "us-east-1", bool force = false) {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public Task<(string?, IDomainResult)> FileUploadAsync(string bucketName, byte[] bytes, FileExtension fileExtension, string location = "us-east-1", bool force = false) =>
|
||||||
|
// Task.Run(() => {
|
||||||
|
// var objName = $"{Guid.NewGuid()}{fileExtension.Id}";
|
||||||
|
|
||||||
|
// if (!_collection.ContainsKey(bucketName))
|
||||||
|
// _collection.Add(bucketName, new Dictionary<string, byte[]>());
|
||||||
|
|
||||||
|
// _collection[bucketName].Add(objName, bytes);
|
||||||
|
|
||||||
|
// return IDomainResult.Success<string?>(objName);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//}
|
||||||
49
webapi/Tests/Core/FakeServices/SessionFakeService.cs
Normal file
49
webapi/Tests/Core/FakeServices/SessionFakeService.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
using DataProviders;
|
||||||
|
|
||||||
|
namespace CoreTests.FakeServices {
|
||||||
|
public class SessionFakeService : ISessionService {
|
||||||
|
|
||||||
|
private readonly ILogger<SessionFakeService> _logger;
|
||||||
|
private List<Guid> _sessions;
|
||||||
|
|
||||||
|
public SessionFakeService(
|
||||||
|
ILogger<SessionFakeService> logger
|
||||||
|
) {
|
||||||
|
_logger = logger;
|
||||||
|
_sessions = new List<Guid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void CommitTransaction(Guid id) {
|
||||||
|
_sessions.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisposeSession(Guid id) {
|
||||||
|
_sessions.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClientSessionHandle? GetSession(Guid id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RollbackTransaction(Guid id) {
|
||||||
|
_sessions.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Guid> StartSession() {
|
||||||
|
return Task.Run(() => {
|
||||||
|
var sessionId = Guid.NewGuid();
|
||||||
|
_sessions.Add(sessionId);
|
||||||
|
return sessionId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartTransaction(Guid id) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
webapi/Tests/Core/FakeServices/VaultFakeService.cs
Normal file
48
webapi/Tests/Core/FakeServices/VaultFakeService.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
//using DomainResults.Common;
|
||||||
|
|
||||||
|
//using VaultProvider;
|
||||||
|
|
||||||
|
//namespace CoreTests.FakeServices {
|
||||||
|
// public class VaultFakeService : IVaultService {
|
||||||
|
|
||||||
|
// private readonly ILogger<VaultFakeService> _logger;
|
||||||
|
// private Dictionary<string, KeyValuePair<string, object>> _collection;
|
||||||
|
|
||||||
|
// public VaultFakeService(
|
||||||
|
// ILogger<VaultFakeService> logger,
|
||||||
|
// Dictionary<string, KeyValuePair<string, object>> collection
|
||||||
|
// ) {
|
||||||
|
// _logger = logger;
|
||||||
|
// _collection = collection;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public (Guid?, IDomainResult) IsTokenWhitelisted(string path, string token) =>
|
||||||
|
// IsTokenWhitelistedAsync(path, token).Result;
|
||||||
|
|
||||||
|
// public Task<(Guid?, IDomainResult)> IsTokenWhitelistedAsync(string path, string token) =>
|
||||||
|
// Task.Run(() => IDomainResult.Success<Guid?>(Guid.NewGuid()));
|
||||||
|
|
||||||
|
// public (string?, IDomainResult) ReadMailboxPassword(string path) =>
|
||||||
|
// ReadMailboxPasswordAsync(path).Result;
|
||||||
|
|
||||||
|
// public Task<(string?, IDomainResult)> ReadMailboxPasswordAsync(string path) =>
|
||||||
|
// Task.Run(() => {
|
||||||
|
// KeyValuePair<string, object> kv;
|
||||||
|
// _collection.TryGetValue(path, out kv);
|
||||||
|
|
||||||
|
// if (kv.Value == null)
|
||||||
|
// return IDomainResult.Failed<string?>();
|
||||||
|
|
||||||
|
// return IDomainResult.Success((string)kv.Value);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// public (Guid?, IDomainResult) WriteMailboxPassword(string path, string email, string password) =>
|
||||||
|
// WriteMailboxPasswordAsync(path, email, password).Result;
|
||||||
|
|
||||||
|
// public Task<(Guid?, IDomainResult)> WriteMailboxPasswordAsync(string path, string email, string password) {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
97
webapi/Tests/Core/PriorityOrderer.cs
Normal file
97
webapi/Tests/Core/PriorityOrderer.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
Usage
|
||||||
|
Add the following attribute to classes for which you want tests run in order:
|
||||||
|
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||||
|
Then decorate your test methods with the Priority attribute.
|
||||||
|
[Fact, Priority(-10)]
|
||||||
|
public void FirstTestToRun() { }
|
||||||
|
[Fact, Priority(0)]
|
||||||
|
public void SecondTestToRun() { }
|
||||||
|
[Fact, Priority(10)]
|
||||||
|
public void ThirdTestToRunA() { }
|
||||||
|
[Fact, Priority(10)]
|
||||||
|
public void ThirdTestToRunB() { }
|
||||||
|
[Fact]
|
||||||
|
public void TestsWithNoPriorityRunLast() { }
|
||||||
|
Priorities are evaluated in numeric order (including 0 and negative numbers). If there are multiple tests with the same priority, those tests will be run in alphabetical order.
|
||||||
|
By default, tests with no explicit Priority attribute are assigned priority int.MaxValue and will be run last. You can change this by setting a DefaultPriority attribute on your test class.
|
||||||
|
[DefaultPriority(0)]
|
||||||
|
public class MyTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SomeTest() { }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SomeOtherTest() { }
|
||||||
|
|
||||||
|
[Fact, Priority(10)]
|
||||||
|
public void RunMeLast() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Xunit.Sdk;
|
||||||
|
|
||||||
|
using Tests.CoreTests.Attributes;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace CoreTests.Core
|
||||||
|
{
|
||||||
|
public class PriorityOrderer : ITestCaseOrderer
|
||||||
|
{
|
||||||
|
|
||||||
|
public const string Name = "Tests.CoreTests.PriorityOrderer";
|
||||||
|
public const string Assembly = "Tests.CoreTests";
|
||||||
|
|
||||||
|
private static string _priorityAttributeName = typeof(PriorityAttribute).AssemblyQualifiedName;
|
||||||
|
private static string _defaultPriorityAttributeName = typeof(DefaultPriorityAttribute).AssemblyQualifiedName;
|
||||||
|
private static string _priorityArgumentName = nameof(PriorityAttribute.Priority);
|
||||||
|
|
||||||
|
private static ConcurrentDictionary<string, int> _defaultPriorities = new ConcurrentDictionary<string, int>();
|
||||||
|
|
||||||
|
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
|
||||||
|
{
|
||||||
|
var groupedTestCases = new Dictionary<int, List<ITestCase>>();
|
||||||
|
var defaultPriorities = new Dictionary<Type, int>();
|
||||||
|
|
||||||
|
foreach (var testCase in testCases)
|
||||||
|
{
|
||||||
|
var defaultPriority = DefaultPriorityForClass(testCase);
|
||||||
|
var priority = PriorityForTest(testCase, defaultPriority);
|
||||||
|
|
||||||
|
if (!groupedTestCases.ContainsKey(priority))
|
||||||
|
groupedTestCases[priority] = new List<ITestCase>();
|
||||||
|
|
||||||
|
groupedTestCases[priority].Add(testCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
var orderedKeys = groupedTestCases.Keys.OrderBy(k => k);
|
||||||
|
foreach (var list in orderedKeys.Select(priority => groupedTestCases[priority]))
|
||||||
|
{
|
||||||
|
list.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
|
||||||
|
foreach (TTestCase testCase in list)
|
||||||
|
yield return testCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int PriorityForTest(ITestCase testCase, int defaultPriority)
|
||||||
|
{
|
||||||
|
var priorityAttribute = testCase.TestMethod.Method.GetCustomAttributes(_priorityAttributeName).SingleOrDefault();
|
||||||
|
return priorityAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? defaultPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int DefaultPriorityForClass(ITestCase testCase)
|
||||||
|
{
|
||||||
|
var testClass = testCase.TestMethod.TestClass.Class;
|
||||||
|
if (!_defaultPriorities.TryGetValue(testClass.Name, out var result))
|
||||||
|
{
|
||||||
|
var defaultAttribute = testClass.GetCustomAttributes(_defaultPriorityAttributeName).SingleOrDefault();
|
||||||
|
result = defaultAttribute?.GetNamedArgument<int>(_priorityArgumentName) ?? int.MaxValue;
|
||||||
|
_defaultPriorities[testClass.Name] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
webapi/Tests/Extensions/Abstractions/ServiceBase.cs
Normal file
17
webapi/Tests/Extensions/Abstractions/ServiceBase.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
using Tests.CoreTests.Abstractions;
|
||||||
|
|
||||||
|
namespace ExtensionsTests.Abstractions {
|
||||||
|
public abstract class ServicesBase : ConfigurationBase {
|
||||||
|
|
||||||
|
public ServicesBase() : base() { }
|
||||||
|
|
||||||
|
protected override void ConfigureServices(IServiceCollection services) {
|
||||||
|
// configure strongly typed settings objects
|
||||||
|
var appSettingsSection = _configuration.GetSection("Configuration");
|
||||||
|
services.Configure<Configuration>(appSettingsSection);
|
||||||
|
// var appSettings = appSettingsSection.Get<Configuration>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
webapi/Tests/Extensions/Configuration.cs
Normal file
3
webapi/Tests/Extensions/Configuration.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace ExtensionsTests {
|
||||||
|
public class Configuration {}
|
||||||
|
}
|
||||||
37
webapi/Tests/Extensions/ExtensionsTests.csproj
Normal file
37
webapi/Tests/Extensions/ExtensionsTests.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Extensions\Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\Core\CoreTests.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
121
webapi/Tests/Extensions/IEquatableExtensionsTests.cs
Normal file
121
webapi/Tests/Extensions/IEquatableExtensionsTests.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using ExtensionMethods;
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ExtensionsTests {
|
||||||
|
public class IEquatableExtensionsTests {
|
||||||
|
|
||||||
|
private class DummyClass : IEquatable<DummyClass> {
|
||||||
|
public string? Test { get; set; }
|
||||||
|
|
||||||
|
public bool Equals(DummyClass? other) {
|
||||||
|
if (other == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return other.Test == Test;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() {
|
||||||
|
return Test.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Eq() {
|
||||||
|
Assert.True(
|
||||||
|
!new DummyClass { Test = "test" }.Eq(new DummyClass { Test = "Test" })
|
||||||
|
&& new DummyClass { Test = "Test" }.Eq(new DummyClass { Test = "Test" })
|
||||||
|
&& !new DummyClass().Eq(new DummyClass { Test = "Test" })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnumerableEq() {
|
||||||
|
|
||||||
|
var emptyList = new List<DummyClass>();
|
||||||
|
|
||||||
|
var list1 = new List<DummyClass> {
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "67890"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var list2 = new List<DummyClass> {
|
||||||
|
new DummyClass {
|
||||||
|
Test = "67890"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var list3 = new List<DummyClass> {
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "ABCDE"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var list4 = new List<DummyClass> {
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "67890"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "67890"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var list5 = new List<DummyClass> {
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "12345"
|
||||||
|
},
|
||||||
|
new DummyClass {
|
||||||
|
Test = "67890"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// compare between two empty lists (true)
|
||||||
|
var result1 = emptyList.EnumerableEq(emptyList);
|
||||||
|
|
||||||
|
// compare between empty and full list (false)
|
||||||
|
var result2 = emptyList.EnumerableEq(list1);
|
||||||
|
|
||||||
|
// compare between same but unordered lists (true)
|
||||||
|
var result3 = list1.EnumerableEq(list2);
|
||||||
|
|
||||||
|
// compare beween two different lists of the same lenght (false)
|
||||||
|
var result4 = list1.EnumerableEq(list3);
|
||||||
|
|
||||||
|
// compare between two different lenght lists containing same elements (false)
|
||||||
|
var result5 = list1.EnumerableEq(list4);
|
||||||
|
|
||||||
|
// compare between different lists with same lenght and same elements but different proportions (false)
|
||||||
|
var result6 = list4.EnumerableEq(list5);
|
||||||
|
|
||||||
|
Assert.True(
|
||||||
|
result1
|
||||||
|
&& !result2
|
||||||
|
&& result3
|
||||||
|
&& !result4
|
||||||
|
&& !result5
|
||||||
|
&& !result6
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
webapi/Tests/Extensions/ObjectExtensionsTests.cs
Normal file
22
webapi/Tests/Extensions/ObjectExtensionsTests.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using ExtensionMethods;
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ExtensionsTests {
|
||||||
|
|
||||||
|
public class ObjectExtensions {
|
||||||
|
|
||||||
|
private class DummyClass {
|
||||||
|
public string Test { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToJson() {
|
||||||
|
var json = new DummyClass {
|
||||||
|
Test = "Test"
|
||||||
|
}.ToJson();
|
||||||
|
|
||||||
|
Assert.Equal("{\"test\":\"Test\"}", json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
256
webapi/Tests/Extensions/StringExtensionsTests.cs
Normal file
256
webapi/Tests/Extensions/StringExtensionsTests.cs
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
using ExtensionMethods;
|
||||||
|
using ExtensionsTests.Abstractions;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ExtensionsTests {
|
||||||
|
public class StringExtensions : ServicesBase {
|
||||||
|
|
||||||
|
private readonly Configuration _configuration;
|
||||||
|
|
||||||
|
public StringExtensions() {
|
||||||
|
_configuration = ServiceProvider.GetService<IOptions<Configuration>>()?.Value
|
||||||
|
?? throw new NullReferenceException("Configuration not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Like() => "http://maks-it.com".Like("https:?//maks*.com");
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Left() => string.Equals("https://maks-it.com".Left(4), "http");
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Right() => string.Equals("https://maks-it.com".Right(4), ".com");
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Mid() => string.Equals("https://maks-it.com".Mid(8, 7), "maks-it");
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToInteger() {
|
||||||
|
var value = "0".ToInteger();
|
||||||
|
Assert.True(value.GetType() == typeof(int) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsInteger() {
|
||||||
|
Assert.True("123".IsInteger() && !"abc123".IsInteger());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Prepend() {
|
||||||
|
var sb = new StringBuilder("123").Prepend("abc");
|
||||||
|
Assert.Equal("abc123", sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DummyEnum {
|
||||||
|
[Display(Name = "First member")]
|
||||||
|
Member1,
|
||||||
|
[Display(Name = "Second member")]
|
||||||
|
Member2
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToEnum() {
|
||||||
|
Assert.True(DummyEnum.Member1 == "First member".ToEnum<DummyEnum>() && DummyEnum.Member2 == "Member2".ToEnum<DummyEnum>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableEnum() => Assert.True(null == "".ToNullableEnum<DummyEnum>() || DummyEnum.Member1 == "Member1".ToNullableEnum<DummyEnum>());
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNull() => Assert.True(null == "".ToNull() && string.Equals("test", "test".ToNull()));
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToLong() {
|
||||||
|
var value = "0".ToLong();
|
||||||
|
Assert.True(value.GetType() == typeof(long) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableLong() {
|
||||||
|
var value = "0".ToNullableLong();
|
||||||
|
Assert.True(value == 0 && value.GetType() == typeof(long) && "".ToNullableLong() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToInt() {
|
||||||
|
var value = "0".ToInt();
|
||||||
|
Assert.True(value.GetType() == typeof(int) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableInt() {
|
||||||
|
var value = "0".ToNullableInt();
|
||||||
|
Assert.True(value.GetType() == typeof(int) && value == 0 && "".ToNullableInt() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToUint() {
|
||||||
|
var value = "0".ToUint();
|
||||||
|
Assert.True(value.GetType() == typeof(uint) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableUint() {
|
||||||
|
var value = "0".ToNullableUint();
|
||||||
|
Assert.True(value.GetType() == typeof(uint) && value == 0 && "".ToNullableUint() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDecimal() {
|
||||||
|
var value = "0".ToDecimal();
|
||||||
|
Assert.True(value.GetType() == typeof(decimal) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableDecimal() {
|
||||||
|
var value = "0".ToNullableDecimal();
|
||||||
|
Assert.True(value.GetType() == typeof(decimal) && "".ToNullableDecimal() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble() {
|
||||||
|
var value = "0".ToDouble();
|
||||||
|
Assert.True(value.GetType() == typeof(double) && value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableDouble() {
|
||||||
|
var value = "0".ToNullableDouble();
|
||||||
|
Assert.True(value.GetType() == typeof(double) && value == 0 && "".ToNullableDouble() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDate() {
|
||||||
|
var value = "05/08/1988".ToDate();
|
||||||
|
Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableDate() {
|
||||||
|
var value = "05/08/1988".ToDate();
|
||||||
|
Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05) && "".ToNullableDate() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDateTime() {
|
||||||
|
var value = "05/08/1988 00:30:00".ToDateTime();
|
||||||
|
Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05, 00, 30, 00));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableDateTime() {
|
||||||
|
var value = "05/08/1988 00:30:00".ToDateTime();
|
||||||
|
Assert.True(value.GetType() == typeof(DateTime) && value == new DateTime(1988, 08, 05, 00, 30, 00) && "".ToNullableDateTime() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToBool() {
|
||||||
|
Assert.True("true".ToBool() && !"false".ToBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullalbeBool() {
|
||||||
|
Assert.True("true".ToNullableBool().Value && !"false".ToNullableBool().Value && "".ToNullableBool() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToGuid() {
|
||||||
|
var value = "7a11f6ed-d1b6-4d38-9f66-738762c4fde6".ToGuid();
|
||||||
|
Assert.True(value.GetType() == typeof(Guid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToNullableGuid() => Assert.Null("".ToNullableGuid());
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void StringSplit() => Assert.True(new string[] { "hello", "world" }.SequenceEqual("hello, world".StringSplit(',')));
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToTitle() => Assert.Equal("Maks-IT", "maks-IT".ToTitle());
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExtractUrls() => Assert.True(new string[] { "https://maks-it.com/123", "https://git.maks-it.com/123" }
|
||||||
|
.SequenceEqual(
|
||||||
|
"Here are some urls that we have to extract! This one: https://maks-it.com/123 and this one too https://git.maks-it.com/123"
|
||||||
|
.ExtractUrls().Select(x => x.AbsoluteUri.ToString()
|
||||||
|
)));
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Format() => Assert.Equal("MAKS-IT is a consulting company", "{0} is a consulting company".Format("MAKS-IT"));
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Excerpt() => Assert.Equal("M...", "MAKS-IT".Excerpt(4));
|
||||||
|
|
||||||
|
private class DummyClass {
|
||||||
|
public string Test { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToObject() {
|
||||||
|
var obj = "{ \"Test\": \"Test\" }".ToObject<DummyClass>();
|
||||||
|
Assert.Equal("Test", obj.Test);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> GetEmailValidationData() {
|
||||||
|
|
||||||
|
var allData = new List<object[]> {
|
||||||
|
new object [] { "BAR.SPORT.SAS.@LEGALMAIL.IT", false },
|
||||||
|
new object [] { "DANICONFCOM@PEC..IT", false },
|
||||||
|
new object [] { "FRANCESCOF..90@PEC.IT", false },
|
||||||
|
new object [] { "grecoornellas.a.s.@pec.it", false },
|
||||||
|
new object [] { "lavillamar.@pec.libero.it", false },
|
||||||
|
new object [] { "podda.pietro.@tiscali.it", false },
|
||||||
|
new object [] { "scads.r.l.@legalmail.it", false },
|
||||||
|
|
||||||
|
new object [] { "ALESSANDRO.DOTTI@ARCHIWORLDPEC.IT", true },
|
||||||
|
new object [] { "alessandro.durante@mastertrucksrl.it", true },
|
||||||
|
new object [] { "alessandro.elia@pec.lottomatica.it", true },
|
||||||
|
new object [] { "ALESSANDRO.EMILIANI@PEC.IT", true },
|
||||||
|
new object [] { "alessandro.falco@pec.lottomatica.it", true },
|
||||||
|
new object [] { "ALESSANDRO.FANNI@PEC.IT", true },
|
||||||
|
new object [] { "ALESSANDRO.FASULO@PEC.IT", true }
|
||||||
|
};
|
||||||
|
|
||||||
|
return allData;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(GetEmailValidationData))]
|
||||||
|
public void IsValidEmail(string email, bool expected) {
|
||||||
|
var result = email.IsValidEmail();
|
||||||
|
Assert.Equal(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HTMLToPlainText() {
|
||||||
|
var html = @"<Grid>
|
||||||
|
<RichTextBox>
|
||||||
|
<FlowDocument>
|
||||||
|
<p name=""p1"">Hello</p>
|
||||||
|
<p name=""p2"">World!</p>
|
||||||
|
</FlowDocument>
|
||||||
|
</RichTextBox>
|
||||||
|
</Grid>";
|
||||||
|
|
||||||
|
var result = html.HTMLToPlainText();
|
||||||
|
var expected = "Hello \nWorld!";
|
||||||
|
|
||||||
|
Assert.True(string.Compare(expected, result) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
5
webapi/Tests/Extensions/appsettings.json
Normal file
5
webapi/Tests/Extensions/appsettings.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"Configuration": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,6 +19,14 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ClientApp", "ClientApp\ClientApp.njsproj", "{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}"
|
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ClientApp", "ClientApp\ClientApp.njsproj", "{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extensions", "Extensions\Extensions.csproj", "{94A44D75-4AE2-4F1A-A7E9-821710B19F93}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{216302C2-64DE-4AE7-BC14-BDAC5B732472}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensionsTests", "Tests\Extensions\ExtensionsTests.csproj", "{43315A1D-9E09-4398-84B9-A9D9D623AE5A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -53,6 +61,18 @@ Global
|
|||||||
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
{8531F7E2-07D6-4EC5-B3E6-316BBF4499E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{94A44D75-4AE2-4F1A-A7E9-821710B19F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{94A44D75-4AE2-4F1A-A7E9-821710B19F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{94A44D75-4AE2-4F1A-A7E9-821710B19F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{94A44D75-4AE2-4F1A-A7E9-821710B19F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{04CB9827-AA6D-4708-A26D-8420C842506D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{04CB9827-AA6D-4708-A26D-8420C842506D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -60,6 +80,8 @@ Global
|
|||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B} = {113EE574-E047-4727-AA36-841F845504D5}
|
{B8F84A37-B54B-4606-9BC3-6FEB96A5A34B} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5}
|
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||||
|
{43315A1D-9E09-4398-84B9-A9D9D623AE5A} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||||
|
{04CB9827-AA6D-4708-A26D-8420C842506D} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {E2805D02-2425-424C-921D-D97341B76F73}
|
SolutionGuid = {E2805D02-2425-424C-921D-D97341B76F73}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user