2020-12-23 11:35:49 +01:00
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System ;
2020-10-09 11:37:25 +02:00
using System.Collections ;
using System.ComponentModel ;
2020-03-24 11:53:56 +11:00
using System.Data.Common ;
2020-03-31 18:01:27 +11:00
using System.IO ;
2020-10-09 11:37:25 +02:00
using System.Linq ;
2020-03-13 14:43:41 +11:00
using System.Net ;
2020-04-03 13:16:01 +11:00
using System.Reflection ;
2020-10-26 10:47:14 +00:00
using System.Threading ;
2020-09-03 12:29:23 +02:00
using Microsoft.AspNetCore.Hosting ;
using Microsoft.AspNetCore.Http ;
Examine 2.0 integration (#10241)
* Init commit for examine 2.0 work, most old umb examine tests working, probably a lot that doesn't
* Gets Umbraco Examine tests passing and makes some sense out of them, fixes some underlying issues.
* Large refactor, remove TaskHelper, rename Notifications to be consistent, Gets all examine/lucene indexes building and startup ordered in the correct way, removes old files, creates new IUmbracoIndexingHandler for abstracting out all index operations for umbraco data, abstracts out IIndexRebuilder, Fixes Stack overflow with LiveModelsProvider and loading assemblies, ports some changes from v8 for startup handling with cold boots, refactors out LastSyncedFileManager
* fix up issues with rebuilding and management dashboard.
* removes old files, removes NetworkHelper, fixes LastSyncedFileManager implementation to ensure the machine name is used, fix up logging with cold boot state.
* Makes MainDom safer to use and makes PublishedSnapshotService lazily register with MainDom
* lazily acquire application id (fix unit tests)
* Fixes resource casing and missing test file
* Ensures caches when requiring internal services for PublishedSnapshotService, UseNuCache is a separate call, shouldn't be buried in AddWebComponents, was also causing issues in integration tests since nucache was being used for the Id2Key service.
* For UmbracoTestServerTestBase enable nucache services
* Fixing tests
* Fix another test
* Fixes tests, use TestHostingEnvironment, make Tests.Common use net5, remove old Lucene.Net.Contrib ref.
* Fixes up some review notes
* Fixes issue with doubly registering PublishedSnapshotService meanig there could be 2x instances of it
* Checks for parseexception when executing the query
* Use application root instead of duplicating functionality.
* Added Examine project to netcore only solution file
* Fixed casing issue with LazyLoad, that is not lowercase.
* uses cancellationToken instead of bool flag, fixes always reading lastId from the LastSyncedFileManager, fixes RecurringHostedServiceBase so that there isn't an overlapping thread for the same task type
* Fix tests
* remove legacy test project from solution file
* Fix test
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-05-18 18:31:38 +10:00
using Microsoft.Extensions.DependencyInjection ;
2020-09-21 21:06:24 +02:00
using Microsoft.Extensions.FileProviders ;
2020-09-03 12:29:23 +02:00
using Microsoft.Extensions.Hosting ;
Examine 2.0 integration (#10241)
* Init commit for examine 2.0 work, most old umb examine tests working, probably a lot that doesn't
* Gets Umbraco Examine tests passing and makes some sense out of them, fixes some underlying issues.
* Large refactor, remove TaskHelper, rename Notifications to be consistent, Gets all examine/lucene indexes building and startup ordered in the correct way, removes old files, creates new IUmbracoIndexingHandler for abstracting out all index operations for umbraco data, abstracts out IIndexRebuilder, Fixes Stack overflow with LiveModelsProvider and loading assemblies, ports some changes from v8 for startup handling with cold boots, refactors out LastSyncedFileManager
* fix up issues with rebuilding and management dashboard.
* removes old files, removes NetworkHelper, fixes LastSyncedFileManager implementation to ensure the machine name is used, fix up logging with cold boot state.
* Makes MainDom safer to use and makes PublishedSnapshotService lazily register with MainDom
* lazily acquire application id (fix unit tests)
* Fixes resource casing and missing test file
* Ensures caches when requiring internal services for PublishedSnapshotService, UseNuCache is a separate call, shouldn't be buried in AddWebComponents, was also causing issues in integration tests since nucache was being used for the Id2Key service.
* For UmbracoTestServerTestBase enable nucache services
* Fixing tests
* Fix another test
* Fixes tests, use TestHostingEnvironment, make Tests.Common use net5, remove old Lucene.Net.Contrib ref.
* Fixes up some review notes
* Fixes issue with doubly registering PublishedSnapshotService meanig there could be 2x instances of it
* Checks for parseexception when executing the query
* Use application root instead of duplicating functionality.
* Added Examine project to netcore only solution file
* Fixed casing issue with LazyLoad, that is not lowercase.
* uses cancellationToken instead of bool flag, fixes always reading lastId from the LastSyncedFileManager, fixes RecurringHostedServiceBase so that there isn't an overlapping thread for the same task type
* Fix tests
* remove legacy test project from solution file
* Fix test
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-05-18 18:31:38 +10:00
using Microsoft.Extensions.Hosting.Internal ;
2020-09-23 07:17:05 +02:00
using Microsoft.Extensions.Logging ;
2020-09-03 12:29:23 +02:00
using Microsoft.Extensions.Options ;
using Moq ;
2020-10-09 11:37:25 +02:00
using NUnit.Framework ;
2021-02-09 10:22:42 +01:00
using Umbraco.Cms.Core ;
using Umbraco.Cms.Core.Cache ;
using Umbraco.Cms.Core.Configuration.Models ;
using Umbraco.Cms.Core.Diagnostics ;
using Umbraco.Cms.Core.Hosting ;
using Umbraco.Cms.Core.Logging ;
using Umbraco.Cms.Core.Models ;
using Umbraco.Cms.Core.Models.Entities ;
using Umbraco.Cms.Core.Net ;
using Umbraco.Cms.Core.PropertyEditors ;
using Umbraco.Cms.Core.Runtime ;
2021-02-12 13:36:50 +01:00
using Umbraco.Cms.Infrastructure.Persistence ;
2021-02-10 14:45:44 +01:00
using Umbraco.Cms.Tests.Common ;
Examine 2.0 integration (#10241)
* Init commit for examine 2.0 work, most old umb examine tests working, probably a lot that doesn't
* Gets Umbraco Examine tests passing and makes some sense out of them, fixes some underlying issues.
* Large refactor, remove TaskHelper, rename Notifications to be consistent, Gets all examine/lucene indexes building and startup ordered in the correct way, removes old files, creates new IUmbracoIndexingHandler for abstracting out all index operations for umbraco data, abstracts out IIndexRebuilder, Fixes Stack overflow with LiveModelsProvider and loading assemblies, ports some changes from v8 for startup handling with cold boots, refactors out LastSyncedFileManager
* fix up issues with rebuilding and management dashboard.
* removes old files, removes NetworkHelper, fixes LastSyncedFileManager implementation to ensure the machine name is used, fix up logging with cold boot state.
* Makes MainDom safer to use and makes PublishedSnapshotService lazily register with MainDom
* lazily acquire application id (fix unit tests)
* Fixes resource casing and missing test file
* Ensures caches when requiring internal services for PublishedSnapshotService, UseNuCache is a separate call, shouldn't be buried in AddWebComponents, was also causing issues in integration tests since nucache was being used for the Id2Key service.
* For UmbracoTestServerTestBase enable nucache services
* Fixing tests
* Fix another test
* Fixes tests, use TestHostingEnvironment, make Tests.Common use net5, remove old Lucene.Net.Contrib ref.
* Fixes up some review notes
* Fixes issue with doubly registering PublishedSnapshotService meanig there could be 2x instances of it
* Checks for parseexception when executing the query
* Use application root instead of duplicating functionality.
* Added Examine project to netcore only solution file
* Fixed casing issue with LazyLoad, that is not lowercase.
* uses cancellationToken instead of bool flag, fixes always reading lastId from the LastSyncedFileManager, fixes RecurringHostedServiceBase so that there isn't an overlapping thread for the same task type
* Fix tests
* remove legacy test project from solution file
* Fix test
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-05-18 18:31:38 +10:00
using Umbraco.Cms.Tests.Common.Testing ;
2021-02-10 11:42:04 +01:00
using Umbraco.Cms.Web.Common.AspNetCore ;
2021-02-09 11:26:22 +01:00
using Umbraco.Extensions ;
2020-10-26 10:47:14 +00:00
using File = System . IO . File ;
2021-02-09 10:22:42 +01:00
using IHostingEnvironment = Umbraco . Cms . Core . Hosting . IHostingEnvironment ;
2020-03-13 14:43:41 +11:00
2021-02-11 08:30:27 +01:00
namespace Umbraco.Cms.Tests.Integration.Implementations
2020-03-13 14:43:41 +11:00
{
public class TestHelper : TestHelperBase
{
private IBackOfficeInfo _backOfficeInfo ;
2020-03-31 17:27:51 +11:00
private IHostingEnvironment _hostingEnvironment ;
2020-03-26 15:39:20 +11:00
private readonly IApplicationShutdownRegistry _hostingLifetime ;
2020-03-13 14:43:41 +11:00
private readonly IIpResolver _ipResolver ;
private readonly IWebHostEnvironment _hostEnvironment ;
private readonly IHttpContextAccessor _httpContextAccessor ;
2020-03-31 18:01:27 +11:00
private string _tempWorkingDir ;
2020-03-13 14:43:41 +11:00
2020-12-23 11:35:49 +01:00
public TestHelper ( )
: base ( typeof ( TestHelper ) . Assembly )
2020-03-13 14:43:41 +11:00
{
var httpContext = new DefaultHttpContext ( ) ;
httpContext . Connection . RemoteIpAddress = IPAddress . Parse ( "127.0.0.1" ) ;
_httpContextAccessor = Mock . Of < IHttpContextAccessor > ( x = > x . HttpContext = = httpContext ) ;
2020-05-14 17:04:16 +10:00
_ipResolver = new AspNetCoreIpResolver ( _httpContextAccessor ) ;
2020-03-13 14:43:41 +11:00
2020-12-23 11:35:49 +01:00
string contentRoot = Assembly . GetExecutingAssembly ( ) . GetRootDirectorySafe ( ) ;
2022-01-10 15:31:46 +00:00
// The mock for IWebHostEnvironment has caused a good few issues.
// We can UseContentRoot, UseWebRoot etc on the host builder instead.
// possibly going down rabbit holes though as would need to cleanup all usages of
// GetHostingEnvironment & GetWebHostEnvironment.
2020-03-31 17:27:51 +11:00
var hostEnvironment = new Mock < IWebHostEnvironment > ( ) ;
2020-12-23 11:35:49 +01:00
// This must be the assembly name for the WebApplicationFactory to work.
2020-09-16 15:17:42 +02:00
hostEnvironment . Setup ( x = > x . ApplicationName ) . Returns ( GetType ( ) . Assembly . GetName ( ) . Name ) ;
2020-09-02 18:10:29 +10:00
hostEnvironment . Setup ( x = > x . ContentRootPath ) . Returns ( ( ) = > contentRoot ) ;
hostEnvironment . Setup ( x = > x . ContentRootFileProvider ) . Returns ( ( ) = > new PhysicalFileProvider ( contentRoot ) ) ;
2020-03-31 17:27:51 +11:00
hostEnvironment . Setup ( x = > x . WebRootPath ) . Returns ( ( ) = > WorkingDirectory ) ;
2020-09-02 18:10:29 +10:00
hostEnvironment . Setup ( x = > x . WebRootFileProvider ) . Returns ( ( ) = > new PhysicalFileProvider ( WorkingDirectory ) ) ;
2022-01-10 15:31:46 +00:00
hostEnvironment . Setup ( x = > x . EnvironmentName ) . Returns ( "Tests" ) ;
2020-12-23 11:35:49 +01:00
// We also need to expose it as the obsolete interface since netcore's WebApplicationFactory casts it.
2020-09-02 18:10:29 +10:00
hostEnvironment . As < Microsoft . AspNetCore . Hosting . IHostingEnvironment > ( ) ;
2020-03-31 17:27:51 +11:00
_hostEnvironment = hostEnvironment . Object ;
2020-03-25 15:06:22 +11:00
2020-03-26 15:39:20 +11:00
_hostingLifetime = new AspNetCoreApplicationShutdownRegistry ( Mock . Of < IHostApplicationLifetime > ( ) ) ;
2020-09-16 15:17:42 +02:00
ConsoleLoggerFactory = LoggerFactory . Create ( builder = > builder . AddConsole ( ) ) ;
2020-11-20 12:24:16 +00:00
ProfilingLogger = new ProfilingLogger ( ConsoleLoggerFactory . CreateLogger < ProfilingLogger > ( ) , Profiler ) ;
2020-03-13 14:43:41 +11:00
}
2020-04-14 16:55:54 +01:00
public IUmbracoBootPermissionChecker UmbracoBootPermissionChecker { get ; } =
new TestUmbracoBootPermissionChecker ( ) ;
2020-03-13 14:43:41 +11:00
2020-12-23 11:35:49 +01:00
public AppCaches AppCaches { get ; } = new AppCaches (
NoAppCache . Instance ,
NoAppCache . Instance ,
2020-04-14 16:55:54 +01:00
new IsolatedCaches ( type = > NoAppCache . Instance ) ) ;
2020-03-13 14:43:41 +11:00
2020-09-16 15:17:42 +02:00
public ILoggerFactory ConsoleLoggerFactory { get ; private set ; }
2020-12-23 11:35:49 +01:00
2020-09-15 10:03:56 +02:00
public IProfilingLogger ProfilingLogger { get ; private set ; }
2020-03-13 14:43:41 +11:00
2020-12-24 16:35:59 +11:00
public IProfiler Profiler { get ; } = new NoopProfiler ( ) ;
2020-03-13 14:43:41 +11:00
public IHttpContextAccessor GetHttpContextAccessor ( ) = > _httpContextAccessor ;
public IWebHostEnvironment GetWebHostEnvironment ( ) = > _hostEnvironment ;
2020-04-14 16:55:54 +01:00
public override IDbProviderFactoryCreator DbProviderFactoryCreator = >
2021-03-05 15:36:27 +01:00
new SqlServerDbProviderFactoryCreator ( DbProviderFactories . GetFactory , Options . Create ( new GlobalSettings ( ) ) ) ;
2020-03-13 14:43:41 +11:00
public override IBulkSqlInsertProvider BulkSqlInsertProvider = > new SqlServerBulkSqlInsertProvider ( ) ;
public override IMarchal Marchal { get ; } = new AspNetCoreMarchal ( ) ;
2020-03-31 17:27:51 +11:00
public override IHostingEnvironment GetHostingEnvironment ( )
= > _hostingEnvironment ? ? = new TestHostingEnvironment (
2020-09-03 12:29:23 +02:00
GetIOptionsMonitorOfHostingSettings ( ) ,
2021-02-08 11:00:15 +01:00
GetIOptionsMonitorOfWebRoutingSettings ( ) ,
2020-04-03 01:08:52 +11:00
_hostEnvironment ) ;
2020-03-31 17:27:51 +11:00
2020-09-03 12:29:23 +02:00
private IOptionsMonitor < HostingSettings > GetIOptionsMonitorOfHostingSettings ( )
{
2020-09-21 21:06:24 +02:00
var hostingSettings = new HostingSettings ( ) ;
2020-09-03 12:29:23 +02:00
return Mock . Of < IOptionsMonitor < HostingSettings > > ( x = > x . CurrentValue = = hostingSettings ) ;
}
2021-02-08 11:00:15 +01:00
private IOptionsMonitor < WebRoutingSettings > GetIOptionsMonitorOfWebRoutingSettings ( )
{
var webRoutingSettings = new WebRoutingSettings ( ) ;
return Mock . Of < IOptionsMonitor < WebRoutingSettings > > ( x = > x . CurrentValue = = webRoutingSettings ) ;
}
2020-03-26 15:39:20 +11:00
public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime ( ) = > _hostingLifetime ;
2020-03-13 14:43:41 +11:00
public override IIpResolver GetIpResolver ( ) = > _ipResolver ;
2020-03-25 15:06:22 +11:00
2020-04-14 16:55:54 +01:00
/// <summary>
/// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name
/// </summary>
public override string MapPathForTestFiles ( string relativePath )
{
if ( ! relativePath . StartsWith ( "~/" ) )
2020-12-23 11:35:49 +01:00
{
2020-04-14 16:55:54 +01:00
throw new ArgumentException ( "relativePath must start with '~/'" , nameof ( relativePath ) ) ;
2020-12-23 11:35:49 +01:00
}
2020-04-14 16:55:54 +01:00
2020-12-23 11:35:49 +01:00
string codeBase = typeof ( TestHelperBase ) . Assembly . CodeBase ;
2020-04-14 16:55:54 +01:00
var uri = new Uri ( codeBase ) ;
2020-12-23 11:35:49 +01:00
string path = uri . LocalPath ;
string bin = Path . GetDirectoryName ( path ) ;
2020-04-14 16:55:54 +01:00
return relativePath . Replace ( "~/" , bin + "/" ) ;
}
2020-10-09 11:37:25 +02:00
2020-12-23 11:35:49 +01:00
public void AssertPropertyValuesAreEqual ( object actual , object expected , Func < IEnumerable , IEnumerable > sorter = null , string [ ] ignoreProperties = null )
2020-10-09 11:37:25 +02:00
{
2020-10-21 13:28:13 +02:00
const int dateDeltaMilliseconds = 1000 ; // 1s
2020-10-09 11:37:25 +02:00
2020-12-23 11:35:49 +01:00
PropertyInfo [ ] properties = expected . GetType ( ) . GetProperties ( ) ;
foreach ( PropertyInfo property in properties )
2020-10-09 11:37:25 +02:00
{
2020-12-23 11:35:49 +01:00
// Ignore properties that are attributed with EditorBrowsableState.Never.
EditorBrowsableAttribute att = property . GetCustomAttribute < EditorBrowsableAttribute > ( false ) ;
2020-10-09 11:37:25 +02:00
if ( att ! = null & & att . State = = EditorBrowsableState . Never )
2020-12-23 11:35:49 +01:00
{
2020-10-09 11:37:25 +02:00
continue ;
2020-12-23 11:35:49 +01:00
}
2020-10-09 11:37:25 +02:00
2020-12-23 11:35:49 +01:00
// Ignore explicitly ignored properties.
2020-10-09 11:37:25 +02:00
if ( ignoreProperties ! = null & & ignoreProperties . Contains ( property . Name ) )
2020-12-23 11:35:49 +01:00
{
2020-10-09 11:37:25 +02:00
continue ;
2020-12-23 11:35:49 +01:00
}
2020-10-09 11:37:25 +02:00
2020-12-23 11:35:49 +01:00
object actualValue = property . GetValue ( actual , null ) ;
object expectedValue = property . GetValue ( expected , null ) ;
2020-10-09 11:37:25 +02:00
AssertAreEqual ( property , expectedValue , actualValue , sorter , dateDeltaMilliseconds ) ;
}
}
private static void AssertListsAreEqual ( PropertyInfo property , IEnumerable expected , IEnumerable actual , Func < IEnumerable , IEnumerable > sorter = null , int dateDeltaMilliseconds = 0 )
{
if ( sorter = = null )
{
// this is pretty hackerific but saves us some code to write
sorter = enumerable = >
{
// semi-generic way of ensuring any collection of IEntity are sorted by Ids for comparison
var entities = enumerable . OfType < IEntity > ( ) . ToList ( ) ;
2020-12-23 11:35:49 +01:00
return entities . Count > 0 ? ( IEnumerable ) entities . OrderBy ( x = > x . Id ) : entities ;
2020-10-09 11:37:25 +02:00
} ;
}
var expectedListEx = sorter ( expected ) . Cast < object > ( ) . ToList ( ) ;
var actualListEx = sorter ( actual ) . Cast < object > ( ) . ToList ( ) ;
if ( actualListEx . Count ! = expectedListEx . Count )
2020-12-23 11:35:49 +01:00
{
2020-10-09 11:37:25 +02:00
Assert . Fail ( "Collection {0}.{1} does not match. Expected IEnumerable containing {2} elements but was IEnumerable containing {3} elements" , property . PropertyType . Name , property . Name , expectedListEx . Count , actualListEx . Count ) ;
2020-12-23 11:35:49 +01:00
}
2020-10-09 11:37:25 +02:00
2020-12-23 11:35:49 +01:00
for ( int i = 0 ; i < actualListEx . Count ; i + + )
{
2020-10-09 11:37:25 +02:00
AssertAreEqual ( property , expectedListEx [ i ] , actualListEx [ i ] , sorter , dateDeltaMilliseconds ) ;
2020-12-23 11:35:49 +01:00
}
2020-10-09 11:37:25 +02:00
}
2020-10-21 13:28:13 +02:00
private static void AssertAreEqual ( PropertyInfo property , object expected , object actual , Func < IEnumerable , IEnumerable > sorter = null , int dateDeltaMilliseconds = 0 )
2020-10-09 11:37:25 +02:00
{
2020-12-23 11:35:49 +01:00
if ( ! ( expected is string ) & & expected is IEnumerable enumerable )
2020-10-09 11:37:25 +02:00
{
// sort property collection by alias, not by property ids
// on members, built-in properties don't have ids (always zero)
if ( expected is PropertyCollection )
2020-12-23 11:35:49 +01:00
{
sorter = e = > ( ( PropertyCollection ) e ) . OrderBy ( x = > x . Alias ) ;
}
2020-10-09 11:37:25 +02:00
// compare lists
2020-12-23 11:35:49 +01:00
AssertListsAreEqual ( property , ( IEnumerable ) actual , enumerable , sorter , dateDeltaMilliseconds ) ;
2020-10-09 11:37:25 +02:00
}
else if ( expected is DateTime expectedDateTime )
{
// compare date & time with delta
2020-12-23 11:35:49 +01:00
var actualDateTime = ( DateTime ) actual ;
double delta = ( actualDateTime - expectedDateTime ) . TotalMilliseconds ;
2020-10-09 11:37:25 +02:00
Assert . IsTrue ( Math . Abs ( delta ) < = dateDeltaMilliseconds , "Property {0}.{1} does not match. Expected: {2} but was: {3}" , property . DeclaringType . Name , property . Name , expected , actual ) ;
}
else if ( expected is Property expectedProperty )
{
// compare values
2020-12-23 11:35:49 +01:00
var actualProperty = ( Property ) actual ;
IPropertyValue [ ] expectedPropertyValues = expectedProperty . Values . OrderBy ( x = > x . Culture ) . ThenBy ( x = > x . Segment ) . ToArray ( ) ;
IPropertyValue [ ] actualPropertyValues = actualProperty . Values . OrderBy ( x = > x . Culture ) . ThenBy ( x = > x . Segment ) . ToArray ( ) ;
2020-10-09 11:37:25 +02:00
if ( expectedPropertyValues . Length ! = actualPropertyValues . Length )
2020-12-23 11:35:49 +01:00
{
2020-10-09 11:37:25 +02:00
Assert . Fail ( $"{property.DeclaringType.Name}.{property.Name}: Expected {expectedPropertyValues.Length} but got {actualPropertyValues.Length}." ) ;
2020-12-23 11:35:49 +01:00
}
for ( int i = 0 ; i < expectedPropertyValues . Length ; i + + )
2020-10-09 11:37:25 +02:00
{
2020-10-21 13:28:13 +02:00
// This is not pretty, but since a property value can be a datetime we can't just always compare them as is.
// This is made worse by the fact that PublishedValue is not always set, meaning we can't lump it all into the same if block
if ( expectedPropertyValues [ i ] . EditedValue is DateTime expectedEditDateTime )
{
2020-12-23 11:35:49 +01:00
var actualEditDateTime = ( DateTime ) actualPropertyValues [ i ] . EditedValue ;
2020-10-21 13:28:13 +02:00
AssertDateTime ( expectedEditDateTime , actualEditDateTime , $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \" { expectedPropertyValues [ i ] . EditedValue } \ " but got \"{actualPropertyValues[i].EditedValue}\"." , dateDeltaMilliseconds ) ;
}
else
{
Assert . AreEqual ( expectedPropertyValues [ i ] . EditedValue , actualPropertyValues [ i ] . EditedValue , $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \" { expectedPropertyValues [ i ] . EditedValue } \ " but got \"{actualPropertyValues[i].EditedValue}\"." ) ;
}
if ( expectedPropertyValues [ i ] . PublishedValue is DateTime expectedPublishDateTime )
{
2020-12-23 11:35:49 +01:00
var actualPublishedDateTime = ( DateTime ) actualPropertyValues [ i ] . PublishedValue ;
2020-10-21 13:28:13 +02:00
AssertDateTime ( expectedPublishDateTime , actualPublishedDateTime , $"{property.DeclaringType.Name}.{property.Name}: Expected published value \" { expectedPropertyValues [ i ] . PublishedValue } \ " but got \"{actualPropertyValues[i].PublishedValue}\"." , dateDeltaMilliseconds ) ;
}
else
{
Assert . AreEqual ( expectedPropertyValues [ i ] . PublishedValue , actualPropertyValues [ i ] . PublishedValue , $"{property.DeclaringType.Name}.{property.Name}: Expected published value \" { expectedPropertyValues [ i ] . PublishedValue } \ " but got \"{actualPropertyValues[i].PublishedValue}\"." ) ;
}
2020-10-09 11:37:25 +02:00
}
}
else if ( expected is IDataEditor expectedEditor )
{
Assert . IsInstanceOf < IDataEditor > ( actual ) ;
2020-12-23 11:35:49 +01:00
var actualEditor = ( IDataEditor ) actual ;
2020-10-09 11:37:25 +02:00
Assert . AreEqual ( expectedEditor . Alias , actualEditor . Alias ) ;
2020-12-23 11:35:49 +01:00
2020-10-09 11:37:25 +02:00
// what else shall we test?
}
else
{
// directly compare values
2020-12-23 11:35:49 +01:00
Assert . AreEqual (
expected ,
actual ,
"Property {0}.{1} does not match. Expected: {2} but was: {3}" ,
property . DeclaringType . Name ,
property . Name ,
expected ? . ToString ( ) ? ? "<null>" ,
actual ? . ToString ( ) ? ? "<null>" ) ;
2020-10-09 11:37:25 +02:00
}
}
2020-10-21 13:28:13 +02:00
2020-12-23 11:35:49 +01:00
private static void AssertDateTime ( DateTime expected , DateTime actual , string failureMessage , int dateDeltaMiliseconds = 0 )
2020-10-21 13:28:13 +02:00
{
2020-12-23 11:35:49 +01:00
double delta = ( actual - expected ) . TotalMilliseconds ;
2020-10-21 13:28:13 +02:00
Assert . IsTrue ( Math . Abs ( delta ) < = dateDeltaMiliseconds , failureMessage ) ;
}
2020-10-26 10:47:14 +00:00
public void DeleteDirectory ( string path )
{
Try ( ( ) = >
{
2020-12-23 11:35:49 +01:00
if ( Directory . Exists ( path ) = = false )
{
return ;
}
foreach ( string file in Directory . EnumerateFiles ( path , "*" , SearchOption . AllDirectories ) )
{
2020-10-26 10:47:14 +00:00
File . Delete ( file ) ;
2020-12-23 11:35:49 +01:00
}
2020-10-26 10:47:14 +00:00
} ) ;
Try ( ( ) = >
{
2020-12-23 11:35:49 +01:00
if ( Directory . Exists ( path ) = = false )
{
return ;
}
2020-10-26 10:47:14 +00:00
Directory . Delete ( path , true ) ;
} ) ;
}
2020-12-23 11:35:49 +01:00
public static void TryAssert ( Action action , int maxTries = 5 , int waitMilliseconds = 200 ) = >
2020-10-26 10:47:14 +00:00
Try < AssertionException > ( action , maxTries , waitMilliseconds ) ;
2020-12-23 11:35:49 +01:00
public static void Try ( Action action , int maxTries = 5 , int waitMilliseconds = 200 ) = >
2020-10-26 10:47:14 +00:00
Try < Exception > ( action , maxTries , waitMilliseconds ) ;
public static void Try < T > ( Action action , int maxTries = 5 , int waitMilliseconds = 200 )
where T : Exception
{
2020-12-23 11:35:49 +01:00
int tries = 0 ;
2020-10-26 10:47:14 +00:00
while ( true )
{
try
{
action ( ) ;
break ;
}
catch ( T )
{
if ( tries + + > maxTries )
2020-12-23 11:35:49 +01:00
{
2020-10-26 10:47:14 +00:00
throw ;
2020-12-23 11:35:49 +01:00
}
2020-10-26 10:47:14 +00:00
Thread . Sleep ( waitMilliseconds ) ;
}
}
}
2020-03-13 14:43:41 +11:00
}
}