in Lib/Collectors/BaseCompare.cs [117:312]
public void Compare(IEnumerable<(CollectObject, string)> differentObjects, IEnumerable<(CollectObject, CollectObject)> modifiedObjects, string? firstRunId, string secondRunId)
{
differentObjects?.AsParallel().ForAll(different =>
{
var colObj = different.Item1;
var obj = new CompareResult()
{
BaseRunId = firstRunId,
CompareRunId = secondRunId,
};
if (different.Item2.Equals(firstRunId))
{
obj.Base = colObj;
Results[(colObj.ResultType, CHANGE_TYPE.DELETED)].Add(obj);
}
else if (different.Item2.Equals(secondRunId))
{
obj.Compare = colObj;
Results[(colObj.ResultType, CHANGE_TYPE.CREATED)].Add(obj);
}
});
modifiedObjects?.AsParallel().ForAll(modified =>
{
var compareLogic = new CompareLogic();
compareLogic.Config.IgnoreCollectionOrder = true;
var first = modified.Item1;
var second = modified.Item2;
if (first != null && second != null)
{
var obj = new CompareResult()
{
Base = first,
Compare = second,
BaseRunId = firstRunId,
CompareRunId = secondRunId
};
var properties = first.GetType().GetProperties();
if (properties is PropertyInfo[])
{
foreach (var prop in properties)
{
try
{
if (Attribute.IsDefined(prop, typeof(SkipCompareAttribute)))
{
continue;
}
List<Diff> diffs;
object? added = null;
object? removed = null;
object? firstProp = prop.GetValue(first);
object? secondProp = prop.GetValue(second);
if (firstProp == null && secondProp == null)
{
continue;
}
else if (firstProp == null && secondProp != null)
{
added = prop.GetValue(second);
diffs = GetDiffs(prop, added, null);
}
else if (secondProp == null && firstProp != null)
{
removed = prop.GetValue(first);
diffs = GetDiffs(prop, null, removed);
}
else
{
var firstVal = prop.GetValue(first);
var secondVal = prop.GetValue(second);
if (firstVal is List<string> && secondVal is List<string>)
{
added = ((List<string>)secondVal).Except((List<string>)firstVal);
removed = ((List<string>)firstVal).Except((List<string>)secondVal);
if (!((IEnumerable<string>)added).Any())
{
added = null;
}
if (!((IEnumerable<string>)removed).Any())
{
removed = null;
}
}
else if (firstVal is List<KeyValuePair<string, string>> && secondVal is List<KeyValuePair<string, string>>)
{
added = ((List<KeyValuePair<string, string>>)secondVal).Except((List<KeyValuePair<string, string>>)firstVal);
removed = ((List<KeyValuePair<string, string>>)firstVal).Except((List<KeyValuePair<string, string>>)secondVal);
if (!((IEnumerable<KeyValuePair<string, string>>)added).Any())
{
added = null;
}
if (!((IEnumerable<KeyValuePair<string, string>>)removed).Any())
{
removed = null;
}
}
else if (firstVal is Dictionary<string, string> && secondVal is Dictionary<string, string>)
{
added = ((Dictionary<string, string>)secondVal)
.Except((Dictionary<string, string>)firstVal)
.ToDictionary(x => x.Key, x => x.Value);
removed = ((Dictionary<string, string>)firstVal)
.Except((Dictionary<string, string>)secondVal)
.ToDictionary(x => x.Key, x => x.Value);
if (!((IEnumerable<KeyValuePair<string, string>>)added).Any())
{
added = null;
}
if (!((IEnumerable<KeyValuePair<string, string>>)removed).Any())
{
removed = null;
}
}
else if (firstVal is Dictionary<string, List<string>> firstDictionary && secondVal is Dictionary<string, List<string>> secondDictionary)
{
added = secondDictionary
.Except(firstDictionary)
.ToDictionary(x => x.Key, x => x.Value);
removed = firstDictionary
.Except(secondDictionary)
.ToDictionary(x => x.Key, x => x.Value);
if (!((Dictionary<string, List<string>>)added).Any())
{
added = null;
}
if (!((Dictionary<string, List<string>>)removed).Any())
{
removed = null;
}
}
else if (firstVal is Dictionary<(TpmAlgId, uint), byte[]> firstTpmAlgDict && secondVal is Dictionary<(TpmAlgId, uint), byte[]> secondTpmAlgDict)
{
added = secondTpmAlgDict.Where(x => !firstTpmAlgDict.ContainsKey(x.Key) || !firstTpmAlgDict[x.Key].SequenceEqual(x.Value));
removed = firstTpmAlgDict.Where(x => !secondTpmAlgDict.ContainsKey(x.Key) || !secondTpmAlgDict[x.Key].SequenceEqual(x.Value));
if (!((IEnumerable<KeyValuePair<(TpmAlgId, uint), byte[]>>)added).Any())
{
added = null;
}
if (!((IEnumerable<KeyValuePair<(TpmAlgId, uint), byte[]>>)removed).Any())
{
removed = null;
}
}
else if ((firstVal is string || firstVal is int || firstVal is bool) && (secondVal is string || secondVal is int || secondVal is bool))
{
if (!compareLogic.Compare(firstVal, secondVal).AreEqual)
{
obj.Diffs.Add(new Diff(prop.Name, firstVal, secondVal));
}
}
else if (firstProp != null && secondProp != null && compareLogic.Compare(firstVal, secondVal).AreEqual)
{
continue;
}
else
{
obj.Diffs.Add(new Diff(prop.Name, firstVal, secondVal));
}
diffs = GetDiffs(prop, added, removed);
}
foreach (var diff in diffs)
{
obj.Diffs.Add(diff);
}
}
catch (InvalidCastException e)
{
Log.Debug(e, $"Failed to cast {JsonConvert.SerializeObject(prop)}");
}
catch (Exception e)
{
Log.Debug(e, "Generic exception. Tell a programmer.");
}
}
}
Results[(first.ResultType, CHANGE_TYPE.MODIFIED)].Add(obj);
}
});
foreach (var empty in Results.Where(x => x.Value.Count == 0))
{
Results.Remove(empty.Key, out _);
}
}