QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142) getrackt, ohne .gitmodules und ohne erreichbares Remote. Der Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen. Umstellung: - Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6) - Gitlink aus dem Index entfernt - Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
273 lines
10 KiB
C#
273 lines
10 KiB
C#
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<string> _ignoredColumns;
|
|
private readonly Dictionary<Type, List<string>> _ignoredProperties;
|
|
private readonly Dictionary<(Type type, string propertyName), List<(string regex, string replace)>> _cleanupProperties;
|
|
private readonly Dictionary<Type, List<string>> _noDateCleanupProperties;
|
|
|
|
public CentronVerifierSettings()
|
|
{
|
|
this._ignoredColumns = new List<string>();
|
|
this._ignoredProperties = new Dictionary<Type, List<string>>();
|
|
this._cleanupProperties = new Dictionary<(Type type, string propertyName), List<(string regex, string replace)>>();
|
|
this._noDateCleanupProperties = new Dictionary<Type, List<string>>();
|
|
|
|
this.CleanupGuidValues = true;
|
|
this.CleanupDateTimeValues = true;
|
|
this.CleanupDateTimeOffsetValues = true;
|
|
}
|
|
|
|
public void IgnoreColumn(string columnName)
|
|
{
|
|
this._ignoredColumns.Add(columnName);
|
|
}
|
|
|
|
public void IgnoreProperties<T>(params Expression<Func<T, object>> [] properties)
|
|
{
|
|
foreach (var property in properties)
|
|
this.IgnoreProperty(property);
|
|
}
|
|
|
|
public void IgnoreProperty<T>(Expression<Func<T, object>> property)
|
|
{
|
|
Guard.NotNull(property, nameof(property));
|
|
|
|
if (this._ignoredProperties.ContainsKey(typeof(T)) == false)
|
|
{
|
|
this._ignoredProperties[typeof(T)] = new List<string>();
|
|
}
|
|
|
|
this._ignoredProperties[typeof(T)].Add(this.GetPropertyName(property));
|
|
}
|
|
|
|
public void CleanupProperty<T>(Expression<Func<T, object>> 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<T>(Expression<Func<T, string>> property)
|
|
{
|
|
Guard.NotNull(property, nameof(property));
|
|
|
|
var propertyName = this.GetPropertyName(property);
|
|
|
|
if (this._noDateCleanupProperties.ContainsKey(typeof(T)) == false)
|
|
{
|
|
this._noDateCleanupProperties[typeof(T)] = new List<string>();
|
|
}
|
|
|
|
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<string>(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<string>(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<string> GetIgnoredColumns()
|
|
{
|
|
return this._ignoredColumns;
|
|
}
|
|
|
|
public bool CleanupGuidValues { get; set; }
|
|
public bool CleanupDateTimeValues { get; set; }
|
|
public bool CleanupDateTimeOffsetValues { get; set; }
|
|
|
|
private string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> 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<JsonProperty> 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
|
|
}
|
|
} |