using DevExpress.CodeParser; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.RegularExpressions; using Centron.Core; namespace Centron.Tests.EndToEnd.Infrastructure.Verifier { public class CentronVerifierSettings { private readonly List _ignoredColumns; private readonly Dictionary> _ignoredProperties; private readonly Dictionary<(Type type, string propertyName), List<(string regex, string replace)>> _cleanupProperties; private readonly Dictionary> _noDateCleanupProperties; public CentronVerifierSettings() { this._ignoredColumns = new List(); this._ignoredProperties = new Dictionary>(); this._cleanupProperties = new Dictionary<(Type type, string propertyName), List<(string regex, string replace)>>(); this._noDateCleanupProperties = new Dictionary>(); this.CleanupGuidValues = true; this.CleanupDateTimeValues = true; this.CleanupDateTimeOffsetValues = true; } public void IgnoreColumn(string columnName) { this._ignoredColumns.Add(columnName); } public void IgnoreProperties(params Expression> [] properties) { foreach (var property in properties) this.IgnoreProperty(property); } public void IgnoreProperty(Expression> property) { Guard.NotNull(property, nameof(property)); if (this._ignoredProperties.ContainsKey(typeof(T)) == false) { this._ignoredProperties[typeof(T)] = new List(); } this._ignoredProperties[typeof(T)].Add(this.GetPropertyName(property)); } public void CleanupProperty(Expression> property, string regex, string replace) { Guard.NotNull(property, nameof(property)); Guard.NotNullOrWhiteSpace(regex, nameof(regex)); //replace can be null var propertyName = this.GetPropertyName(property); var key = (typeof(T), propertyName); if (this._cleanupProperties.ContainsKey(key) == false) { this._cleanupProperties[key] = new List<(string regex, string replace)>(); } this._cleanupProperties[key].Add((regex, replace)); } public void NoDateCleanup(Expression> property) { Guard.NotNull(property, nameof(property)); var propertyName = this.GetPropertyName(property); if (this._noDateCleanupProperties.ContainsKey(typeof(T)) == false) { this._noDateCleanupProperties[typeof(T)] = new List(); } this._noDateCleanupProperties[typeof(T)].Add(propertyName); } public void MergeWith(CentronVerifierSettings settings) { Guard.NotNull(settings, nameof(settings)); foreach (var ignoredProperty in settings._ignoredProperties) { if (this._ignoredProperties.ContainsKey(ignoredProperty.Key) == false) { this._ignoredProperties.Add(ignoredProperty.Key, new List(ignoredProperty.Value)); //Make sure to create a copy of the list, so we can't change the original one by accident } else { this._ignoredProperties[ignoredProperty.Key].AddRange(ignoredProperty.Value); } } foreach (var cleanupProperty in settings._cleanupProperties) { if (this._cleanupProperties.ContainsKey(cleanupProperty.Key) == false) { this._cleanupProperties.Add(cleanupProperty.Key, new List<(string, string)>(cleanupProperty.Value)); //Make sure to create a copy of the list, so we can't change the original one by accident } else { this._cleanupProperties[cleanupProperty.Key].AddRange(cleanupProperty.Value); } } foreach (var noDate in settings._noDateCleanupProperties) { if (this._noDateCleanupProperties.ContainsKey(noDate.Key) == false) { this._noDateCleanupProperties.Add(noDate.Key, new List(noDate.Value)); //Make sure to create a copy of the list, so we can't change the original one by accident } else { this._noDateCleanupProperties[noDate.Key].AddRange(noDate.Value); } } this.CleanupGuidValues = settings.CleanupGuidValues || this.CleanupGuidValues; this.CleanupDateTimeValues = settings.CleanupDateTimeValues || this.CleanupDateTimeValues; this.CleanupDateTimeOffsetValues = settings.CleanupDateTimeOffsetValues || this.CleanupDateTimeOffsetValues; } public IContractResolver GetContractResolver() { return new VerifierContractResolver(this); } public List GetIgnoredColumns() { return this._ignoredColumns; } public bool CleanupGuidValues { get; set; } public bool CleanupDateTimeValues { get; set; } public bool CleanupDateTimeOffsetValues { get; set; } private string GetPropertyName(Expression> property) { var unary = property.Body as UnaryExpression; var expr = property.Body as MemberExpression ?? unary?.Operand as MemberExpression; var prop = expr.Member as PropertyInfo; return prop.Name; } #region Internal private class VerifierContractResolver : DefaultContractResolver { private readonly CentronVerifierSettings _settings; public VerifierContractResolver(CentronVerifierSettings settings) { Guard.NotNull(settings, nameof(settings)); this._settings = settings; } protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { return base.CreateProperties(type, memberSerialization).OrderBy(f => f.PropertyName).ToList(); } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); foreach (var ignoredProperty in this._settings._ignoredProperties) { if (property.DeclaringType.IsAssignableFrom(ignoredProperty.Key) && ignoredProperty.Value.Contains(property.PropertyName)) { property.Ignored = true; } } foreach (var cleanupProperty in this._settings._cleanupProperties) { if (property.DeclaringType.IsAssignableFrom(cleanupProperty.Key.type) && cleanupProperty.Key.propertyName == property.PropertyName) { foreach (var cleanup in cleanupProperty.Value) { property.ValueProvider = new CleanupValueProvider(property.ValueProvider, cleanup.regex, cleanup.replace); } } } if (property.PropertyType == typeof(string)) { bool doNotCleanupDate = this._settings._noDateCleanupProperties .Where(f => property.DeclaringType.IsAssignableFrom(f.Key)) .Where(f => f.Value.Contains(property.PropertyName)) .Any(); if (doNotCleanupDate == false) property.ValueProvider = new CleanupDateValueProvider(property.ValueProvider); } return property; } } private class CleanupValueProvider : IValueProvider { private readonly IValueProvider _inner; private readonly string _regex; private readonly string _replace; public CleanupValueProvider(IValueProvider inner, string regex, string replace) { Guard.NotNull(inner, nameof(inner)); Guard.NotNullOrWhiteSpace(regex, nameof(regex)); //replace can be NULL this._inner = inner; this._regex = regex; this._replace = replace; } public object GetValue(object target) { var value = this._inner.GetValue(target); if (value == null) return null; return Regex.Replace((string)value, this._regex, this._replace); } public void SetValue(object target, object value) { this._inner.SetValue(target, value); } } private class CleanupDateValueProvider : IValueProvider { private readonly IValueProvider _inner; public CleanupDateValueProvider(IValueProvider inner) { Guard.NotNull(inner, nameof(inner)); this._inner = inner; } public object GetValue(object target) { var value = this._inner.GetValue(target); if (value == null) return null; value = Regex.Replace((string)value, RegexHelper.Date, "EinDatum"); value = Regex.Replace((string)value, RegexHelper.RtfCreatedDate, string.Empty); return value; } public void SetValue(object target, object value) { this._inner.SetValue(target, value); } } #endregion } }