diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e75067..98ac1e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. @@ -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 diff --git a/Directory.Build.props b/Directory.Build.props index 1a04156..3677869 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 1.7.0 + 1.7.1 \ No newline at end of file diff --git a/ricaun.RevitTest.Application/Revit/App.cs b/ricaun.RevitTest.Application/Revit/App.cs index 2ea4a90..66fc5bf 100644 --- a/ricaun.RevitTest.Application/Revit/App.cs +++ b/ricaun.RevitTest.Application/Revit/App.cs @@ -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) { diff --git a/ricaun.RevitTest.Application/Revit/Log.cs b/ricaun.RevitTest.Application/Revit/Log.cs index ccfa163..6d27bf2 100644 --- a/ricaun.RevitTest.Application/Revit/Log.cs +++ b/ricaun.RevitTest.Application/Revit/Log.cs @@ -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() diff --git a/ricaun.RevitTest.Application/Revit/Utils/MetadataMapper.cs b/ricaun.RevitTest.Application/Revit/Utils/MetadataMapper.cs new file mode 100644 index 0000000..e857c15 --- /dev/null +++ b/ricaun.RevitTest.Application/Revit/Utils/MetadataMapper.cs @@ -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 destination, IEnumerable 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 destination, IDictionary 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 GetNames(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> 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>(); + 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 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); + } + } + } +} \ No newline at end of file diff --git a/ricaun.RevitTest.Application/Revit/Utils/TestExecuteUtils.cs b/ricaun.RevitTest.Application/Revit/Utils/TestExecuteUtils.cs index 8ee768b..10e9a52 100644 --- a/ricaun.RevitTest.Application/Revit/Utils/TestExecuteUtils.cs +++ b/ricaun.RevitTest.Application/Revit/Utils/TestExecuteUtils.cs @@ -18,7 +18,7 @@ public static async Task ExecuteAsync(IRevitTask revitTask, s { Log.WriteLine($"TestExecuteUtils: {filePath}"); var zipFile = await revitTask.Run(() => CopyFilesUsingZipFolder(filePath)); - + if (zipFile is null) { Log.WriteLine($"TestExecuteUtils: Copy Zip Fail"); @@ -27,15 +27,14 @@ public static async Task ExecuteAsync(IRevitTask revitTask, s string zipDestination = null; var extractToTempSucess = await revitTask.Run(() => ZipExtension.ExtractToTempFolder(zipFile, out zipDestination)); - + if (extractToTempSucess == false) { Log.WriteLine($"TestExecuteUtils: Extract Zip Fail"); throw new Exception("Extract Zip Fail"); } - //TestAssemblyModel tests = await revitTask.Run(() => TestDirectory(zipDestination, parameters)); - TestAssemblyModel tests = await TestDirectoryAsync(revitTask, zipDestination, Path.GetFileName(filePath), parameters); + TestAssemblyModel tests = await Task.Run(() => TestDirectoryAsync(revitTask, zipDestination, Path.GetFileName(filePath), parameters)); await revitTask.Run(() => CopyFilesBackUsingZip(filePath, zipDestination)); @@ -85,9 +84,9 @@ private static async Task TestDirectoryAsync(IRevitTask revit { TestAssemblyModel modelTest = null; - Log.WriteLine("----------------------------------"); + Log.WriteLine(); Log.WriteLine($"TestEngine: {ricaun.NUnit.TestEngine.Initialize(out string testInitialize)} {testInitialize}"); - Log.WriteLine("----------------------------------"); + Log.WriteLine(); foreach (var filePath in Directory.GetFiles(directory, filePattern)) // "*.dll" { @@ -101,51 +100,52 @@ private static async Task TestDirectoryAsync(IRevitTask revit TestEngineFilter.CancellationTokenTimeOut = TimeSpan.FromSeconds(3); #endif - if (FileVersionInfoUtils.TryGetComments(filePath, out ConfigurationComments comments)) + var configurationMetadata = ConfigurationMetadata.GetConfigurationMetadata(filePath); + + if (configurationMetadata.Timeout > 0) { - if (comments.TimeOut > 0) - { - TestEngineFilter.CancellationTokenTimeOut = TimeSpan.FromSeconds(comments.TimeOut); - Log.WriteLine($"TimeOut: {comments.TimeOut}"); - } + TestEngineFilter.CancellationTokenTimeOut = TimeSpan.FromMinutes(configurationMetadata.Timeout); + Log.WriteLine($"Tasks.Timeout: {configurationMetadata.Timeout} minutes"); + } - string containTestNameForNoRevitContext = comments.TestAsync; - if (string.IsNullOrEmpty(containTestNameForNoRevitContext) == false) + string containTestNameForNoRevitContext = configurationMetadata.Name; + if (string.IsNullOrEmpty(containTestNameForNoRevitContext) == false) + { + Log.WriteLine($"Tasks.Name: {containTestNameForNoRevitContext}"); + if (TestEngineFilter.ExplicitEnabled == false) { - if (TestEngineFilter.ExplicitEnabled == false) - { - TestEngineFilter.ExplicitEnabled = false; - TestEngineFilter.TestNames.AddRange(TestEngine.GetTestFullNames(filePath)); - } + TestEngineFilter.ExplicitEnabled = false; + TestEngineFilter.TestNames.AddRange(TestEngine.GetTestFullNames(filePath)); + } - var originalTestNames = TestEngineFilter.TestNames.ToArray(); - var testGroupNoContext = originalTestNames - .GroupBy(str => str.Contains(containTestNameForNoRevitContext)) - .ToDictionary(group => group.Key, group => group.ToList()); + var originalTestNames = TestEngineFilter.TestNames.ToArray(); + var testGroupNoContext = originalTestNames + .GroupBy(str => str.Contains(containTestNameForNoRevitContext)) + .ToDictionary(group => group.Key, group => group.ToList()); - if (testGroupNoContext.TryGetValue(false, out var inContextTestNames)) - { - TestEngineFilter.TestNames.Clear(); - TestEngineFilter.TestNames.AddRange(inContextTestNames); - modelTest = await revitTask.Run(() => TestEngine.TestAssembly(filePath, parameters)); - } + if (testGroupNoContext.TryGetValue(false, out var inContextTestNames)) + { + Log.WriteLine($"InContext: [{string.Join(",", inContextTestNames)}]"); + TestEngineFilter.TestNames.Clear(); + TestEngineFilter.TestNames.AddRange(inContextTestNames); + modelTest = await revitTask.Run(() => TestEngine.TestAssembly(filePath, parameters)); + } - if (testGroupNoContext.TryGetValue(true, out var testAsyncNames)) + if (testGroupNoContext.TryGetValue(true, out var testAsyncNames)) + { + Log.WriteLine($"Tasks: [{string.Join(",", testAsyncNames)}]"); + TestEngineFilter.TestNames.Clear(); + TestEngineFilter.TestNames.AddRange(testAsyncNames); + var modelTestAsync = await Task.Run(() => TestEngine.TestAssembly(filePath, parameters)); + if (modelTest is null) modelTest = modelTestAsync; + else { - Log.WriteLine($"TestAsync: [{string.Join(",", testAsyncNames)}]"); - TestEngineFilter.TestNames.Clear(); - TestEngineFilter.TestNames.AddRange(testAsyncNames); - var modelTestAsync = TestEngine.TestAssembly(filePath, parameters); - if (modelTest is null) modelTest = modelTestAsync; - else - { - modelTest.Tests.AddRange(modelTestAsync.Tests); - } + modelTest.Tests.AddRange(modelTestAsync.Tests); } - - TestEngineFilter.TestNames.Clear(); - TestEngineFilter.TestNames.AddRange(originalTestNames); } + + TestEngineFilter.TestNames.Clear(); + TestEngineFilter.TestNames.AddRange(originalTestNames); } if (modelTest is null) @@ -156,6 +156,7 @@ private static async Task TestDirectoryAsync(IRevitTask revit var passed = modelTest.Success ? "Passed" : "Failed"; if (modelTest.TestCount == 0) { passed = "No Tests"; } + Log.WriteLine(); Log.WriteLine($"{modelTest}\t {passed}"); var tests = modelTest.Tests.SelectMany(e => e.Tests); @@ -188,95 +189,29 @@ private static async Task TestDirectoryAsync(IRevitTask revit } } - Log.WriteLine("----------------------------------"); + Log.WriteLine(); return modelTest; } - //public static TestAssemblyModel Execute(string filePath, params object[] parameters) - //{ - // var zipFile = CopyFilesUsingZipFolder(filePath); - - // if (zipFile is null) - // return null; - - // var extractToTempSucess = ZipExtension.ExtractToTempFolder(zipFile, out string zipDestination); - - // if (extractToTempSucess == false) - // return null; - - // TestAssemblyModel tests = TestDirectory(zipDestination, parameters); - - // CopyFilesBackUsingZip(filePath, zipDestination); - - // return tests; - //} - - //private static TestAssemblyModel TestDirectory(string directory, params object[] parameters) - //{ - // TestAssemblyModel modelTest = null; - - // Log.WriteLine("----------------------------------"); - // Log.WriteLine($"TestEngine: {ricaun.NUnit.TestEngine.Initialize(out string testInitialize)} {testInitialize}"); - // Log.WriteLine("----------------------------------"); - - // foreach (var filePath in Directory.GetFiles(directory, "*.dll")) - // { - // var fileName = Path.GetFileName(filePath); - // try - // { - // if (TestEngine.ContainNUnit(filePath)) - // { - // //Log.WriteLine($"Test File: {fileName}"); - // //foreach (var testName in TestEngine.GetTestFullNames(filePath)) - // //{ - // // Log.WriteLine($"\t{testName}"); - // //} - - // TestEngineFilter.CancellationTokenTimeOut = TimeSpan.FromMinutes(1); - - // modelTest = TestEngine.TestAssembly(filePath, parameters); - - // var passed = modelTest.Success ? "Passed" : "Failed"; - // if (modelTest.TestCount == 0) { passed = "No Tests"; } - - // Log.WriteLine($"{modelTest}\t {passed}"); - - // var tests = modelTest.Tests.SelectMany(e => e.Tests); - - // foreach (var test in tests) - // { - // Log.WriteLine($"\t {test.Time}\t {test}"); - // //Debug.WriteLine($"Debug:\t {test}\t {test.Console.Trim()}"); - // } - - // if (tests.Any() == false) - // { - // Log.WriteLine($"Error: {modelTest.Message}"); - // try - // { - // var ex = new Exception(modelTest.Message.Split('\n').FirstOrDefault()); - // modelTest = TestEngine.Fail(filePath, ex); - // } - // catch { } - // } - // } - // } - // catch (Exception ex) - // { - // Log.WriteLine($"Error: {fileName} {ex}"); - // } - // } - - // Log.WriteLine("----------------------------------"); - - // return modelTest; - //} - - private class ConfigurationComments + private class ConfigurationMetadata { - public string TestAsync { get; set; } - public double TimeOut { get; set; } + public string Name { get; set; } + /// + /// Timeout in minutes + /// + public double Timeout { get; set; } + + public static ConfigurationMetadata GetConfigurationMetadata(string filePath) + { + var configurationMetadata = new ConfigurationMetadata(); + try + { + MetadataMapper.Map(configurationMetadata, TestEngine.GetAssemblyMetadataAttributes(filePath), "ricaun.RevitTest.Application.Tasks"); + } + catch { } + return configurationMetadata; + } } } } diff --git a/ricaun.RevitTest.Command/Command/IRunTestService.cs b/ricaun.RevitTest.Command/Command/IRunTestService.cs index 9d7068b..ed39239 100644 --- a/ricaun.RevitTest.Command/Command/IRunTestService.cs +++ b/ricaun.RevitTest.Command/Command/IRunTestService.cs @@ -12,7 +12,7 @@ public bool RunTests( string forceLanguageToRevit = null, bool forceToOpenNewRevit = false, bool forceToCloseRevit = false, - int timeoutMinutes = 0, + double timeoutMinutes = 0, params string[] testFilters); } } \ No newline at end of file diff --git a/ricaun.RevitTest.Command/Command/Options.cs b/ricaun.RevitTest.Command/Command/Options.cs index 0169dc5..9a0c8c6 100644 --- a/ricaun.RevitTest.Command/Command/Options.cs +++ b/ricaun.RevitTest.Command/Command/Options.cs @@ -62,7 +62,7 @@ private static Parser CreateParser() [Option("timeout", Default = 0, HelpText = "Timeout in minutes to abort this application.")] - public int Timeout { get; set; } + public double Timeout { get; set; } [Option("debugger", Default = false, diff --git a/ricaun.RevitTest.Command/Process/RevitTestProcessStart.cs b/ricaun.RevitTest.Command/Process/RevitTestProcessStart.cs index aa1f653..318027d 100644 --- a/ricaun.RevitTest.Command/Process/RevitTestProcessStart.cs +++ b/ricaun.RevitTest.Command/Process/RevitTestProcessStart.cs @@ -48,7 +48,7 @@ public RevitTestProcessStart SetClose(bool close = true) if (!close) return this; return SetRevitArgument("close"); } - public RevitTestProcessStart SetTimeout(int timeoutMinutes) => SetRevitArgument("timeout", timeoutMinutes); + public RevitTestProcessStart SetTimeout(double timeoutMinutes) => SetRevitArgument("timeout", timeoutMinutes); public RevitTestProcessStart SetTestFilter(string[] testFilters) { if (testFilters.Length == 0) diff --git a/ricaun.RevitTest.Command/Process/RevitTestProcessStartUtils.cs b/ricaun.RevitTest.Command/Process/RevitTestProcessStartUtils.cs index eb0c208..6819d49 100644 --- a/ricaun.RevitTest.Command/Process/RevitTestProcessStartUtils.cs +++ b/ricaun.RevitTest.Command/Process/RevitTestProcessStartUtils.cs @@ -56,7 +56,7 @@ public static async Task RunExecuteTests( string language = null, bool revitOpen = false, bool revitClose = false, - int timeoutMinutes = 0, + double timeoutMinutes = 0, bool debugger = false, Action consoleAction = null, Action debugAction = null, diff --git a/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj b/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj index be4d7ad..b830334 100644 --- a/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj +++ b/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj @@ -40,7 +40,7 @@ - $(PackageId) + $(PackageId).$(Version) $(PackageId) Copyright (C) $(Company) $(CopyrightYears) diff --git a/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip b/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip index 9e85817..d6fe362 100644 Binary files a/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip and b/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip differ diff --git a/ricaun.RevitTest.Console/Revit/RevitRunTestService.cs b/ricaun.RevitTest.Console/Revit/RevitRunTestService.cs index 4e04cfd..dc6418e 100644 --- a/ricaun.RevitTest.Console/Revit/RevitRunTestService.cs +++ b/ricaun.RevitTest.Console/Revit/RevitRunTestService.cs @@ -17,7 +17,7 @@ public bool RunTests(string fileToTest, string forceLanguageToRevit = null, bool forceToOpenNewRevit = false, bool forceToCloseRevit = false, - int timeoutMinutes = 0, + double timeoutMinutes = 0, params string[] testFilters) { RevitTestUtils.CreateRevitServer( diff --git a/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs b/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs index 940c663..d478074 100644 --- a/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs +++ b/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs @@ -98,7 +98,7 @@ public static void CreateRevitServer( string forceLanguageToRevit = null, bool forceToOpenNewRevit = false, bool forceToCloseRevit = false, - int timeoutMinutes = 0, + double timeoutMinutes = 0, params string[] testFilters) { int timeoutNotBusyCountMax = 10; @@ -198,7 +198,7 @@ public static void CreateRevitServer( } }; - var timeoutSeconds = timeoutMinutes * 60; + int timeoutSeconds = (int) timeoutMinutes * 60; for (int i = 0; i <= timeoutSeconds; i++) { Thread.Sleep(1000); diff --git a/ricaun.RevitTest.TestAdapter/Metadatas/MapperKey.cs b/ricaun.RevitTest.TestAdapter/Metadatas/MapperKey.cs index a606f46..cd39560 100644 --- a/ricaun.RevitTest.TestAdapter/Metadatas/MapperKey.cs +++ b/ricaun.RevitTest.TestAdapter/Metadatas/MapperKey.cs @@ -8,12 +8,12 @@ namespace ricaun.RevitTest.TestAdapter.Metadatas { internal static class MapperKey { - public static T Map(T destination, IDictionary dictionary) + public static T Map(T destination, IDictionary dictionary, string prefix = null) { if (dictionary is null) return destination; - foreach (var kvp in Mapper.ProcessProperties(destination)) + foreach (var kvp in Mapper.ProcessProperties(destination, prefix)) { var sourceKey = kvp.Key; var sourcePropertyInfo = kvp.PropertyInfo; @@ -28,6 +28,7 @@ public static T Map(T destination, IDictionary dictionary) { try { + destinationValue = Convert.ChangeType(destinationValue, sourcePropertyInfo.PropertyType); sourcePropertyInfo.SetValue(kvp.Object, destinationValue); Debug.WriteLine($"\t{sourceKey}: {sourceValue} >> {sourcePropertyInfo.Name}: {destinationValue}"); } @@ -46,29 +47,44 @@ public static class Mapper { public static string[] CustomAttributeNames = new[] { "ElementName", "DisplayName", "Name" }; public static Dictionary> 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>(); - MapperConvert.Add(typeof(int), (string valueToConvert) => - { - if (int.TryParse(valueToConvert, out int value)) - return value; - return valueToConvert; - }); - MapperConvert.Add(typeof(double), (string valueToConvert) => - { - try - { - return double.Parse(valueToConvert.Replace(',', '.'), System.Globalization.CultureInfo.InvariantCulture); - } - catch { } - return valueToConvert; - }); - MapperConvert.Add(typeof(bool), (string valueToConvert) => - { - var value = valueToConvert.ToLower(); - return value.Equals("true") || value.Equals("1"); - }); + 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 diff --git a/ricaun.RevitTest.TestAdapter/Metadatas/MetadataMapper.cs b/ricaun.RevitTest.TestAdapter/Metadatas/MetadataMapper.cs index fa67fdc..bd87ee9 100644 --- a/ricaun.RevitTest.TestAdapter/Metadatas/MetadataMapper.cs +++ b/ricaun.RevitTest.TestAdapter/Metadatas/MetadataMapper.cs @@ -8,7 +8,7 @@ namespace ricaun.RevitTest.TestAdapter.Metadatas { internal static class MetadataMapper { - public static T Map(T destination, IEnumerable attributes) where T : class + public static T Map(T destination, IEnumerable attributes, string prefix = null) where T : class { if (attributes is null) return destination; @@ -17,7 +17,7 @@ public static T Map(T destination, IEnumerable att .GroupBy(attr => attr.Key) .ToDictionary(group => group.Key, group => group.Last().Value); - return MapperKey.Map(destination, metadataDictionary); + return MapperKey.Map(destination, metadataDictionary, prefix); } } } diff --git a/ricaun.RevitTest.TestAdapter/Models/RunSettingsModel.cs b/ricaun.RevitTest.TestAdapter/Models/RunSettingsModel.cs index 6f88fa7..5f8abf1 100644 --- a/ricaun.RevitTest.TestAdapter/Models/RunSettingsModel.cs +++ b/ricaun.RevitTest.TestAdapter/Models/RunSettingsModel.cs @@ -24,7 +24,7 @@ public class NUnitModel public bool Close { get; set; } [XmlElement("Timeout")] - public int Timeout { get; set; } + public double Timeout { get; set; } [XmlElement("Verbosity")] public int Verbosity { get; set; } diff --git a/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip b/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip index 9d6bbad..20d9364 100644 Binary files a/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip and b/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip differ diff --git a/ricaun.RevitTest.TestAdapter/Resources/net8.0-windows/ricaun.RevitTest.Console.zip b/ricaun.RevitTest.TestAdapter/Resources/net8.0-windows/ricaun.RevitTest.Console.zip index 50c3e69..504f500 100644 Binary files a/ricaun.RevitTest.TestAdapter/Resources/net8.0-windows/ricaun.RevitTest.Console.zip and b/ricaun.RevitTest.TestAdapter/Resources/net8.0-windows/ricaun.RevitTest.Console.zip differ diff --git a/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs b/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs index b3adca4..9d33e34 100644 --- a/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs +++ b/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs @@ -109,7 +109,7 @@ public async Task RunExecuteTests( string language = null, bool revitOpen = false, bool revitClose = false, - int timeoutMinutes = 0, + double timeoutMinutes = 0, Action consoleAction = null, Action debugAction = null, Action errorAction = null, diff --git a/ricaun.RevitTest.Tests/TestsDebugger.cs b/ricaun.RevitTest.Tests/TestsDebugger.cs index 93eaf85..e8706a1 100644 --- a/ricaun.RevitTest.Tests/TestsDebugger.cs +++ b/ricaun.RevitTest.Tests/TestsDebugger.cs @@ -22,11 +22,11 @@ //[assembly: AssemblyMetadata("NUnit.Application", "..\\..\\..\\..\\ricaun.RevitTest.Console\\bin\\Debug\\ricaun.DA4R.NUnit.Console.zip")] -[assembly: AssemblyMetadata("NUnit.Timeout", "5")] - //[assembly: AssemblyMetadata("NUnit.Language", "ENU /hosted")] #endif +[assembly: AssemblyMetadata("NUnit.Timeout", "5.5")] + namespace ricaun.RevitTest.Tests { #if DEBUG diff --git a/ricaun.RevitTest.Tests/TestsRevitTask.cs b/ricaun.RevitTest.Tests/TestsRevitTask.cs index 69833a2..1ac5433 100644 --- a/ricaun.RevitTest.Tests/TestsRevitTask.cs +++ b/ricaun.RevitTest.Tests/TestsRevitTask.cs @@ -2,10 +2,12 @@ using NUnit.Framework; using ricaun.Revit.UI.Tasks; using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; -[assembly: System.Reflection.AssemblyDescription("{\"TestAsync\":\"RevitTask\",\"TimeOut\":60.0}")] +[assembly: System.Reflection.AssemblyMetadata("ricaun.RevitTest.Application.Tasks.Name", "RevitTask")] +[assembly: System.Reflection.AssemblyMetadata("ricaun.RevitTest.Application.Tasks.Timeout", "0.05")] namespace ricaun.RevitTest.Tests { @@ -51,6 +53,20 @@ private bool InContext(UIApplication uiapp) return !(uiapp.ActiveAddInId is null); } + [Test] + public void GetAssemblies() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(assembly => typeof(TestsRevitTask).Assembly.FullName == assembly.FullName); + foreach (var assembly in assemblies) + { + Console.WriteLine($"{assembly.GetName().Name} | {(!string.IsNullOrEmpty(assembly.Location) ? System.IO.Path.GetFileName(assembly.Location) : string.Empty)}"); + } +#if !DEBUG + // Check if the assembly is only loaded once + Assert.AreEqual(1, assemblies.Count()); +#endif + } + [Test] public async Task RunContext() {