diff --git a/.linting/roslynator.ruleset b/.linting/roslynator.ruleset index 52a4ec943..c4cf0dcbf 100644 --- a/.linting/roslynator.ruleset +++ b/.linting/roslynator.ruleset @@ -30,6 +30,7 @@ Just add ruleset file to a solution and open it. + diff --git a/src/App/NetDaemon.App/Common/NetDaemonAppBase.cs b/src/App/NetDaemon.App/Common/NetDaemonAppBase.cs index 7d801d038..6bc0a2742 100644 --- a/src/App/NetDaemon.App/Common/NetDaemonAppBase.cs +++ b/src/App/NetDaemon.App/Common/NetDaemonAppBase.cs @@ -309,6 +309,11 @@ public void ListenServiceCall(string domain, string service, Func public void Log(LogLevel level, string message, params object[] param) { + if (Logger is null) + { + return; + } + if (param.Length > 0) { var result = param.Prepend(Id).ToArray(); diff --git a/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs b/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs index 10d391b6d..b08716288 100644 --- a/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs +++ b/src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs @@ -644,7 +644,7 @@ public async Task Stop() } /// - [SuppressMessage("", "1031")] + [SuppressMessage("", "CA1031")] public async Task UnloadAllApps() { Logger.LogTrace("Unloading all apps ({instances}, {running})", InternalAllAppInstances.Count, InternalRunningAppInstances.Count); diff --git a/tests/NetDaemon.Daemon.Tests/Daemon/DataRepositoryTests.cs b/tests/NetDaemon.Daemon.Tests/Daemon/DataRepositoryTests.cs index 31286a7f2..08aa24e0c 100644 --- a/tests/NetDaemon.Daemon.Tests/Daemon/DataRepositoryTests.cs +++ b/tests/NetDaemon.Daemon.Tests/Daemon/DataRepositoryTests.cs @@ -41,7 +41,7 @@ public async Task SavedDataShouldReturnSameDataUsingExpando() data.Item = "Some data"; // ACT - await daemon.SaveDataAsync("data_exists", data); + await daemon.SaveDataAsync("data_exists", data).ConfigureAwait(false); var collectedData = await daemon.GetDataAsync("data_exists").ConfigureAwait(false); // ASSERT @@ -76,7 +76,7 @@ public async Task RepositoryLoadSavedDataUsingExpando() dataBeingSaved.SomeDateTime = DateTime.Now; // ACT - await dataRepository.Save>("RepositoryLoadSavedData_id", dataBeingSaved); + await dataRepository.Save>("RepositoryLoadSavedData_id", dataBeingSaved).ConfigureAwait(false); var dataReturned = await dataRepository.Get>("RepositoryLoadSavedData_id").ConfigureAwait(false); var returnedFluentExpandoObject = new FluentExpandoObject(); @@ -84,13 +84,8 @@ public async Task RepositoryLoadSavedDataUsingExpando() dynamic dynamicDataReturned = returnedFluentExpandoObject; - if (dataBeingSaved.SomeString == dynamicDataReturned?.SomeString) - { - System.Console.WriteLine("hello"); - } - // ASSERT - Assert.Equal(dataBeingSaved.SomeString, dynamicDataReturned?.SomeString); + Assert.Equal(dataBeingSaved.SomeString, dynamicDataReturned.SomeString); Assert.Equal(dataBeingSaved.SomeInt, dynamicDataReturned!.SomeInt); Assert.Equal(dataBeingSaved.SomeFloat, dynamicDataReturned!.SomeFloat); // There is no way for json serializer to know this is a datetime diff --git a/tests/NetDaemon.Daemon.Tests/Daemon/HttpTests.cs b/tests/NetDaemon.Daemon.Tests/Daemon/HttpTests.cs index e0392f5db..dabcce3b5 100644 --- a/tests/NetDaemon.Daemon.Tests/Daemon/HttpTests.cs +++ b/tests/NetDaemon.Daemon.Tests/Daemon/HttpTests.cs @@ -15,10 +15,6 @@ public class SerializedReturn public class HttpTests : DaemonHostTestBase { - public HttpTests() : base() - { - } - [Fact] public async Task HttpClientShouldReturnCorrectContent() { @@ -84,7 +80,7 @@ public async Task HttpHandlerGetJsonShouldReturnCorrectContent() // ARRANGE const string? response = "{\"json_prop\": \"hello world\"}"; - HttpClientFactoryMock factoryMock = new(); + using HttpClientFactoryMock factoryMock = new(); factoryMock.SetResponse(response); var httpHandler = new HttpHandler(factoryMock.Object); @@ -102,7 +98,7 @@ public void HttpHandlerGetJsonBadFormatShouldReturnThrowException() // ARRANGE const string? response = "{\"json_prop\": \"hello world\"}"; - HttpClientFactoryMock factoryMock = new(); + using HttpClientFactoryMock factoryMock = new(); factoryMock.SetResponse(response); var httpHandler = new HttpHandler(factoryMock.Object); @@ -117,7 +113,7 @@ public async Task HttpHandlerPostJsonShouldReturnCorrectContent() // ARRANGE const string? response = "{\"json_prop\": \"hello world\"}"; - HttpClientFactoryMock factoryMock = new(); + using HttpClientFactoryMock factoryMock = new(); factoryMock.SetResponse(response); var httpHandler = new HttpHandler(factoryMock.Object); @@ -127,7 +123,7 @@ public async Task HttpHandlerPostJsonShouldReturnCorrectContent() // ASSERT Assert.Equal("hello world", result?.Property); - Assert.Equal("{\"posted\":\"some value\"}", factoryMock?.MessageHandler?.RequestContent); + Assert.Equal("{\"posted\":\"some value\"}", factoryMock.MessageHandler?.RequestContent); } [Fact] @@ -136,7 +132,7 @@ public async Task HttpHandlerPostJsonNoReturnShouldReturnCorrectContent() // ARRANGE const string? response = "{\"json_prop\": \"hello world\"}"; - HttpClientFactoryMock factoryMock = new(); + using HttpClientFactoryMock factoryMock = new(); factoryMock.SetResponse(response); var httpHandler = new HttpHandler(factoryMock.Object); @@ -145,7 +141,7 @@ public async Task HttpHandlerPostJsonNoReturnShouldReturnCorrectContent() await httpHandler.PostJson("http://fake.com", new { posted = "some value" }).ConfigureAwait(false); // ASSERT - Assert.Equal("{\"posted\":\"some value\"}", factoryMock?.MessageHandler?.RequestContent); + Assert.Equal("{\"posted\":\"some value\"}", factoryMock.MessageHandler?.RequestContent); } } } \ No newline at end of file diff --git a/tests/NetDaemon.Daemon.Tests/Daemon/NetDaemonHostTests.cs b/tests/NetDaemon.Daemon.Tests/Daemon/NetDaemonHostTests.cs index 788ca1a70..dd3eb91f8 100644 --- a/tests/NetDaemon.Daemon.Tests/Daemon/NetDaemonHostTests.cs +++ b/tests/NetDaemon.Daemon.Tests/Daemon/NetDaemonHostTests.cs @@ -9,6 +9,7 @@ using Xunit; using NetDaemon.Daemon.Fakes; using NetDaemon.Daemon.Tests.DaemonRunner.App; +using System.Diagnostics.CodeAnalysis; namespace NetDaemon.Daemon.Tests.Daemon { @@ -157,7 +158,7 @@ public async Task SendEventShouldCallCorrectMethod() var eventData = DaemonHostTestBase.GetDynamicDataObject(); // ACT - await DefaultDaemonHost.SendEvent("test_event", eventData); + await DefaultDaemonHost.SendEvent("test_event", eventData).ConfigureAwait(false); await RunFakeDaemonUntilTimeout().ConfigureAwait(false); @@ -372,6 +373,7 @@ public async Task CallServiceEventShouldCallCorrectFunction() } [Fact] + [SuppressMessage("", "CA1508")] public async Task CallServiceEventOtherShouldNotCallFunction() { // ARRANGE @@ -381,7 +383,7 @@ public async Task CallServiceEventOtherShouldNotCallFunction() DefaultHassClientMock.AddCallServiceEvent("custom_domain", "other_service", dynObject); var isCalled = false; - string? message = ""; + string? message = null; DefaultDaemonHost.ListenServiceCall("custom_domain", "any_service", data => { diff --git a/tests/NetDaemon.Daemon.Tests/DaemonRunner/Api/ApiTests.cs b/tests/NetDaemon.Daemon.Tests/DaemonRunner/Api/ApiTests.cs index f9736b46a..7597881b5 100644 --- a/tests/NetDaemon.Daemon.Tests/DaemonRunner/Api/ApiTests.cs +++ b/tests/NetDaemon.Daemon.Tests/DaemonRunner/Api/ApiTests.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using JoySoftware.HomeAssistant.Client; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -11,35 +10,35 @@ using NetDaemon.Common; using NetDaemon.Common.Reactive; using NetDaemon.Daemon.Storage; -using NetDaemon.Daemon.Tests.Daemon; using NetDaemon.Service.Api; using Xunit; using System.Threading; -using System.Text.Unicode; using System.Text; using System.Net.WebSockets; using System.IO; using System.Text.Json; -using System.Collections.Generic; using System.Linq; using NetDaemon.Common.Configuration; using NetDaemon.Daemon.Fakes; using NetDaemon.Common.Exceptions; +using System.Diagnostics.CodeAnalysis; namespace NetDaemon.Daemon.Tests.DaemonRunner.Api { - public class ApiFakeStartup + public class ApiFakeStartup : IAsyncLifetime, IDisposable { + private readonly Mock _defaultMockedRxApp; private readonly Common.NetDaemonApp _defaultDaemonApp; private readonly Common.NetDaemonApp _defaultDaemonApp2; private readonly BaseTestRxApp _defaultDaemonRxApp; - private readonly Mock _defaultMockedRxApp; private readonly NetDaemonHost _defaultDaemonHost; + private readonly HttpHandlerMock _defaultHttpHandlerMock; private readonly LoggerMock _loggerMock; private readonly Mock _defaultDataRepositoryMock; private readonly HassClientMock _defaultHassClientMock; - private readonly HttpHandlerMock _defaultHttpHandlerMock; + private bool disposedValue; + public IConfiguration Configuration { get; } public ApiFakeStartup(IConfiguration configuration) @@ -93,10 +92,10 @@ public void ConfigureServices(IServiceCollection services) services.Configure(Configuration.GetSection("HomeAssistant")); services.Configure(Configuration.GetSection("NetDaemon")); - services.AddTransient(_ => _defaultHassClientMock.Object); - services.AddTransient(_ => _defaultDataRepositoryMock.Object); - services.AddTransient(); - services.AddSingleton(_ => _defaultDaemonHost); + services.AddTransient(_ => _defaultHassClientMock.Object); + services.AddTransient(_ => _defaultDataRepositoryMock.Object); + services.AddTransient(); + services.AddSingleton(_ => _defaultDaemonHost); services.AddHttpClient(); } @@ -111,8 +110,42 @@ public static void Configure(IApplicationBuilder app, IWebHostEnvironment _) app.UseWebSockets(webSocketOptions); app.UseMiddleware(); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + _defaultHttpHandlerMock.Dispose(); + } + + disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + public Task InitializeAsync() + { + return Task.CompletedTask; + } + + public async Task DisposeAsync() + { + await _defaultDaemonApp.DisposeAsync().ConfigureAwait(false); + await _defaultDaemonApp2.DisposeAsync().ConfigureAwait(false); + await _defaultDaemonRxApp.DisposeAsync().ConfigureAwait(false); + await _defaultDaemonHost.DisposeAsync().ConfigureAwait(false); + } } - public class ApiTests : IAsyncLifetime + + public class ApiTests : IAsyncLifetime, IDisposable { // protected readonly EventQueueManager EventQueueManager; private readonly TestServer _server; @@ -121,6 +154,7 @@ public class ApiTests : IAsyncLifetime { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + private bool disposedValue; public ArraySegment Buffer { get; } @@ -145,6 +179,7 @@ public Task InitializeAsync() return Task.CompletedTask; } + [SuppressMessage("", "CA2201")] private static async Task ReadString(WebSocket ws) { var buffer = new ArraySegment(new byte[8192]); @@ -226,5 +261,25 @@ public async Task TestGetConfig() Assert.NotNull(response?.DaemonSettings?.AppSource); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + _server.Dispose(); + } + + disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } \ No newline at end of file diff --git a/tests/NetDaemon.Daemon.Tests/FakesTests/FakeTests.cs b/tests/NetDaemon.Daemon.Tests/FakesTests/FakeTests.cs index 557581086..db7a2ccdd 100644 --- a/tests/NetDaemon.Daemon.Tests/FakesTests/FakeTests.cs +++ b/tests/NetDaemon.Daemon.Tests/FakesTests/FakeTests.cs @@ -1,5 +1,6 @@ using System; using System.Dynamic; +using System.Globalization; using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; @@ -262,7 +263,7 @@ public async Task UsingEntitiesLambdaNewEventShouldCallFunction() var called = false; // ACT - DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir")) + DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir", true, CultureInfo.InvariantCulture)) .StateChanges .Subscribe(_ => called = true); @@ -283,7 +284,7 @@ public async Task CallbackObserverAttributeMissingShouldReturnNull() string? missingString = "has initial value"; // ACT - DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir")) + DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir", true, CultureInfo.InvariantCulture)) .StateChanges .Subscribe(s => missingString = s.New.Attribute?.missing_attribute); @@ -411,7 +412,8 @@ public async Task GetDataShouldReturnCachedValue() public async Task TestFakeAppTurnOnCorrectLight() { // Add the app to test - await AddAppInstance(new FakeApp()).ConfigureAwait(false); + await using var fakeApp = new FakeApp(); + await AddAppInstance(fakeApp).ConfigureAwait(false); // Init NetDaemon core runtime await InitializeFakeDaemon().ConfigureAwait(false); @@ -430,7 +432,8 @@ public async Task TestFakeAppTurnOnCorrectLight() public async Task TestFakeAppCallNoteWhenBatteryLevelBelowValue() { // Add the app to test - await AddAppInstance(new FakeApp()).ConfigureAwait(false); + await using var fakeApp = new FakeApp(); + await AddAppInstance(fakeApp).ConfigureAwait(false); // Init NetDaemon core runtime await InitializeFakeDaemon().ConfigureAwait(false); diff --git a/tests/NetDaemon.Daemon.Tests/Fluent/FluentCameraTests.cs b/tests/NetDaemon.Daemon.Tests/Fluent/FluentCameraTests.cs index 49eedd308..1b0e4934a 100644 --- a/tests/NetDaemon.Daemon.Tests/Fluent/FluentCameraTests.cs +++ b/tests/NetDaemon.Daemon.Tests/Fluent/FluentCameraTests.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Moq; @@ -106,8 +107,8 @@ await DefaultDaemonApp public async Task CameraPlayStreamCallsCorrectServiceCall() { // ARRANGE - const string? entityId = "camera.camera1"; - const string? service_call = "play_stream"; + const string? entityId = "camera.camera1"; + const string? service_call = "play_stream"; // ACT await DefaultDaemonApp @@ -128,8 +129,8 @@ await DefaultDaemonApp public async Task CameraRecordCallsCorrectServiceCall() { // ARRANGE - const string? entityId = "camera.camera1"; - const string? service_call = "record"; + const string? entityId = "camera.camera1"; + const string? service_call = "record"; // ACT await DefaultDaemonApp @@ -151,8 +152,8 @@ await DefaultDaemonApp public async Task CameraSnapshotCallsCorrectServiceCall() { // ARRANGE - const string? entityId = "camera.camera1"; - const string? service_call = "snapshot"; + const string? entityId = "camera.camera1"; + const string? service_call = "snapshot"; // ACT await DefaultDaemonApp @@ -172,8 +173,8 @@ await DefaultDaemonApp public async Task CameraTurnOnCallsCorrectServiceCall() { // ARRANGE - const string? entityId = "camera.camera1"; - const string? service_call = "turn_on"; + const string? entityId = "camera.camera1"; + const string? service_call = "turn_on"; // ACT await DefaultDaemonApp @@ -190,8 +191,8 @@ await DefaultDaemonApp public async Task CameraTurnOffCallsCorrectServiceCall() { // ARRANGE - const string? entityId = "camera.camera1"; - const string? service_call = "turn_off"; + const string? entityId = "camera.camera1"; + const string? service_call = "turn_off"; // ACT await DefaultDaemonApp @@ -205,6 +206,7 @@ await DefaultDaemonApp } [Fact] + [SuppressMessage("", "CA2201")] public async Task CamerasFuncExceptionLogsError() { // ARRANGE diff --git a/tests/NetDaemon.Daemon.Tests/Fluent/FluentTests.cs b/tests/NetDaemon.Daemon.Tests/Fluent/FluentTests.cs index f093fcbcf..ef6c6e4cc 100644 --- a/tests/NetDaemon.Daemon.Tests/Fluent/FluentTests.cs +++ b/tests/NetDaemon.Daemon.Tests/Fluent/FluentTests.cs @@ -1,5 +1,7 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Dynamic; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -369,6 +371,7 @@ await DefaultDaemonApp } [Fact] + [SuppressMessage("", "CA2201")] public async Task EntityFuncExceptionLogsError() { // ARRANGE @@ -430,7 +433,7 @@ public async Task TurnOffEntityLamdaSelectionCallsCorrectServiceCall() await InitializeFakeDaemon().ConfigureAwait(false); // ACT await DefaultDaemonApp - .Entities(n => n.EntityId.StartsWith("light.correct_entity")) + .Entities(n => n.EntityId.StartsWith("light.correct_entity", true, CultureInfo.InvariantCulture)) .TurnOff() .ExecuteAsync().ConfigureAwait(false); @@ -656,6 +659,7 @@ await DefaultDaemonApp } [Fact] + [SuppressMessage("", "CA2201")] public async Task MediaPlayersFuncExceptionLogsError() { // ARRANGE diff --git a/tests/NetDaemon.Daemon.Tests/NetDaemon.Daemon.Tests.csproj b/tests/NetDaemon.Daemon.Tests/NetDaemon.Daemon.Tests.csproj index 3f8ddb65b..fa9960f8d 100644 --- a/tests/NetDaemon.Daemon.Tests/NetDaemon.Daemon.Tests.csproj +++ b/tests/NetDaemon.Daemon.Tests/NetDaemon.Daemon.Tests.csproj @@ -25,6 +25,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + @@ -62,5 +66,7 @@ ..\..\.linting\roslynator.ruleset + true + AllEnabledByDefault diff --git a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/AppExtensionsTests.cs b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/AppExtensionsTests.cs index 57a4b1475..c504382f3 100644 --- a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/AppExtensionsTests.cs +++ b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/AppExtensionsTests.cs @@ -16,7 +16,7 @@ public void TestToSafeHomeAssistantEntityIdReturnCorrectString(string convert, s //ACT string converted = convert.ToSafeHomeAssistantEntityId(); - Assert.Equal(expected.Length, converted.Length); + Assert.Equal(expected?.Length, converted.Length); Assert.Equal(expected, converted); } } diff --git a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyAppsTests.cs b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyAppsTests.cs index a81d01f87..004f4c4a9 100644 --- a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyAppsTests.cs +++ b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyAppsTests.cs @@ -1,19 +1,17 @@ -using JoySoftware.HomeAssistant.Client; using Microsoft.Extensions.Logging; using Moq; using NetDaemon.Daemon.Fakes; -using System; -using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; using Xunit; namespace NetDaemon.Daemon.Tests.NetDaemonApp { - public class DaemonAppTestApp : NetDaemon.Common.NetDaemonApp { } + public class DaemonAppTestApp : Common.NetDaemonApp { } public class FaultyAppTests : DaemonHostTestBase { - public FaultyAppTests() : base() + public FaultyAppTests() { App = new DaemonAppTestApp { @@ -23,7 +21,7 @@ public FaultyAppTests() : base() App.StartUpAsync(DefaultDaemonHost).Wait(); } - public NetDaemon.Common.NetDaemonApp App { get; } + public Common.NetDaemonApp App { get; } [Fact] public async Task ARunTimeErrorShouldLogError() @@ -37,7 +35,7 @@ public async Task ARunTimeErrorShouldLogError() .Call((_, _, _) => { // Do conversion error - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); return Task.CompletedTask; }).Execute(); @@ -60,7 +58,7 @@ public async Task ARunTimeErrorShouldNotBreakOtherApps() .Call((_, _, _) => { // Do conversion error - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); return Task.CompletedTask; }).Execute(); @@ -94,7 +92,7 @@ public async Task MissingAttributeShouldNotBreakOtherApps() .Call((_, _, _) => { // Do conversion error - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); return Task.CompletedTask; }).Execute(); diff --git a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyRxAppsTests.cs b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyRxAppsTests.cs index 26d691353..efd73beb4 100644 --- a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyRxAppsTests.cs +++ b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/FaultyRxAppsTests.cs @@ -7,6 +7,7 @@ using Xunit; using System.Reactive.Linq; using NetDaemon.Daemon.Fakes; +using System.Globalization; namespace NetDaemon.Daemon.Tests.NetDaemonApp { @@ -37,7 +38,7 @@ public async Task ARunTimeErrorShouldLogError() .StateChanges .Subscribe(_ => { - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); }); DefaultHassClientMock.AddChangedEvent("binary_sensor.pir", "off", "on"); @@ -115,7 +116,7 @@ public async Task ARunTimeErrorShouldNotBreakOtherApps() .StateChanges .Subscribe(_ => { - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); }); App @@ -151,7 +152,7 @@ public async Task ARunTimeErrorInAttributeSelectorShouldNotBreakOtherApps() .Where(e => e.New.Attribute!.an_int == "WTF this is not an int!!") .Subscribe(_ => { - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); }); App @@ -187,7 +188,7 @@ public async Task ToUnavailableShouldNotBreak() .Where(e => e.New.State == "on") .Subscribe(_ => { - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); }); App @@ -223,7 +224,7 @@ public async Task FromUnavailableShouldNotBreak() .Where(e => e.New.State == "on") .Subscribe(_ => { - int x = int.Parse("ss"); + int x = int.Parse("ss", CultureInfo.InvariantCulture); }); App diff --git a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/NetDaemonAppTests.cs b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/NetDaemonAppTests.cs index ae95800ca..41edc8682 100644 --- a/tests/NetDaemon.Daemon.Tests/NetDaemonApp/NetDaemonAppTests.cs +++ b/tests/NetDaemon.Daemon.Tests/NetDaemonApp/NetDaemonAppTests.cs @@ -15,12 +15,13 @@ public class AppTestApp : Common.NetDaemonApp { } public class AppTestApp2 : Common.NetDaemonApp { } - public class NetDaemonApptests + public class NetDaemonApptests : IAsyncLifetime, IDisposable { private const string appTemplate = " app: "; private readonly LoggerMock _logMock; private readonly Common.NetDaemonApp _app; private readonly Mock _netDaemonMock; + private bool disposedValue; public NetDaemonApptests() { @@ -206,5 +207,34 @@ public void LogMessageWithParamsExceptionAndDifferentLogLevelsShoulCallCorrectLo // ASSERT _logMock.AssertLogged(level, exception, appTemplate + "Hello Bob", Times.Once()); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + } + + disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + public Task InitializeAsync() + { + return Task.CompletedTask; + } + + public async Task DisposeAsync() + { + await _app.DisposeAsync().ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/tests/NetDaemon.Daemon.Tests/Reactive/RxAppTest.cs b/tests/NetDaemon.Daemon.Tests/Reactive/RxAppTest.cs index 865d40b89..4a9f99bca 100644 --- a/tests/NetDaemon.Daemon.Tests/Reactive/RxAppTest.cs +++ b/tests/NetDaemon.Daemon.Tests/Reactive/RxAppTest.cs @@ -1,5 +1,6 @@ using System; using System.Dynamic; +using System.Globalization; using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; @@ -258,7 +259,7 @@ public async Task UsingEntitiesLambdaNewEventShouldCallFunction() var called = false; // ACT - DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir")) + DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir", true, CultureInfo.InvariantCulture)) .StateChanges .Subscribe(_ => called = true); @@ -278,7 +279,7 @@ public async Task CallbackObserverAttributeMissingShouldReturnNull() string? missingString = "has initial value"; // ACT - DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir")) + DefaultDaemonRxApp.Entities(n => n.EntityId.StartsWith("binary_sensor.pir", true, CultureInfo.InvariantCulture)) .StateChanges .Subscribe(s => missingString = s.New.Attribute?.missing_attribute); diff --git a/tests/NetDaemon.Daemon.Tests/Reactive/RxSchedulers.cs b/tests/NetDaemon.Daemon.Tests/Reactive/RxSchedulers.cs index 697f5da72..bae74601f 100644 --- a/tests/NetDaemon.Daemon.Tests/Reactive/RxSchedulers.cs +++ b/tests/NetDaemon.Daemon.Tests/Reactive/RxSchedulers.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Moq; @@ -16,15 +18,12 @@ namespace NetDaemon.Daemon.Tests.Reactive /// public class RxSchedulerTest : CoreDaemonHostTestBase { - public RxSchedulerTest() : base() - { - } - [Fact] + [SuppressMessage("", "CA2201")] public async Task CreateObservableIntervallFailureShouldLogError() { // ARRANGE - var app = new BaseTestRxApp(); + await using var app = new BaseTestRxApp(); await app.StartUpAsync(DefaultDaemonHost).ConfigureAwait(false); app.IsEnabled = true; @@ -40,7 +39,7 @@ public async Task CreateObservableIntervallFailureShouldLogError() public async Task CreateObservableIntervallShouldCallFunction() { // ARRANGE - var app = new BaseTestRxApp + await using var app = new BaseTestRxApp { IsEnabled = true }; @@ -56,10 +55,11 @@ public async Task CreateObservableIntervallShouldCallFunction() } [Fact] + [SuppressMessage("", "CA2201")] public async Task CreateObservableTimerFailureShouldLogError() { // ARRANGE - var app = new BaseTestRxApp(); + await using var app = new BaseTestRxApp(); await app.StartUpAsync(DefaultDaemonHost).ConfigureAwait(false); app.IsEnabled = true; @@ -75,7 +75,7 @@ public async Task CreateObservableTimerFailureShouldLogError() public async Task CreateObservableTimerShouldCallFunction() { // ARRANGE - var app = new BaseTestRxApp + await using var app = new BaseTestRxApp { IsEnabled = true }; @@ -96,10 +96,10 @@ public void RunDailyOneHourAfterShouldCallCreateObservableIntervall() // ARRANGE var time = DateTime.Now; var timeOneHourBack = time.AddHours(1); - var timeFormat = timeOneHourBack.ToString("HH:mm:ss"); + var timeFormat = timeOneHourBack.ToString("HH:mm:ss", CultureInfo.InvariantCulture); // ACT - DefaultMockedRxApp.Object.RunDaily(timeFormat, () => System.Console.WriteLine("Test")); + DefaultMockedRxApp.Object.RunDaily(timeFormat, () => Console.WriteLine("Test")); // ASSERT DefaultMockedRxApp.Verify(n => n.CreateObservableTimer(It.IsAny(), TimeSpan.FromDays(1), It.IsAny()), Times.Once()); @@ -111,7 +111,7 @@ public void RunDailyOneHourBeforeShouldCallCreateObservableIntervall() // ARRANGE var time = DateTime.Now; var timeOneHourBack = time.Subtract(TimeSpan.FromHours(1)); - var timeFormat = timeOneHourBack.ToString("HH:mm:ss"); + var timeFormat = timeOneHourBack.ToString("HH:mm:ss", CultureInfo.InvariantCulture); // ACT DefaultMockedRxApp.Object.RunDaily(timeFormat, () => System.Console.WriteLine("Test")); @@ -126,7 +126,7 @@ public void RunDailyShouldCallCreateObservableIntervall() // ARRANGE // ACT - DefaultMockedRxApp.Object.RunDaily("10:00:00", () => System.Console.WriteLine("Test")); + DefaultMockedRxApp.Object.RunDaily("10:00:00", () => Console.WriteLine("Test")); // ASSERT DefaultMockedRxApp.Verify(n => n.CreateObservableTimer(It.IsAny(), TimeSpan.FromDays(1), It.IsAny()), Times.Once()); @@ -139,7 +139,7 @@ public void RunDailyShouldThrowExceptionOnErrorFormat() // ACT // ASSERT Assert.Throws(() => - DefaultMockedRxApp.Object.RunDaily("no good input", () => System.Console.WriteLine("Test"))); + DefaultMockedRxApp.Object.RunDaily("no good input", () => Console.WriteLine("Test"))); } [Fact] @@ -147,7 +147,7 @@ public void RunEveryHourShouldCallCreateObservableIntervall() { // ARRANGE // ACT - DefaultMockedRxApp.Object.RunEveryHour("10:00", () => System.Console.WriteLine("Test")); + DefaultMockedRxApp.Object.RunEveryHour("10:00", () => Console.WriteLine("Test")); // ASSERT DefaultMockedRxApp.Verify(n => n.CreateObservableTimer(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once()); @@ -160,7 +160,7 @@ public void RunEveryHourShouldThrowExceptionOnErrorFormat() // ACT // ASSERT Assert.Throws(() => - DefaultMockedRxApp.Object.RunEveryHour("no good input", () => System.Console.WriteLine("Test"))); + DefaultMockedRxApp.Object.RunEveryHour("no good input", () => Console.WriteLine("Test"))); } [Fact] @@ -181,7 +181,7 @@ public void RunEveryMinuteShouldThrowExceptionOnErrorFormat() // ACT // ASSERT Assert.Throws(() => - DefaultMockedRxApp.Object.RunEveryMinute(-1, () => System.Console.WriteLine("Test"))); + DefaultMockedRxApp.Object.RunEveryMinute(-1, () => Console.WriteLine("Test"))); } [Fact] @@ -190,12 +190,13 @@ public void RunEveryShouldCallCreateObservableIntervall() // ARRANGE // ACT - DefaultMockedRxApp.Object.RunEvery(TimeSpan.FromSeconds(5), () => System.Console.WriteLine("Test")); + DefaultMockedRxApp.Object.RunEvery(TimeSpan.FromSeconds(5), () => Console.WriteLine("Test")); // ASSERT DefaultMockedRxApp.Verify(n => n.CreateObservableIntervall(TimeSpan.FromSeconds(5), It.IsAny()), Times.Once()); } [Fact] + [SuppressMessage("", "CA2201")] public async Task RunInFailureShouldLogError() { // ARRANGE diff --git a/tests/NetDaemon.Daemon.Tests/SchedulerTests.cs b/tests/NetDaemon.Daemon.Tests/SchedulerTests.cs index 27d9ef488..a4fb1f3c3 100644 --- a/tests/NetDaemon.Daemon.Tests/SchedulerTests.cs +++ b/tests/NetDaemon.Daemon.Tests/SchedulerTests.cs @@ -7,12 +7,14 @@ using NetDaemon.Common; using Xunit; using NetDaemon.Daemon.Fakes; +using System.Diagnostics.CodeAnalysis; namespace NetDaemon.Daemon.Tests { public class SchedulerTests { [Fact] + [SuppressMessage("", "CA1031")] public async void TestRunInShouldStartAndCompleteCorrectly() { // ARRANGE @@ -53,6 +55,7 @@ public async void TestRunInShouldStartAndCompleteCorrectly() } [Fact] + [SuppressMessage("", "CA1031")] public async void RunInShouldLogWarningForFaultyRun() { // ARRANGE @@ -68,7 +71,7 @@ public async void RunInShouldLogWarningForFaultyRun() // ACT scheduledResult = scheduler.RunIn(20, () => { - int i = int.Parse("Not an integer makes runtime error!"); + int i = int.Parse("Not an integer makes runtime error!", CultureInfo.InvariantCulture); return Task.CompletedTask; }); @@ -87,6 +90,7 @@ public async void RunInShouldLogWarningForFaultyRun() } [Fact] + [SuppressMessage("", "CA1031")] public async void TestRunInShouldStartAndAncCancelCorrectly() { // ARRANGE @@ -132,7 +136,7 @@ public async void TestRunInShouldStartAndAncCancelCorrectly() [InlineData("00:00:00", "00:00:00", 0)] [InlineData("23:59:59", "00:00:00", 1)] [InlineData("00:00:01", "00:00:00", (24 * 60 * 60) - 1)] - public void DailyTimeBetweenNowAndTargetTime(string nowTime, string targetTime, int nrOfSecondsRemaining) + public async Task DailyTimeBetweenNowAndTargetTime(string nowTime, string targetTime, int nrOfSecondsRemaining) { // ARRANGE DateTime timePart = DateTime.ParseExact(nowTime, "HH:mm:ss", CultureInfo.InvariantCulture); @@ -141,7 +145,7 @@ public void DailyTimeBetweenNowAndTargetTime(string nowTime, string targetTime, var mockTimeManager = new TimeManagerMock(fakeTimeNow); - var scheduler = new Scheduler(mockTimeManager.Object); + await using var scheduler = new Scheduler(mockTimeManager.Object); var timeToWait = scheduler.CalculateDailyTimeBetweenNowAndTargetTime(timeTarget); @@ -153,7 +157,7 @@ public void DailyTimeBetweenNowAndTargetTime(string nowTime, string targetTime, [InlineData(59, 0, 1)] [InlineData(0, 59, 59)] [InlineData(31, 30, 59)] - public void EveryMinuteCalcTimeCorrectTargetDelay(short nowSeconds, short targetSeconds, short expectedDelaySeconds) + public async Task EveryMinuteCalcTimeCorrectTargetDelay(short nowSeconds, short targetSeconds, short expectedDelaySeconds) { // ARRANGE var startTime = @@ -161,7 +165,7 @@ public void EveryMinuteCalcTimeCorrectTargetDelay(short nowSeconds, short target var mockTimeManager = new TimeManagerMock(startTime); - var scheduler = new Scheduler(mockTimeManager.Object); + await using var scheduler = new Scheduler(mockTimeManager.Object); var calculatedDelay = scheduler.CalculateEveryMinuteTimeBetweenNowAndTargetTime(targetSeconds); @@ -169,6 +173,8 @@ public void EveryMinuteCalcTimeCorrectTargetDelay(short nowSeconds, short target } [Fact] + [SuppressMessage("", "CA1508")] + [SuppressMessage("", "CA1031")] public async void TestRunDailyUsingStartTimeCallsFuncCorrectly() { // ARRANGE @@ -203,6 +209,7 @@ public async void TestRunDailyUsingStartTimeCallsFuncCorrectly() } [Fact] + [SuppressMessage("", "CA1031")] public async void RunDailyFaultShouldLogWarning() { // ARRANGE @@ -218,7 +225,7 @@ public async void RunDailyFaultShouldLogWarning() // ACT scheduledResult = scheduler.RunDaily("10:00:01", () => { - int i = int.Parse("Not an integer makes runtime error!"); + int i = int.Parse("Not an integer makes runtime error!", CultureInfo.InvariantCulture); return Task.CompletedTask; }); await Task.Delay(1500).ConfigureAwait(false); @@ -236,6 +243,7 @@ public async void RunDailyFaultShouldLogWarning() } [Fact] + [SuppressMessage("", "CA1031")] public async void RunDailyOnDaysFaultShouldLogWarning() { // ARRANGE @@ -251,7 +259,7 @@ public async void RunDailyOnDaysFaultShouldLogWarning() // ACT scheduledResult = scheduler.RunDaily("10:00:01", new DayOfWeek[] { DayOfWeek.Saturday }, () => { - int i = int.Parse("Not an integer makes runtime error!"); + int i = int.Parse("Not an integer makes runtime error!", CultureInfo.InvariantCulture); return Task.CompletedTask; }); await Task.Delay(1500).ConfigureAwait(false); @@ -269,6 +277,8 @@ public async void RunDailyOnDaysFaultShouldLogWarning() } [Fact] + [SuppressMessage("", "CA1508")] + [SuppressMessage("", "CA1031")] public async void TestRunDailyUsingStartTimeCancelsCorrectly() { // ARRANGE @@ -312,6 +322,8 @@ public async void TestRunDailyUsingStartTimeCancelsCorrectly() [InlineData("2001-02-07 10:00:00", DayOfWeek.Wednesday)] [InlineData("2001-02-08 10:00:00", DayOfWeek.Thursday)] [InlineData("2001-02-09 10:00:00", DayOfWeek.Friday)] + [SuppressMessage("", "CA1508")] + [SuppressMessage("", "CA1031")] public async void TestRunDailyUsingStartTimeOnWeekdayCallsFuncCorrectly(string time, DayOfWeek dayOfWeek) { // ARRANGE @@ -353,6 +365,8 @@ public async void TestRunDailyUsingStartTimeOnWeekdayCallsFuncCorrectly(string t [InlineData("2001-02-07 10:00:00")] [InlineData("2001-02-08 10:00:00")] [InlineData("2001-02-09 10:00:00")] + [SuppressMessage("", "CA1508")] + [SuppressMessage("", "CA1031")] public async void TestRunDailyUsingStartTimeOnWeekdayNotCalled(string time) { // ARRANGE @@ -389,6 +403,7 @@ public async void TestRunDailyUsingStartTimeOnWeekdayNotCalled(string time) } [Fact] + [SuppressMessage("", "CA1031")] public async void TestRunEveryMinuteStartTimeCallsFuncCorrectly() { // ARRANGE @@ -425,6 +440,7 @@ public async void TestRunEveryMinuteStartTimeCallsFuncCorrectly() } [Fact] + [SuppressMessage("", "CA1031")] public async void RunEveryMinuteFaultyShouldLogWarning() { // ARRANGE @@ -440,7 +456,7 @@ public async void RunEveryMinuteFaultyShouldLogWarning() // ACT scheduledResult = scheduler.RunEveryMinute(0, () => { - int i = int.Parse("Not an integer makes runtime error!"); + int i = int.Parse("Not an integer makes runtime error!", CultureInfo.InvariantCulture); return Task.CompletedTask; }); await Task.Delay(1000).ConfigureAwait(false); @@ -458,6 +474,7 @@ public async void RunEveryMinuteFaultyShouldLogWarning() } [Fact] + [SuppressMessage("", "CA1031")] public async void TestRunEveryMinuteStartTimeCanceledCorrectly() { // ARRANGE @@ -496,6 +513,8 @@ public async void TestRunEveryMinuteStartTimeCanceledCorrectly() } [Fact] + [SuppressMessage("", "CA1508")] + [SuppressMessage("", "CA1031")] public async void TestRunEveryMinuteStartTimeNotZeroCallsFuncCorrectly() { // ARRANGE diff --git a/tests/NetDaemon.Daemon.Tests/TestBaseClasses.cs b/tests/NetDaemon.Daemon.Tests/TestBaseClasses.cs index cb56686f3..dcdce4611 100644 --- a/tests/NetDaemon.Daemon.Tests/TestBaseClasses.cs +++ b/tests/NetDaemon.Daemon.Tests/TestBaseClasses.cs @@ -16,9 +16,10 @@ public class BaseTestApp : Common.NetDaemonApp { } public class BaseTestRxApp : NetDaemonRxApp { } - public class CoreDaemonHostTestBase : DaemonHostTestBase, IAsyncLifetime + public class CoreDaemonHostTestBase : DaemonHostTestBase, IAsyncLifetime, IDisposable { private readonly NetDaemonHost _notConnectedDaemonHost; + private bool disposedValue; public CoreDaemonHostTestBase() : base() { @@ -136,9 +137,11 @@ public void SetupFakeData() { await base.DisposeAsync().ConfigureAwait(false); + await _notConnectedDaemonHost.DisposeAsync().ConfigureAwait(false); await DefaultDaemonApp.DisposeAsync().ConfigureAwait(false); await DefaultDaemonRxApp.DisposeAsync().ConfigureAwait(false); await DefaultMockedRxApp.Object.DisposeAsync().ConfigureAwait(false); + await DefaultDaemonRxApp.DisposeAsync().ConfigureAwait(false); } /// @@ -165,5 +168,23 @@ public void SetupFakeData() : new CancellationTokenSource(milliSeconds); return (_notConnectedDaemonHost.Run("host", 8123, false, "token", cancelSource.Token), cancelSource); } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + } + disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } \ No newline at end of file