Skip to content

Commit

Permalink
Merge pull request #63 from ricaun-io/develop
Browse files Browse the repository at this point in the history
Version 1.7.1
  • Loading branch information
ricaun authored Dec 10, 2024
2 parents 8f4edf2 + 6ec0ab4 commit 63e40a9
Show file tree
Hide file tree
Showing 22 changed files with 354 additions and 166 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [1.7.1] / 2024-12-07 - 2024-12-10
### Application
- Update to use `AssemblyMetadata` to set configuration. (Fix: #64)
- Update `TestExecuteUtils` to use `ConfigurationMetadata`.
- Update `Log` file name.
- Update `ricaun.NUnit` to `1.4.1`.
- Add `MetadataMapper` to map `AssemblyMetadata` configuration.
- Update to use `Task.Run` to force run outside the Revit context.
- Update `Timeout` to time unit in minutes.
### Command
- Update `AssemblyName` to use `Version`.
- Update `Timeout` to `double`.
### TestAdapter
- Update `MapperKey` to multiple converts.
- Update `MetadataMapper` with `prefix`.
- Fix `Mapper` convert integer to ignore dot.
- Update `Timeout` to `double`.
### Tests
- Update `TestsRevitTask` with `AssemblyMetadata` configuration.

## [1.7.0] / 2024-11-02 - 2024-12-03
### Features
- Support `IRevitTask` functions as parameters.
Expand Down Expand Up @@ -526,6 +546,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- [x] TestsFail

[vNext]: ../../compare/1.0.0...HEAD
[1.7.1]: ../../compare/1.7.0...1.7.1
[1.7.0]: ../../compare/1.6.0...1.7.0
[1.6.0]: ../../compare/1.5.0...1.6.0
[1.5.0]: ../../compare/1.4.1...1.5.0
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<Version>1.7.0</Version>
<Version>1.7.1</Version>
</PropertyGroup>
</Project>
3 changes: 2 additions & 1 deletion ricaun.RevitTest.Application/Revit/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ private static void PipeTestServer_Initialize()

try
{
testAssemblyModel = await TestExecuteUtils.ExecuteAsync(RevitTask, message.TestPathFile, RevitParameters.Parameters);
testAssemblyModel = await Task.Run(() => TestExecuteUtils.ExecuteAsync(RevitTask, message.TestPathFile, RevitParameters.Parameters));
//testAssemblyModel = await TestExecuteUtils.ExecuteAsync(RevitTask, message.TestPathFile, RevitParameters.Parameters);
}
catch (Exception ex)
{
Expand Down
2 changes: 1 addition & 1 deletion ricaun.RevitTest.Application/Revit/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static void OpenJornal()
#endregion

#region File
private static string FileName = "RevitTest_{0}.log";
private static string FileName = "RevitTest_{0:X}.log";
private static string FilePath = null;

private static void CreateFile()
Expand Down
199 changes: 199 additions & 0 deletions ricaun.RevitTest.Application/Revit/Utils/MetadataMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace ricaun.RevitTest.Application.Revit
{
internal static class MetadataMapper
{
public static T Map<T>(T destination, IEnumerable<AssemblyMetadataAttribute> attributes, string prefix = null) where T : class
{
if (attributes is null)
return destination;

var metadataDictionary = attributes
.GroupBy(attr => attr.Key)
.ToDictionary(group => group.Key, group => group.Last().Value);

return MapperKey.Map(destination, metadataDictionary, prefix);
}
}
internal static class MapperKey
{
public static T Map<T>(T destination, IDictionary<string, string> dictionary, string prefix = null)
{
if (dictionary is null)
return destination;

foreach (var kvp in Mapper.ProcessProperties(destination, prefix))
{
var sourceKey = kvp.Key;
var sourcePropertyInfo = kvp.PropertyInfo;
var sourceValue = sourcePropertyInfo.GetValue(kvp.Object);

Debug.WriteLine($"{sourceKey} - {sourcePropertyInfo} - {sourceValue}");

if (dictionary.TryGetValue(sourceKey, out string valueToConvert))
{
var destinationValue = Mapper.ConvertValueToPropertyInfo(valueToConvert, sourcePropertyInfo);
if (!Mapper.IsValueEqual(sourceValue, destinationValue))
{
try
{
destinationValue = Convert.ChangeType(destinationValue, sourcePropertyInfo.PropertyType);
sourcePropertyInfo.SetValue(kvp.Object, destinationValue);
Debug.WriteLine($"\t{sourceKey}: {sourceValue} >> {sourcePropertyInfo.Name}: {destinationValue}");
}
catch (Exception ex){ Debug.WriteLine(ex); }
}
}
}

return destination;
}
public static IEnumerable<string> GetNames<T>(T destination)
{
return Mapper.ProcessProperties(destination).Select(e => e.Key).ToList();
}
public static class Mapper
{
public static string[] CustomAttributeNames = new[] { "ElementName", "DisplayName", "Name" };
public static Dictionary<Type, Func<string, object>> MapperConvert;
public static object ConvertToLong(string valueToConvert)
{
if (long.TryParse(valueToConvert.Replace(',', '.').Split('.')[0], out var value))
return value;
return valueToConvert;
}
public static object ConvertToULong(string valueToConvert)
{
if (ulong.TryParse(valueToConvert.Replace(',', '.').Split('.')[0], out var value))
return value;
return valueToConvert;
}
public static object ConvertToDouble(string valueToConvert)
{
try
{
return double.Parse(valueToConvert.Replace(',', '.'), System.Globalization.CultureInfo.InvariantCulture);
}
catch { }
return valueToConvert;
}
public static object ConvertToBool(string valueToConvert)
{
var value = valueToConvert.ToLower();
return value.Equals("true") || value.Equals("1");
}
static Mapper()
{
MapperConvert = new Dictionary<Type, Func<string, object>>();
MapperConvert.Add(typeof(ulong), ConvertToULong);
MapperConvert.Add(typeof(uint), ConvertToULong);
MapperConvert.Add(typeof(ushort), ConvertToULong);
MapperConvert.Add(typeof(long), ConvertToLong);
MapperConvert.Add(typeof(int), ConvertToLong);
MapperConvert.Add(typeof(short), ConvertToLong);
MapperConvert.Add(typeof(double), ConvertToDouble);
MapperConvert.Add(typeof(float), ConvertToDouble);
MapperConvert.Add(typeof(bool), ConvertToBool);
}

#region PropertyInformation
public class PropertyInformation
{
public string Key { get; }
public object Object { get; }
public PropertyInfo PropertyInfo { get; }

public PropertyInformation(string key, object obj, PropertyInfo propertyInfo)
{
Key = key;
Object = obj;
PropertyInfo = propertyInfo;
}
}
public static IEnumerable<PropertyInformation> ProcessProperties(object obj, string prefix = null)
{
if (obj == null)
yield break;

if (string.IsNullOrEmpty(prefix))
prefix = string.Empty;

Type objectType = obj.GetType();
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (PropertyInfo property in properties)
{
var propertyName = GetCustomAttributeName(property);
string propertyKey = string.IsNullOrEmpty(prefix) ? propertyName : $"{prefix}.{propertyName}";

if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
object nestedPropertyValue = property.GetValue(obj);
if (nestedPropertyValue is null)
{
try
{
nestedPropertyValue = Activator.CreateInstance(property.PropertyType);
property.SetValue(obj, nestedPropertyValue);
}
catch { }
}
foreach (var nestedProperty in ProcessProperties(nestedPropertyValue, propertyKey))
{
yield return nestedProperty;
}
}
else
{
yield return new PropertyInformation(propertyKey, obj, property);
}
}
}
#endregion
public static string GetCustomAttributeName(MemberInfo memberInfo)
{
try
{
var customPropertyNames = CustomAttributeNames;
foreach (var customAttribute in memberInfo.GetCustomAttributes())
{
var type = customAttribute.GetType();
foreach (var propertyName in customPropertyNames)
{
if (type?.GetProperty(propertyName) is PropertyInfo propertyInfo)
{
var value = propertyInfo.GetValue(customAttribute) as string;
if (!string.IsNullOrEmpty(value)) return value;
}
}
}
}
catch { }
return memberInfo.Name;
}
public static object ConvertValueToPropertyInfo(string valueToConvert, PropertyInfo propertyInfo)
{
var type = propertyInfo.PropertyType;
if (MapperConvert.TryGetValue(type, out var converter))
{
return converter.Invoke(valueToConvert);
}
return valueToConvert;
}
public static bool IsValueEqual(object sourceValue, object destinationValue)
{
if (sourceValue is null)
{
return destinationValue is null;
}

return sourceValue.Equals(destinationValue);
}
}
}
}
Loading

0 comments on commit 63e40a9

Please sign in to comment.