diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18ff770..569623f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,33 @@ 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.6.0] / 2024-09-25 - 2024-10-06
+### Features
+- Support `TestAdapter` custom executer.
+- Support environment variables to overwrite settings in the `TestAdapter`. (Fix: #57)
+- Support `Cancel` tests and `Kill` processes in the `TestAdapter`.
+### App
+- Force to kill test when `ClientDisconnected`.
+### Command
+- Update to use `JsonService` implementation to use `Newtonsoft.Json` in the domain.
+- Update `ProcessStart` with `GetProcesses` to enable kill process.
+### Console
+- Add `RevitTestUtils.Exceptions` to show exceptions in the console.
+- Add `ricaun.RevitAPI.Fake.References.RevitAPIUI` to fix `RevitAPIUI` reference exception in the discovery test. (Fix: #58)
+- Disable/Remove discovery test to use `RevitAPIUI` version `2021` to `2023`.
+- Add Environment variable for process arguments `RICAUN_REVITTEST_CONSOLE_PROCESS_ARGUMENTS`.
+### Shared
+- Update to use `ricaun.NamedPipeWrapper.Json` version `1.8.0`.
+- Add `ClientDisconnected` in `PipeProcessServer`.
+### TestAdapter
+- Use `LocalExtensionData` to store `TestModel` result.
+- Add `EnvironmentSettings` to overwrite settings in the `TestAdapter`.
+- Update `JsonService` implementation to use `Newtonsoft.Json` in the domain.
+- Support `Cancel` to abort and `Kill` processes.
+- Add `ProcessExtension` to `KillTree` for net framework.
+### Tests
+- Add `TestsRevitUI` to validate fake `RevitAPIUI` reference.
+
## [1.5.0] / 2024-09-11 - 2024-09-19
### Features
- Support tests with `TestCaseSource`. (Fix: #55)
@@ -486,6 +513,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- [x] TestsFail
[vNext]: ../../compare/1.0.0...HEAD
+[1.6.0]: ../../compare/1.5.0...1.6.0
[1.5.0]: ../../compare/1.4.1...1.5.0
[1.4.1]: ../../compare/1.4.0...1.4.1
[1.4.0]: ../../compare/1.3.6...1.4.0
diff --git a/Directory.Build.props b/Directory.Build.props
index 019c277..19b00f1 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,5 +1,5 @@
- 1.5.0
+ 1.6.0
\ No newline at end of file
diff --git a/README.old.md b/README.old.md
index 6782573..2a1fdc3 100644
--- a/README.old.md
+++ b/README.old.md
@@ -69,7 +69,7 @@ For more information see [Wiki](https://github.com/ricaun-io/ricaun.RevitTest/wi
* [ricaun.RevitTest.Application.bundle.zip](ricaun.RevitTest.Application)
#### Shared
* [ricaun.NUnit](https://github.com/ricaun-io/ricaun.NUnit)
-* [NamedPipeWrapper.Json](https://github.com/ricaun-io/named-pipe-wrapper-json)
+* [ricaun.NamedPipeWrapper.Json](https://github.com/ricaun-io/named-pipe-wrapper-json)
#### TestAdapter
* [ricaun.RevitTest.Console.exe](ricaun.RevitTest.Console)
* [ricaun.RevitTest.Command](ricaun.RevitTest.Command)
@@ -131,6 +131,18 @@ dotnet test ricaun.RevitTest.Tests.dll --settings:.runsettings -- NUnit.Version=
dotnet test ricaun.RevitTest.Tests.dll -v:detailed -- NUnit.Application=""
```
+### Environment Variables
+```
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_VERSION
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_LANGUAGE
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_OPEN
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_CLOSE
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_TIMEOUT
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_VERBOSITY
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_APPLICATION
+RICAUN_REVITTEST_TESTADAPTER_NUNIT_METADATA
+```
+
### `.runsettings`
.csproj
```xml
diff --git a/ricaun.RevitTest.Application/Revit/App.cs b/ricaun.RevitTest.Application/Revit/App.cs
index c0ce3af..a289911 100644
--- a/ricaun.RevitTest.Application/Revit/App.cs
+++ b/ricaun.RevitTest.Application/Revit/App.cs
@@ -73,6 +73,22 @@ private static void PipeTestServer_Initialize()
response.Tests = null;
});
+ PipeTestServer.ClientDisconnected = () =>
+ {
+ try
+ {
+ if (IsTestRunning)
+ {
+ Log.WriteLine("PipeTestServer: ClientDisconnected - TestEngine.KillTests");
+ ricaun.NUnit.TestEngine.Result = new TestModelResult((test) =>
+ {
+ throw new Exception("Client disconnect, TestEngine.Kill to ignore test result.");
+ });
+ }
+ }
+ catch { }
+ };
+
var initializeServer = PipeTestServer.Initialize();
if (initializeServer)
diff --git a/ricaun.RevitTest.Command/Extensions/Json/IJsonService.cs b/ricaun.RevitTest.Command/Extensions/Json/IJsonService.cs
new file mode 100644
index 0000000..6347497
--- /dev/null
+++ b/ricaun.RevitTest.Command/Extensions/Json/IJsonService.cs
@@ -0,0 +1,23 @@
+namespace ricaun.RevitTest.Command.Extensions.Json
+{
+ ///
+ /// Represents a service for JSON serialization and deserialization.
+ ///
+ public interface IJsonService
+ {
+ ///
+ /// Deserializes the specified JSON string into an object of type T.
+ ///
+ /// The type of the object to deserialize.
+ /// The JSON string to deserialize.
+ /// The deserialized object of type T.
+ T Deserialize(string value);
+
+ ///
+ /// Serializes the specified object into a JSON string.
+ ///
+ /// The object to serialize.
+ /// The JSON string representation of the serialized object.
+ string Serialize(object value);
+ }
+}
\ No newline at end of file
diff --git a/ricaun.RevitTest.Command/Extensions/Json/JsonService.cs b/ricaun.RevitTest.Command/Extensions/Json/JsonService.cs
new file mode 100644
index 0000000..4082906
--- /dev/null
+++ b/ricaun.RevitTest.Command/Extensions/Json/JsonService.cs
@@ -0,0 +1,43 @@
+namespace ricaun.RevitTest.Command.Extensions.Json
+{
+#if NETFRAMEWORK
+ using System.Web.Script.Serialization;
+ internal class JsonService : IJsonService
+ {
+ public JsonService()
+ {
+ JavaScriptSerializer = new JavaScriptSerializer();
+ }
+ public JavaScriptSerializer JavaScriptSerializer { get; set; }
+ public T Deserialize(string value)
+ {
+ return JavaScriptSerializer.Deserialize(value);
+ }
+
+ public string Serialize(object value)
+ {
+ return JavaScriptSerializer.Serialize(value);
+ }
+ }
+#endif
+#if NET
+ using System.Text.Json;
+ internal class JsonService : IJsonService
+ {
+ public T Deserialize(string value)
+ {
+ return JsonSerializer.Deserialize(value);
+ }
+
+ public string Serialize(object value)
+ {
+ return JsonSerializer.Serialize(value);
+ }
+ }
+#endif
+#if NETSTANDARD
+internal class JsonService : NewtonsoftJsonService
+{
+}
+#endif
+}
\ No newline at end of file
diff --git a/ricaun.RevitTest.Command/Extensions/Json/NewtonsoftJsonService.cs b/ricaun.RevitTest.Command/Extensions/Json/NewtonsoftJsonService.cs
new file mode 100644
index 0000000..f94a5c5
--- /dev/null
+++ b/ricaun.RevitTest.Command/Extensions/Json/NewtonsoftJsonService.cs
@@ -0,0 +1,20 @@
+namespace ricaun.RevitTest.Command.Extensions.Json
+{
+ internal class NewtonsoftJsonService : IJsonService
+ {
+ public NewtonsoftJsonService()
+ {
+ Settings = new Newtonsoft.Json.JsonSerializerSettings();
+ }
+ public Newtonsoft.Json.JsonSerializerSettings Settings { get; }
+ public T Deserialize(string value)
+ {
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(value, Settings);
+ }
+
+ public string Serialize(object value)
+ {
+ return Newtonsoft.Json.JsonConvert.SerializeObject(value, Settings);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ricaun.RevitTest.Command/Extensions/JsonExtension.cs b/ricaun.RevitTest.Command/Extensions/JsonExtension.cs
index ed390ae..50c5777 100644
--- a/ricaun.RevitTest.Command/Extensions/JsonExtension.cs
+++ b/ricaun.RevitTest.Command/Extensions/JsonExtension.cs
@@ -1,98 +1,33 @@
-namespace ricaun.RevitTest.Command.Extensions
+using ricaun.RevitTest.Command.Extensions.Json;
+
+namespace ricaun.RevitTest.Command.Extensions
{
-#if NETFRAMEWORK
- using System.Web.Script.Serialization;
///
/// JsonExtension
- /// Reference Include="System.Web.Extensions"
///
public static class JsonExtension
{
- private static JavaScriptSerializer JavaScriptSerializer { get; set; } = new JavaScriptSerializer();
-
- ///
- /// Deserialize
- ///
- ///
- ///
- ///
- public static T Deserialize(this string value)
- {
- return JavaScriptSerializer.Deserialize(value);
- }
-
///
- /// Serialize
+ /// IJsonService
///
- ///
- ///
- public static string Serialize(object value)
- {
- return JavaScriptSerializer.Serialize(value);
- }
+ public static IJsonService JsonService { get; set; } = CreateJsonService();
///
- /// ToJson
+ /// Create JsonService
///
- ///
///
- public static string ToJson(this object value)
+ ///
+ /// If NewtonsoftJsonService is available, use it.
+ ///
+ private static IJsonService CreateJsonService()
{
- return Serialize(value);
+ try
+ {
+ return new NewtonsoftJsonService();
+ }
+ catch { };
+ return new JsonService();
}
- }
-#endif
-
-#if NETSTANDARD
- using Newtonsoft.Json;
- public static class JsonExtension
- {
- ///
- /// Settings
- ///
- public static JsonSerializerSettings Settings { get; set; } = new JsonSerializerSettings();
-
- ///
- /// Deserialize
- ///
- ///
- ///
- ///
- public static T Deserialize(this string value)
- {
- return JsonConvert.DeserializeObject(value, Settings);
- }
-
- ///
- /// Serialize
- ///
- ///
- ///
- public static string Serialize(object value)
- {
- return JsonConvert.SerializeObject(value, Settings);
- }
-
- ///
- /// ToJson
- ///
- ///
- ///
- public static string ToJson(this object value)
- {
- return Serialize(value);
- }
- }
-#endif
-
-#if NET
- using System.Text.Json;
- public static class JsonExtension
- {
- ///
- /// Settings
- ///
- public static JsonSerializerOptions Settings { get; set; } = new JsonSerializerOptions();
///
/// Deserialize
@@ -102,7 +37,7 @@ public static class JsonExtension
///
public static T Deserialize(this string value)
{
- return JsonSerializer.Deserialize(value, Settings);
+ return JsonService.Deserialize(value);
}
///
@@ -112,7 +47,7 @@ public static T Deserialize(this string value)
///
public static string Serialize(object value)
{
- return JsonSerializer.Serialize(value, Settings);
+ return JsonService.Serialize(value);
}
///
@@ -125,5 +60,4 @@ public static string ToJson(this object value)
return Serialize(value);
}
}
-#endif
}
\ No newline at end of file
diff --git a/ricaun.RevitTest.Command/Process/ProcessStart.cs b/ricaun.RevitTest.Command/Process/ProcessStart.cs
index 6ce0847..9f52729 100644
--- a/ricaun.RevitTest.Command/Process/ProcessStart.cs
+++ b/ricaun.RevitTest.Command/Process/ProcessStart.cs
@@ -10,6 +10,12 @@ namespace ricaun.RevitTest.Command.Process
{
public class ProcessStart
{
+ private static List Processes = new List();
+ public static System.Diagnostics.Process[] GetProcesses()
+ {
+ return Processes.OfType().Where(e => !e.HasExited).ToArray();
+ }
+
protected virtual void WriteLine(string message)
{
Debug.WriteLine(message);
@@ -99,6 +105,7 @@ private async Task Run(string arguments,
if (string.IsNullOrEmpty(processPath)) return;
var psi = NewProcessStartInfo(arguments);
var process = System.Diagnostics.Process.Start(psi);
+ Processes.Add(process);
process.OutputDataReceived += (sender, e) =>
{
consoleAction?.Invoke(e.Data);
diff --git a/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj b/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj
index da4013d..be4d7ad 100644
--- a/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj
+++ b/ricaun.RevitTest.Command/ricaun.RevitTest.Command.csproj
@@ -90,6 +90,12 @@
+
+
+ NU1903
+
+
+
diff --git a/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip b/ricaun.RevitTest.Console/Resources/ricaun.RevitTest.Application.bundle.zip
index b5e8079..94635c0 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/Utils/RevitTestUtils.cs b/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs
index e2611aa..940c663 100644
--- a/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs
+++ b/ricaun.RevitTest.Console/Revit/Utils/RevitTestUtils.cs
@@ -19,9 +19,6 @@ namespace ricaun.RevitTest.Console.Revit.Utils
///
public static class RevitTestUtils
{
- private const int RevitMinVersionReference = 2021;
- private const int RevitMaxVersionReference = 2023;
-
private const int SleepMillisecondsBeforeFinish = 1000;
private const int SleepMillisecondsDebuggerAttached = 1000;
@@ -40,22 +37,17 @@ public static string[] GetTestFullNames(string filePath)
Log.WriteLine($"RevitTestUtils: {revitVersion}");
LoggerTest($"RevitTestUtils: {revitVersion}");
- // Problem with AnavRes.dll / adui22res.dll (version -2020)
- // Problem with UI (version 2024)
- var revitVersionMinMax = Math.Min(Math.Max(revitVersion, RevitMinVersionReference), RevitMaxVersionReference);
- if (RevitInstallationUtils.InstalledRevit.TryGetRevitInstallationGreater(revitVersionMinMax, out RevitInstallation revitInstallationMinMax))
- {
- LoggerTest($"GetTest Version {revitVersionMinMax}");
- Log.WriteLine($"RevitTestUtils: {revitInstallationMinMax.InstallLocation}");
- tests = TestEngine.GetTestFullNames(filePath, revitInstallationMinMax.InstallLocation);
- }
- else if (RevitInstallationUtils.InstalledRevit.TryGetRevitInstallationGreater(revitVersion, out RevitInstallation revitInstallation))
+ if (RevitInstallationUtils.InstalledRevit.TryGetRevitInstallationGreater(revitVersion, out RevitInstallation revitInstallation))
{
LoggerTest($"GetTest Version {revitVersion}");
Log.WriteLine($"RevitTestUtils: {revitInstallation.InstallLocation}");
tests = TestEngine.GetTestFullNames(filePath, revitInstallation.InstallLocation);
}
+ foreach (var exception in TestEngine.Exceptions)
+ {
+ Log.WriteLine($"RevitTestUtils.Exceptions: {exception}");
+ }
if (tests.Length == 0)
{
throw new Exception($"Unable to read tests class using the Revit version {revitVersion}.");
@@ -111,7 +103,7 @@ public static void CreateRevitServer(
{
int timeoutNotBusyCountMax = 10;
- if (timeoutMinutes <= 0)
+ if (timeoutMinutes <= 0)
timeoutMinutes = TimeoutMinutesDefault;
if (revitVersionNumber == 0)
@@ -162,6 +154,7 @@ public static void CreateRevitServer(
if (revitInstallation.TryGetProcess(out Process process) == false || forceToOpenNewRevit)
{
var startRevitLanguageArgument = RevitLanguageUtils.GetArgument(forceLanguageToRevit);
+ startRevitLanguageArgument = string.Join(" ", startRevitLanguageArgument, Environment.GetEnvironmentVariable("RICAUN_REVITTEST_CONSOLE_PROCESS_ARGUMENTS"));
Log.WriteLine($"{revitInstallation}: Start {startRevitLanguageArgument}");
process = revitInstallation.Start(startRevitLanguageArgument);
}
diff --git a/ricaun.RevitTest.Console/ricaun.RevitTest.Console.csproj b/ricaun.RevitTest.Console/ricaun.RevitTest.Console.csproj
index c4d8cd4..54b73cc 100644
--- a/ricaun.RevitTest.Console/ricaun.RevitTest.Console.csproj
+++ b/ricaun.RevitTest.Console/ricaun.RevitTest.Console.csproj
@@ -48,6 +48,7 @@
+
diff --git a/ricaun.RevitTest.Shared/NamedPipeExtension.cs b/ricaun.RevitTest.Shared/NamedPipeExtension.cs
index 6fcd75e..da92351 100644
--- a/ricaun.RevitTest.Shared/NamedPipeExtension.cs
+++ b/ricaun.RevitTest.Shared/NamedPipeExtension.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper;
+using ricaun.NamedPipeWrapper;
using System;
using System.Diagnostics;
diff --git a/ricaun.RevitTest.Shared/PipeProcessClient.cs b/ricaun.RevitTest.Shared/PipeProcessClient.cs
index a97e426..a7c2ceb 100644
--- a/ricaun.RevitTest.Shared/PipeProcessClient.cs
+++ b/ricaun.RevitTest.Shared/PipeProcessClient.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper;
+using ricaun.NamedPipeWrapper;
using System;
namespace ricaun.RevitTest.Shared
diff --git a/ricaun.RevitTest.Shared/PipeProcessServer.cs b/ricaun.RevitTest.Shared/PipeProcessServer.cs
index ead9220..faba00e 100644
--- a/ricaun.RevitTest.Shared/PipeProcessServer.cs
+++ b/ricaun.RevitTest.Shared/PipeProcessServer.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper;
+using ricaun.NamedPipeWrapper;
using System;
using System.Diagnostics;
@@ -27,12 +27,20 @@ public bool Initialize()
namedPipe = new NamedPipeServer(pipeName);
namedPipe.ClientConnected += OnClientConnected;
namedPipe.ClientMessage += OnClientMessage;
+ namedPipe.ClientDisconnected += OnClientDisconnected;
namedPipe.NamedPipeDebug();
namedPipe.Start();
}
return namedPipe != null;
}
+ public Action ClientDisconnected { get; set; }
+
+ private void OnClientDisconnected(NamedPipeConnection connection)
+ {
+ ClientDisconnected?.Invoke();
+ }
+
public void Update(Action response)
{
if (ServerMessage is null) ServerMessage = new TServer();
diff --git a/ricaun.RevitTest.Shared/PipeTestServer.cs b/ricaun.RevitTest.Shared/PipeTestServer.cs
index 50281ae..ebd19d8 100644
--- a/ricaun.RevitTest.Shared/PipeTestServer.cs
+++ b/ricaun.RevitTest.Shared/PipeTestServer.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper;
+using ricaun.NamedPipeWrapper;
using System;
using System.Diagnostics;
diff --git a/ricaun.RevitTest.Shared/ProcessPipeNameUtils.cs b/ricaun.RevitTest.Shared/ProcessPipeNameUtils.cs
index 81be872..6919446 100644
--- a/ricaun.RevitTest.Shared/ProcessPipeNameUtils.cs
+++ b/ricaun.RevitTest.Shared/ProcessPipeNameUtils.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper;
+using ricaun.NamedPipeWrapper;
using System.Diagnostics;
namespace ricaun.RevitTest.Shared
diff --git a/ricaun.RevitTest.Shared/TestRequest.cs b/ricaun.RevitTest.Shared/TestRequest.cs
index 88291ef..19129af 100644
--- a/ricaun.RevitTest.Shared/TestRequest.cs
+++ b/ricaun.RevitTest.Shared/TestRequest.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper.Json;
+using ricaun.NamedPipeWrapper.Json;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
diff --git a/ricaun.RevitTest.Shared/TestResponse.cs b/ricaun.RevitTest.Shared/TestResponse.cs
index 5e9f6a0..4c43286 100644
--- a/ricaun.RevitTest.Shared/TestResponse.cs
+++ b/ricaun.RevitTest.Shared/TestResponse.cs
@@ -1,4 +1,4 @@
-using NamedPipeWrapper.Json;
+using ricaun.NamedPipeWrapper.Json;
using ricaun.NUnit.Models;
using System;
using System.ComponentModel;
diff --git a/ricaun.RevitTest.Shared/ricaun.RevitTest.Shared.csproj b/ricaun.RevitTest.Shared/ricaun.RevitTest.Shared.csproj
index 8868679..18ac533 100644
--- a/ricaun.RevitTest.Shared/ricaun.RevitTest.Shared.csproj
+++ b/ricaun.RevitTest.Shared/ricaun.RevitTest.Shared.csproj
@@ -64,7 +64,7 @@
-
+
diff --git a/ricaun.RevitTest.TestAdapter/Extensions/Json/JsonService.cs b/ricaun.RevitTest.TestAdapter/Extensions/Json/JsonService.cs
index 6da24b7..2d7bb34 100644
--- a/ricaun.RevitTest.TestAdapter/Extensions/Json/JsonService.cs
+++ b/ricaun.RevitTest.TestAdapter/Extensions/Json/JsonService.cs
@@ -8,7 +8,11 @@
///
internal class JsonService : IJsonService
{
- private static JavaScriptSerializer JavaScriptSerializer { get; set; } = new JavaScriptSerializer();
+ public JsonService()
+ {
+ JavaScriptSerializer = new JavaScriptSerializer();
+ }
+ public JavaScriptSerializer JavaScriptSerializer { get; set; }
public T Deserialize(string value)
{
return JavaScriptSerializer.Deserialize(value);
@@ -19,7 +23,8 @@ public string Serialize(object value)
return JavaScriptSerializer.Serialize(value);
}
}
-#else
+#endif
+#if NET
using System.Text.Json;
internal class JsonService : IJsonService
{
diff --git a/ricaun.RevitTest.TestAdapter/Extensions/Json/NewtonsoftJsonService.cs b/ricaun.RevitTest.TestAdapter/Extensions/Json/NewtonsoftJsonService.cs
new file mode 100644
index 0000000..490a49a
--- /dev/null
+++ b/ricaun.RevitTest.TestAdapter/Extensions/Json/NewtonsoftJsonService.cs
@@ -0,0 +1,20 @@
+namespace ricaun.RevitTest.TestAdapter.Extensions.Json
+{
+ internal class NewtonsoftJsonService : IJsonService
+ {
+ public NewtonsoftJsonService()
+ {
+ Settings = new Newtonsoft.Json.JsonSerializerSettings();
+ }
+ public Newtonsoft.Json.JsonSerializerSettings Settings { get; }
+ public T Deserialize(string value)
+ {
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(value, Settings);
+ }
+
+ public string Serialize(object value)
+ {
+ return Newtonsoft.Json.JsonConvert.SerializeObject(value, Settings);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ricaun.RevitTest.TestAdapter/Extensions/JsonExtension.cs b/ricaun.RevitTest.TestAdapter/Extensions/JsonExtension.cs
index 73d8894..5b8e398 100644
--- a/ricaun.RevitTest.TestAdapter/Extensions/JsonExtension.cs
+++ b/ricaun.RevitTest.TestAdapter/Extensions/JsonExtension.cs
@@ -6,7 +6,27 @@
///
internal static class JsonExtension
{
- private static IJsonService jsonService { get; set; } = new JsonService();
+ ///
+ /// IJsonService
+ ///
+ public static IJsonService JsonService { get; set; } = CreateJsonService();
+
+ ///
+ /// Create JsonService
+ ///
+ ///
+ ///
+ /// If NewtonsoftJsonService is available, use it.
+ ///
+ private static IJsonService CreateJsonService()
+ {
+ try
+ {
+ return new NewtonsoftJsonService();
+ }
+ catch { };
+ return new JsonService();
+ }
///
/// Deserialize
@@ -16,7 +36,7 @@ internal static class JsonExtension
///
public static T Deserialize(this string value)
{
- return jsonService.Deserialize(value);
+ return JsonService.Deserialize(value);
}
///
@@ -26,7 +46,7 @@ public static T Deserialize(this string value)
///
public static string Serialize(object value)
{
- return jsonService.Serialize(value);
+ return JsonService.Serialize(value);
}
///
diff --git a/ricaun.RevitTest.TestAdapter/Extensions/ProcessExtension.cs b/ricaun.RevitTest.TestAdapter/Extensions/ProcessExtension.cs
new file mode 100644
index 0000000..85b4c9d
--- /dev/null
+++ b/ricaun.RevitTest.TestAdapter/Extensions/ProcessExtension.cs
@@ -0,0 +1,138 @@
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+namespace ricaun.RevitTest.TestAdapter.Extensions
+{
+ internal static class ProcessExtension
+ {
+ ///
+ /// Kill
+ ///
+ ///
+ ///
+ public static void Kill(this Process process, bool entireProcessTree)
+ {
+ if (process is null) return;
+
+ if (!entireProcessTree)
+ {
+ process.Kill();
+ return;
+ }
+
+ process.KillTree();
+ }
+
+ #region KillTree
+ private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+ private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);
+
+ ///
+ /// KillTree
+ ///
+ ///
+ ///
+ /// https://github.com/dotnet/cli/blob/master/test/Microsoft.DotNet.Tools.Tests.Utilities/Extensions/ProcessExtensions.cs
+ ///
+ internal static void KillTree(this Process process)
+ {
+ process.KillTree(_defaultTimeout);
+ }
+
+ private static void KillTree(this Process process, TimeSpan timeout)
+ {
+ string stdout;
+ if (_isWindows)
+ {
+ RunProcessAndWaitForExit(
+ "taskkill",
+ $"/T /F /PID {process.Id}",
+ timeout,
+ out stdout);
+ }
+ else
+ {
+ var children = new HashSet();
+ GetAllChildIdsUnix(process.Id, children, timeout);
+ foreach (var childId in children)
+ {
+ KillProcessUnix(childId, timeout);
+ }
+ KillProcessUnix(process.Id, timeout);
+ }
+ }
+
+ private static void GetAllChildIdsUnix(int parentId, ISet children, TimeSpan timeout)
+ {
+ string stdout;
+ var exitCode = RunProcessAndWaitForExit(
+ "pgrep",
+ $"-P {parentId}",
+ timeout,
+ out stdout);
+
+ if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
+ {
+ using (var reader = new StringReader(stdout))
+ {
+ while (true)
+ {
+ var text = reader.ReadLine();
+ if (text == null)
+ {
+ return;
+ }
+
+ int id;
+ if (int.TryParse(text, out id))
+ {
+ children.Add(id);
+ // Recursively get the children
+ GetAllChildIdsUnix(id, children, timeout);
+ }
+ }
+ }
+ }
+ }
+
+ private static void KillProcessUnix(int processId, TimeSpan timeout)
+ {
+ string stdout;
+ RunProcessAndWaitForExit(
+ "kill",
+ $"-TERM {processId}",
+ timeout,
+ out stdout);
+ }
+
+ private static int RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = fileName,
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ UseShellExecute = false
+ };
+
+ var process = Process.Start(startInfo);
+
+ stdout = null;
+ if (process.WaitForExit((int)timeout.TotalMilliseconds))
+ {
+ stdout = process.StandardOutput.ReadToEnd();
+ }
+ else
+ {
+ process.Kill();
+ }
+
+ return process.ExitCode;
+ }
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/ricaun.RevitTest.TestAdapter/Metadatas/EnvironmentSettings.cs b/ricaun.RevitTest.TestAdapter/Metadatas/EnvironmentSettings.cs
new file mode 100644
index 0000000..d2ac584
--- /dev/null
+++ b/ricaun.RevitTest.TestAdapter/Metadatas/EnvironmentSettings.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+
+namespace ricaun.RevitTest.TestAdapter.Metadatas
+{
+ internal static class EnvironmentSettings
+ {
+ ///
+ /// Apply the environment settings.
+ ///
+ public static void Create()
+ {
+ try
+ {
+ var environmentDictionary = new Dictionary();
+ var environmentKeyNames = GetEnvironmentKeyNames();
+ foreach (var environmentKeyName in environmentKeyNames)
+ {
+ var environmentName = environmentKeyName.Value;
+ var value = Environment.GetEnvironmentVariable(environmentName);
+
+ AdapterLogger.Logger.DebugOnlyLocal($"\tEnvironment: {environmentName} \t {value}");
+
+ if (value is null)
+ continue;
+
+ environmentDictionary[environmentKeyName.Key] = value;
+ AdapterLogger.Logger.Info($"Environment: {environmentName}");
+ }
+
+ MapperKey.Map(AdapterSettings.Settings, environmentDictionary);
+
+ AdapterLogger.Logger.DebugOnlyLocal($"\tAdapterSettings: {AdapterSettings.Settings}");
+ }
+ catch (Exception ex)
+ {
+ AdapterLogger.Logger.InfoAny($"Environment: {ex}");
+ }
+ }
+
+ ///
+ /// Gets the environment names.
+ ///
+ /// The environment names.
+ ///
+ /// NUnit.Version -> RICAUN_REVITTEST_TESTADAPTER_NUNIT_VERSION
+ ///
+ public static IEnumerable GetEnvironmentNames()
+ {
+ return GetEnvironmentKeyNames().Values;
+ }
+
+ ///
+ /// Gets the environment key names.
+ ///
+ /// The environment key names.
+ ///
+ /// NUnit.Version -> RICAUN_REVITTEST_TESTADAPTER_NUNIT_VERSION
+ ///
+ internal static Dictionary GetEnvironmentKeyNames()
+ {
+ var result = new Dictionary();
+ var assemblyName = typeof(EnvironmentSettings).Assembly.GetName().Name;
+ var names = MapperKey.GetNames(AdapterSettings.Settings);
+ foreach (var name in names)
+ {
+ var fullName = $"{assemblyName}.{name}";
+ result[name] = ConvertToEnvironmentName(fullName);
+ }
+ return result;
+ }
+
+ ///
+ /// Converts the name to environment name.
+ ///
+ /// The name to convert.
+ /// The converted environment name.
+ private static string ConvertToEnvironmentName(string name)
+ {
+ return name.Replace(".", "_").ToUpper();
+ }
+ }
+}
diff --git a/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip b/ricaun.RevitTest.TestAdapter/Resources/net48/ricaun.RevitTest.Console.zip
index 55793f3..d1ec630 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 52c6a11..5eaa589 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 86f85b1..b3adca4 100644
--- a/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs
+++ b/ricaun.RevitTest.TestAdapter/Services/RevitTestConsole.cs
@@ -15,11 +15,11 @@ private string GetEnvironmentVariable(string applicationPath)
{
try
{
- var enviromentVariable = Environment.GetEnvironmentVariable(applicationPath);
- if (!string.IsNullOrEmpty(enviromentVariable))
+ var environmentVariable = Environment.GetEnvironmentVariable(applicationPath);
+ if (!string.IsNullOrEmpty(environmentVariable))
{
- AdapterLogger.Logger.Info($"Application Environment: {Path.GetFileName(enviromentVariable)}");
- return enviromentVariable;
+ AdapterLogger.Logger.Info($"Application Environment: {Path.GetFileName(environmentVariable)}");
+ return environmentVariable;
}
}
catch { }
diff --git a/ricaun.RevitTest.TestAdapter/TestAdapter.cs b/ricaun.RevitTest.TestAdapter/TestAdapter.cs
index b3ad238..b7f9f6a 100644
--- a/ricaun.RevitTest.TestAdapter/TestAdapter.cs
+++ b/ricaun.RevitTest.TestAdapter/TestAdapter.cs
@@ -5,6 +5,7 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
+using ricaun.RevitTest.TestAdapter.Metadatas;
using ricaun.RevitTest.TestAdapter.Models;
using ricaun.RevitTest.TestAdapter.Services;
using System;
@@ -40,6 +41,7 @@ protected TestAdapter()
protected void Initialize(IDiscoveryContext discoveryContext, IMessageLogger messageLogger)
{
AdapterSettings.Create(discoveryContext);
+ EnvironmentSettings.Create();
AdapterLogger.Create(messageLogger, AdapterSettings.Settings.NUnit.Verbosity);
AdapterLogger.Logger.InfoAny($"TestAdapter: {this.AdapterVersion}");
@@ -55,7 +57,7 @@ protected void Initialize(IDiscoveryContext discoveryContext, IMessageLogger mes
AdapterLogger.Logger.DebugOnlyLocal($"\tTestAdapter: {this.AdapterVersion}");
AdapterLogger.Logger.DebugOnlyLocal($"\tAdapterSettings: {AdapterSettings.Settings}");
- var collection = Metadatas.XmlUtils.ParseKeyValues(discoveryContext.RunSettings.SettingsXml);
+ var collection = XmlUtils.ParseKeyValues(discoveryContext.RunSettings.SettingsXml);
foreach (var item in collection)
{
AdapterLogger.Logger.DebugOnlyLocal($"\t{item.Key}: {item.Value}");
@@ -63,10 +65,20 @@ protected void Initialize(IDiscoveryContext discoveryContext, IMessageLogger mes
AdapterLogger.Logger.DebugOnlyLocal("-");
- foreach (var item in Metadatas.MapperKey.GetNames(AdapterSettings.Instance))
+ foreach (var item in MapperKey.GetNames(AdapterSettings.Instance))
{
AdapterLogger.Logger.DebugOnlyLocal($"\t{item}");
}
+
+ AdapterLogger.Logger.DebugOnlyLocal("-");
+
+ foreach (var item in EnvironmentSettings.GetEnvironmentNames())
+ {
+ AdapterLogger.Logger.DebugOnlyLocal($"\tEnvironment: {item}");
+ }
+
+ //Environment.SetEnvironmentVariable("RICAUN_REVITTEST_TESTADAPTER_NUNIT_VERBOSITY", "3");
+
AdapterLogger.Logger.DebugOnlyLocal("-DEBUG-");
//var RunSettings = Metadatas.Mapper.Map(collection, new RunSettingsModel());
diff --git a/ricaun.RevitTest.TestAdapter/TestDiscoverer.cs b/ricaun.RevitTest.TestAdapter/TestDiscoverer.cs
index aeaddb0..342a059 100644
--- a/ricaun.RevitTest.TestAdapter/TestDiscoverer.cs
+++ b/ricaun.RevitTest.TestAdapter/TestDiscoverer.cs
@@ -2,6 +2,7 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
using ricaun.RevitTest.TestAdapter.Extensions;
+using ricaun.RevitTest.TestAdapter.Metadatas;
using ricaun.RevitTest.TestAdapter.Services;
using System;
using System.Collections.Generic;
@@ -44,7 +45,8 @@ internal static List GetTests(
{
foreach (var source in sources)
{
- Metadatas.MetadataSettings.Create(source);
+ MetadataSettings.Create(source);
+ EnvironmentSettings.Create();
AdapterLogger.Logger.Info($"DiscoverTests: {source}");
using (var revit = new RevitTestConsole(AdapterSettings.Settings.NUnit.Application, source))
diff --git a/ricaun.RevitTest.TestAdapter/TestExecutor.cs b/ricaun.RevitTest.TestAdapter/TestExecutor.cs
index 5dc83d1..a9d8c65 100644
--- a/ricaun.RevitTest.TestAdapter/TestExecutor.cs
+++ b/ricaun.RevitTest.TestAdapter/TestExecutor.cs
@@ -1,10 +1,13 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using ricaun.NUnit.Models;
+using ricaun.RevitTest.TestAdapter.Extensions;
+using ricaun.RevitTest.TestAdapter.Metadatas;
using ricaun.RevitTest.TestAdapter.Services;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
namespace ricaun.RevitTest.TestAdapter
@@ -60,10 +63,44 @@ public void RunTests(IEnumerable sources, IRunContext runContext, IFrame
task.GetAwaiter().GetResult();
}
- public void Cancel()
+ #region Cancel
+ ///
+ /// Force to cancel `RunTests` if process exit
+ ///
+ private void InitializeCancel()
+ {
+ AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
+ }
+
+ private void FinishCancel()
{
+ AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_ProcessExit;
}
+ private void CurrentDomain_ProcessExit(object sender, EventArgs e)
+ {
+ Cancel();
+ }
+
+ ///
+ /// Cancel force to kill process.
+ ///
+ public void Cancel()
+ {
+ FinishCancel();
+ try
+ {
+ foreach (var process in ricaun.RevitTest.Command.Process.ProcessStart.GetProcesses())
+ {
+ process.Kill(true);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.IO.File.WriteAllText($"{this.GetType().Assembly.GetName().Name}.Exception.txt", ex.ToString());
+ }
+ }
+ #endregion
private static bool IsLogDebug => System.Diagnostics.Debugger.IsAttached || AdapterSettings.Settings.NUnit.Verbosity > 2;
///
@@ -75,6 +112,8 @@ public void Cancel()
///
private async Task RunTests(IFrameworkHandle frameworkHandle, string source, List tests = null)
{
+ InitializeCancel();
+
tests = tests ?? new List();
AdapterLogger.Logger.Info($"RunTest: {source} [TestCase: {tests.Count}]");
@@ -82,7 +121,8 @@ private async Task RunTests(IFrameworkHandle frameworkHandle, string source, Lis
{
AdapterLogger.Logger.Info($"Test: {test.FullyQualifiedName}.{test.DisplayName}");
}
- Metadatas.MetadataSettings.Create(source);
+ MetadataSettings.Create(source);
+ EnvironmentSettings.Create();
AdapterLogger.Logger.Info("---------");
AdapterLogger.Logger.Info($"RevitTestConsole: {AdapterSettings.Settings.NUnit.Application}");
@@ -112,12 +152,14 @@ private async Task RunTests(IFrameworkHandle frameworkHandle, string source, Lis
AdapterSettings.Settings.NUnit.Open,
AdapterSettings.Settings.NUnit.Close,
AdapterSettings.Settings.NUnit.Timeout,
- AdapterLogger.Logger.Debug, (message) => { if (IsLogDebug) AdapterLogger.Logger.Debug(message); }, AdapterLogger.Logger.Warning,
+ AdapterLogger.Logger.Debug, (message) => { if (IsLogDebug) AdapterLogger.Logger.Debug(message); }, AdapterLogger.Logger.Warning,
filters);
}
AdapterLogger.Logger.Info("---------");
+
+ FinishCancel();
}
private static void RecordResultTestModel(IFrameworkHandle frameworkHandle, string source, List tests, TestModel testModel)
@@ -131,6 +173,7 @@ private static void RecordResultTestModel(IFrameworkHandle frameworkHandle, stri
AdapterLogger.Logger.Info($"\tTestCase: {testCase} [{testCase.DisplayName}] \t{testCase.Id}");
+ testCase.LocalExtensionData = testModel;
var testResult = new TestResult(testCase);
testResult.Outcome = TestOutcome.Failed;
diff --git a/ricaun.RevitTest.TestAdapter/ricaun.RevitTest.TestAdapter.csproj b/ricaun.RevitTest.TestAdapter/ricaun.RevitTest.TestAdapter.csproj
index e153177..5c5d860 100644
--- a/ricaun.RevitTest.TestAdapter/ricaun.RevitTest.TestAdapter.csproj
+++ b/ricaun.RevitTest.TestAdapter/ricaun.RevitTest.TestAdapter.csproj
@@ -50,6 +50,12 @@
+
+
+ NU1903
+
+
+
@@ -156,5 +162,5 @@
-
+
diff --git a/ricaun.RevitTest.Tests/TestsRevitUI.cs b/ricaun.RevitTest.Tests/TestsRevitUI.cs
new file mode 100644
index 0000000..6228767
--- /dev/null
+++ b/ricaun.RevitTest.Tests/TestsRevitUI.cs
@@ -0,0 +1,39 @@
+using Autodesk.Revit.ApplicationServices;
+using Autodesk.Revit.UI;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace ricaun.RevitTest.Tests
+{
+ public class TestsRevitUI
+ {
+ static IEnumerable GetTypes()
+ {
+ yield return typeof(UIApplication);
+ yield return typeof(Application);
+ yield return typeof(UIFramework.RevitRibbonControl);
+ yield return typeof(Autodesk.Windows.RibbonControl);
+ }
+ [TestCaseSource(nameof(GetTypes))]
+ public void TestTypes(Type type)
+ {
+ Console.WriteLine(type);
+ }
+
+#if DEBUG
+ static IEnumerable GetAssemblyTypes()
+ {
+ return GetTypes().Select(t => t.Assembly);
+ }
+
+ [TestCaseSource(nameof(GetAssemblyTypes))]
+ public void TestAssemblyTypes(Assembly assembly)
+ {
+ Console.WriteLine(assembly);
+ }
+#endif
+ }
+}
\ No newline at end of file