2018-06-29 19:52:40 +02:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Threading ;
2020-02-13 13:57:39 +01:00
using System.Web ;
2019-11-11 18:56:14 +11:00
using Moq ;
2018-06-29 19:52:40 +02:00
using NUnit.Framework ;
using Umbraco.Core ;
2019-11-11 18:56:14 +11:00
using Umbraco.Core.Cache ;
2019-11-08 07:51:14 +01:00
using Umbraco.Core.Composing ;
2019-11-13 14:15:50 +01:00
using Umbraco.Core.Configuration ;
2019-11-19 11:44:34 +01:00
using Umbraco.Core.Configuration.UmbracoSettings ;
2019-12-18 12:27:14 +01:00
using Umbraco.Core.Diagnostics ;
2019-11-20 13:38:41 +01:00
using Umbraco.Core.Hosting ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.IO ;
2019-11-11 18:56:14 +11:00
using Umbraco.Core.Logging ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.Models ;
using Umbraco.Core.Models.Entities ;
2019-12-19 10:43:00 +01:00
using Umbraco.Core.Models.PublishedContent ;
2020-03-25 16:52:42 +11:00
using Umbraco.Net ;
2019-12-12 08:11:23 +01:00
using Umbraco.Core.Persistence ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.PropertyEditors ;
2020-01-28 17:07:06 +11:00
using Umbraco.Core.Serialization ;
2019-11-12 13:40:07 +01:00
using Umbraco.Core.Services ;
2019-12-05 10:41:58 +01:00
using Umbraco.Core.Strings ;
2020-05-06 20:37:03 +02:00
using Umbraco.Persistance.SqlCe ;
2020-03-13 12:08:25 +11:00
using Umbraco.Tests.Common ;
2019-11-21 14:19:56 +01:00
using Umbraco.Web ;
2019-11-20 13:38:41 +01:00
using Umbraco.Web.Hosting ;
2020-02-14 13:04:49 +01:00
using Umbraco.Web.Routing ;
2018-06-29 19:52:40 +02:00
using File = System . IO . File ;
namespace Umbraco.Tests.TestHelpers
{
/// <summary>
/// Common helper properties and methods useful to testing
/// </summary>
public static class TestHelper
{
2020-03-25 15:06:22 +11:00
private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal ( ) ;
2020-03-13 12:08:25 +11:00
private class TestHelperInternal : TestHelperBase
2020-03-09 13:31:56 +11:00
{
2020-03-13 14:43:41 +11:00
public TestHelperInternal ( ) : base ( typeof ( TestHelperInternal ) . Assembly )
{
}
2020-05-08 17:30:30 +10:00
public override IDbProviderFactoryCreator DbProviderFactoryCreator { get ; } = new UmbracoDbProviderFactoryCreator ( ) ;
2020-03-09 13:31:56 +11:00
2020-03-13 12:08:25 +11:00
public override IBulkSqlInsertProvider BulkSqlInsertProvider { get ; } = new SqlCeBulkSqlInsertProvider ( ) ;
2018-06-29 19:52:40 +02:00
2020-03-13 12:08:25 +11:00
public override IMarchal Marchal { get ; } = new FrameworkMarchal ( ) ;
2019-11-13 10:48:51 +01:00
2020-03-13 12:08:25 +11:00
public override IBackOfficeInfo GetBackOfficeInfo ( )
2020-03-13 12:33:28 +11:00
= > new AspNetBackOfficeInfo (
2020-03-23 17:15:32 +11:00
SettingsForTests . GenerateMockGlobalSettings ( GetUmbracoVersion ( ) ) ,
2020-03-13 12:33:28 +11:00
TestHelper . IOHelper , Mock . Of < ILogger > ( ) , SettingsForTests . GenerateMockWebRoutingSettings ( ) ) ;
2019-11-21 14:19:56 +01:00
2020-03-13 12:08:25 +11:00
public override IHostingEnvironment GetHostingEnvironment ( )
2020-04-03 17:05:50 +11:00
= > new AspNetHostingEnvironment ( SettingsForTests . DefaultHostingSettings ) ;
2020-03-13 12:08:25 +11:00
2020-03-26 15:39:20 +11:00
public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime ( )
= > new AspNetApplicationShutdownRegistry ( ) ;
2020-03-25 15:06:22 +11:00
2020-03-13 12:08:25 +11:00
public override IIpResolver GetIpResolver ( )
= > new AspNetIpResolver ( ) ;
2019-11-12 14:11:08 +01:00
}
2018-06-29 19:52:40 +02:00
2020-03-13 12:08:25 +11:00
public static ITypeFinder GetTypeFinder ( ) = > _testHelperInternal . GetTypeFinder ( ) ;
public static TypeLoader GetMockedTypeLoader ( ) = > _testHelperInternal . GetMockedTypeLoader ( ) ;
2020-03-23 17:15:32 +11:00
public static Configs GetConfigs ( ) = > _testHelperInternal . GetConfigs ( ) ;
2020-03-13 12:08:25 +11:00
public static IRuntimeState GetRuntimeState ( ) = > _testHelperInternal . GetRuntimeState ( ) ;
public static IBackOfficeInfo GetBackOfficeInfo ( ) = > _testHelperInternal . GetBackOfficeInfo ( ) ;
2020-03-23 17:15:32 +11:00
public static IConfigsFactory GetConfigsFactory ( ) = > _testHelperInternal . GetConfigsFactory ( ) ;
2020-03-13 12:08:25 +11:00
2018-06-29 19:52:40 +02:00
/// <summary>
2020-03-31 17:27:51 +11:00
/// Gets the working directory of the test project.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <value>The assembly directory.</value>
2020-03-31 17:27:51 +11:00
public static string WorkingDirectory = > _testHelperInternal . WorkingDirectory ;
2018-06-29 19:52:40 +02:00
2020-03-13 12:08:25 +11:00
public static IShortStringHelper ShortStringHelper = > _testHelperInternal . ShortStringHelper ;
public static IJsonSerializer JsonSerializer = > _testHelperInternal . JsonSerializer ;
public static IVariationContextAccessor VariationContextAccessor = > _testHelperInternal . VariationContextAccessor ;
public static IDbProviderFactoryCreator DbProviderFactoryCreator = > _testHelperInternal . DbProviderFactoryCreator ;
public static IBulkSqlInsertProvider BulkSqlInsertProvider = > _testHelperInternal . BulkSqlInsertProvider ;
public static IMarchal Marchal = > _testHelperInternal . Marchal ;
2020-03-16 14:02:08 +01:00
public static ICoreDebugSettings CoreDebugSettings = > _testHelperInternal . CoreDebugSettings ;
2019-12-05 10:41:58 +01:00
2019-12-19 12:27:05 +01:00
2020-03-13 12:08:25 +11:00
public static IIOHelper IOHelper = > _testHelperInternal . IOHelper ;
public static IMainDom MainDom = > _testHelperInternal . MainDom ;
public static UriUtility UriUtility = > _testHelperInternal . UriUtility ;
2020-02-17 12:07:51 +01:00
2020-03-13 12:08:25 +11:00
public static IWebRoutingSettings WebRoutingSettings = > _testHelperInternal . WebRoutingSettings ;
2020-02-14 13:04:49 +01:00
2020-03-31 17:27:51 +11:00
2018-06-29 19:52:40 +02:00
/// <summary>
2020-03-31 17:27:51 +11:00
/// 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
2018-06-29 19:52:40 +02:00
/// </summary>
2020-03-31 17:27:51 +11:00
/// <param name="relativePath"></param>
2018-06-29 19:52:40 +02:00
/// <returns></returns>
2020-03-31 17:27:51 +11:00
public static string MapPathForTestFiles ( string relativePath ) = > _testHelperInternal . MapPathForTestFiles ( relativePath ) ;
2018-06-29 19:52:40 +02:00
public static void InitializeContentDirectories ( )
{
2019-11-13 15:52:18 +01:00
CreateDirectories ( new [ ] { Constants . SystemDirectories . MvcViews , SettingsForTests . GenerateMockGlobalSettings ( ) . UmbracoMediaPath , Constants . SystemDirectories . AppPlugins } ) ;
2018-06-29 19:52:40 +02:00
}
public static void CleanContentDirectories ( )
{
2019-11-13 15:52:18 +01:00
CleanDirectories ( new [ ] { Constants . SystemDirectories . MvcViews , SettingsForTests . GenerateMockGlobalSettings ( ) . UmbracoMediaPath } ) ;
2018-06-29 19:52:40 +02:00
}
public static void CreateDirectories ( string [ ] directories )
{
foreach ( var directory in directories )
{
2019-11-26 08:15:00 +01:00
var directoryInfo = new DirectoryInfo ( IOHelper . MapPath ( directory ) ) ;
2018-06-29 19:52:40 +02:00
if ( directoryInfo . Exists = = false )
2019-11-26 08:15:00 +01:00
Directory . CreateDirectory ( IOHelper . MapPath ( directory ) ) ;
2018-06-29 19:52:40 +02:00
}
}
public static void CleanDirectories ( string [ ] directories )
{
var preserves = new Dictionary < string , string [ ] >
{
2019-11-13 11:26:03 +01:00
{ Constants . SystemDirectories . MvcViews , new [ ] { "dummy.txt" } }
2018-06-29 19:52:40 +02:00
} ;
foreach ( var directory in directories )
{
2019-11-26 08:15:00 +01:00
var directoryInfo = new DirectoryInfo ( IOHelper . MapPath ( directory ) ) ;
2018-06-29 19:52:40 +02:00
var preserve = preserves . ContainsKey ( directory ) ? preserves [ directory ] : null ;
2018-05-03 15:09:56 +02:00
if ( directoryInfo . Exists )
foreach ( var x in directoryInfo . GetFiles ( ) . Where ( x = > preserve = = null | | preserve . Contains ( x . Name ) = = false ) )
2018-06-29 19:52:40 +02:00
x . Delete ( ) ;
}
}
public static void CleanUmbracoSettingsConfig ( )
{
2020-03-31 17:27:51 +11:00
var currDir = new DirectoryInfo ( WorkingDirectory ) ;
2018-06-29 19:52:40 +02:00
var umbracoSettingsFile = Path . Combine ( currDir . Parent . Parent . FullName , "config" , "umbracoSettings.config" ) ;
if ( File . Exists ( umbracoSettingsFile ) )
File . Delete ( umbracoSettingsFile ) ;
}
2020-03-13 12:08:25 +11:00
// TODO: Move to Assertions or AssertHelper
2019-01-27 01:17:32 -05:00
// FIXME: obsolete the dateTimeFormat thing and replace with dateDelta
2018-06-29 19:52:40 +02:00
public static void AssertPropertyValuesAreEqual ( object actual , object expected , string dateTimeFormat = null , Func < IEnumerable , IEnumerable > sorter = null , string [ ] ignoreProperties = null )
{
const int dateDeltaMilliseconds = 500 ; // .5s
var properties = expected . GetType ( ) . GetProperties ( ) ;
foreach ( var property in properties )
{
// ignore properties that are attributed with EditorBrowsableState.Never
var att = property . GetCustomAttribute < EditorBrowsableAttribute > ( false ) ;
if ( att ! = null & & att . State = = EditorBrowsableState . Never )
continue ;
// ignore explicitely ignored properties
if ( ignoreProperties ! = null & & ignoreProperties . Contains ( property . Name ) )
continue ;
var actualValue = property . GetValue ( actual , null ) ;
var expectedValue = property . GetValue ( expected , null ) ;
AssertAreEqual ( property , expectedValue , actualValue , sorter , dateDeltaMilliseconds ) ;
}
}
private static void AssertAreEqual ( PropertyInfo property , object expected , object actual , Func < IEnumerable , IEnumerable > sorter = null , int dateDeltaMilliseconds = 0 )
{
if ( ! ( expected is string ) & & expected is IEnumerable )
{
2018-08-30 12:51:55 +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 )
sorter = e = > ( ( PropertyCollection ) e ) . OrderBy ( x = > x . Alias ) ;
2018-06-29 19:52:40 +02:00
// compare lists
AssertListsAreEqual ( property , ( IEnumerable ) actual , ( IEnumerable ) expected , sorter , dateDeltaMilliseconds ) ;
}
else if ( expected is DateTime expectedDateTime )
{
// compare date & time with delta
var actualDateTime = ( DateTime ) actual ;
var delta = ( actualDateTime - expectedDateTime ) . TotalMilliseconds ;
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
var actualProperty = ( Property ) actual ;
var expectedPropertyValues = expectedProperty . Values . OrderBy ( x = > x . Culture ) . ThenBy ( x = > x . Segment ) . ToArray ( ) ;
var actualPropertyValues = actualProperty . Values . OrderBy ( x = > x . Culture ) . ThenBy ( x = > x . Segment ) . ToArray ( ) ;
if ( expectedPropertyValues . Length ! = actualPropertyValues . Length )
Assert . Fail ( $"{property.DeclaringType.Name}.{property.Name}: Expected {expectedPropertyValues.Length} but got {actualPropertyValues.Length}." ) ;
for ( var i = 0 ; i < expectedPropertyValues . Length ; i + + )
{
Assert . AreEqual ( expectedPropertyValues [ i ] . EditedValue , actualPropertyValues [ i ] . EditedValue , $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \" { expectedPropertyValues [ i ] . EditedValue } \ " but got \"{actualPropertyValues[i].EditedValue}\"." ) ;
Assert . AreEqual ( expectedPropertyValues [ i ] . PublishedValue , actualPropertyValues [ i ] . PublishedValue , $"{property.DeclaringType.Name}.{property.Name}: Expected published value \" { expectedPropertyValues [ i ] . EditedValue } \ " but got \"{actualPropertyValues[i].EditedValue}\"." ) ;
}
}
else if ( expected is IDataEditor expectedEditor )
{
Assert . IsInstanceOf < IDataEditor > ( actual ) ;
var actualEditor = ( IDataEditor ) actual ;
Assert . AreEqual ( expectedEditor . Alias , actualEditor . Alias ) ;
// what else shall we test?
}
else
{
// directly compare values
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>" ) ;
}
}
private static void AssertListsAreEqual ( PropertyInfo property , IEnumerable expected , IEnumerable actual , Func < IEnumerable , IEnumerable > sorter = null , int dateDeltaMilliseconds = 0 )
{
2018-08-30 12:51:55 +02:00
2018-06-29 19:52:40 +02:00
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 ( ) ;
return entities . Count > 0 ? ( IEnumerable ) entities . OrderBy ( x = > x . Id ) : entities ;
} ;
}
var expectedListEx = sorter ( expected ) . Cast < object > ( ) . ToList ( ) ;
var actualListEx = sorter ( actual ) . Cast < object > ( ) . ToList ( ) ;
if ( actualListEx . Count ! = expectedListEx . Count )
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 ) ;
for ( var i = 0 ; i < actualListEx . Count ; i + + )
AssertAreEqual ( property , expectedListEx [ i ] , actualListEx [ i ] , sorter , dateDeltaMilliseconds ) ;
}
public static void DeleteDirectory ( string path )
{
Try ( ( ) = >
{
if ( Directory . Exists ( path ) = = false ) return ;
foreach ( var file in Directory . EnumerateFiles ( path , "*" , SearchOption . AllDirectories ) )
File . Delete ( file ) ;
} ) ;
Try ( ( ) = >
{
if ( Directory . Exists ( path ) = = false ) return ;
Directory . Delete ( path , true ) ;
} ) ;
}
public static void TryAssert ( Action action , int maxTries = 5 , int waitMilliseconds = 200 )
{
Try < AssertionException > ( action , maxTries , waitMilliseconds ) ;
}
public static void Try ( Action action , int maxTries = 5 , int waitMilliseconds = 200 )
{
Try < Exception > ( action , maxTries , waitMilliseconds ) ;
}
public static void Try < T > ( Action action , int maxTries = 5 , int waitMilliseconds = 200 )
where T : Exception
{
var tries = 0 ;
while ( true )
{
try
{
action ( ) ;
break ;
}
catch ( T )
{
if ( tries + + > maxTries )
throw ;
Thread . Sleep ( waitMilliseconds ) ;
}
}
}
2019-11-12 13:40:07 +01:00
2020-03-13 12:08:25 +11:00
// TODO: Move to MockedValueEditors.cs
2019-11-12 13:40:07 +01:00
public static DataValueEditor CreateDataValueEditor ( string name )
{
var valueType = ( ValueTypes . IsValue ( name ) ) ? name : ValueTypes . String ;
return new DataValueEditor (
Mock . Of < IDataTypeService > ( ) ,
Mock . Of < ILocalizationService > ( ) ,
2019-12-11 08:13:51 +01:00
Mock . Of < ILocalizedTextService > ( ) ,
2019-12-09 09:00:00 +01:00
Mock . Of < IShortStringHelper > ( ) ,
2019-11-12 13:40:07 +01:00
new DataEditorAttribute ( name , name , name )
{
ValueType = valueType
}
) ;
}
2019-11-13 10:48:51 +01:00
2020-03-23 17:15:32 +11:00
public static IUmbracoVersion GetUmbracoVersion ( ) = > _testHelperInternal . GetUmbracoVersion ( ) ;
2019-11-15 11:07:37 +01:00
2020-03-13 12:08:25 +11:00
public static IRegister GetRegister ( ) = > _testHelperInternal . GetRegister ( ) ;
2019-11-20 13:38:41 +01:00
2020-03-13 12:08:25 +11:00
public static IHostingEnvironment GetHostingEnvironment ( ) = > _testHelperInternal . GetHostingEnvironment ( ) ;
2019-11-26 12:47:48 +01:00
2020-04-22 14:23:56 +10:00
public static ILoggingConfiguration GetLoggingConfiguration ( IHostingEnvironment hostingEnv ) = > _testHelperInternal . GetLoggingConfiguration ( hostingEnv ) ;
2020-03-26 15:39:20 +11:00
public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime ( ) = > _testHelperInternal . GetHostingEnvironmentLifetime ( ) ;
2020-03-25 15:06:22 +11:00
2020-03-13 12:08:25 +11:00
public static IIpResolver GetIpResolver ( ) = > _testHelperInternal . GetIpResolver ( ) ;
2019-12-04 09:43:22 +01:00
2020-03-13 12:08:25 +11:00
public static IRequestCache GetRequestCache ( ) = > _testHelperInternal . GetRequestCache ( ) ;
2020-02-13 13:57:39 +01:00
public static IHttpContextAccessor GetHttpContextAccessor ( HttpContextBase httpContextBase = null )
{
if ( httpContextBase is null )
{
var httpContextMock = new Mock < HttpContextBase > ( ) ;
httpContextMock . Setup ( x = > x . DisposeOnPipelineCompleted ( It . IsAny < IDisposable > ( ) ) )
. Returns ( Mock . Of < ISubscriptionToken > ( ) ) ;
2020-02-14 13:04:49 +01:00
2020-02-13 13:57:39 +01:00
httpContextBase = httpContextMock . Object ;
}
var mock = new Mock < IHttpContextAccessor > ( ) ;
mock . Setup ( x = > x . HttpContext ) . Returns ( httpContextBase ) ;
return mock . Object ;
}
2020-02-14 13:04:49 +01:00
2020-03-13 12:08:25 +11:00
public static IPublishedUrlProvider GetPublishedUrlProvider ( ) = > _testHelperInternal . GetPublishedUrlProvider ( ) ;
2018-06-29 19:52:40 +02:00
}
}