Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 1.7.1 #63

Merged
merged 19 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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