Files
Umbraco-CMS/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs

325 lines
15 KiB
C#
Raw Normal View History

// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Diagnostics;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Mail;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Net;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Tests.Common;
2021-02-10 11:42:04 +01:00
using Umbraco.Cms.Web.Common.AspNetCore;
using Umbraco.Core;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Extensions;
using Umbraco.Infrastructure.Persistence.Mappers;
using Constants = Umbraco.Cms.Core.Constants;
using File = System.IO.File;
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Tests.TestHelpers
{
/// <summary>
/// Common helper properties and methods useful to testing
/// </summary>
public static class TestHelper
{
private static readonly TestHelperInternal s_testHelperInternal = new TestHelperInternal();
private class TestHelperInternal : TestHelperBase
{
public TestHelperInternal()
: base(typeof(TestHelperInternal).Assembly)
{
}
public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = Mock.Of<IDbProviderFactoryCreator>();
public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = Mock.Of<IBulkSqlInsertProvider>();
public override IMarchal Marchal { get; } = Mock.Of<IMarchal>();
public override IBackOfficeInfo GetBackOfficeInfo()
=> Mock.Of<IBackOfficeInfo>();
public override IHostingEnvironment GetHostingEnvironment()
{
var testPath = TestContext.CurrentContext.TestDirectory.Split("bin")[0];
return new AspNetCoreHostingEnvironment(
Mock.Of<IOptionsMonitor<HostingSettings>>(x => x.CurrentValue == new HostingSettings()),
Mock.Of<IOptionsMonitor<WebRoutingSettings>>(x => x.CurrentValue == new WebRoutingSettings()),
Mock.Of<IWebHostEnvironment>(
x =>
x.WebRootPath == "/" &&
x.ContentRootPath == testPath));
}
public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime()
=> Mock.Of<IApplicationShutdownRegistry>();
public override IIpResolver GetIpResolver()
=> Mock.Of<IIpResolver>();
}
public static ITypeFinder GetTypeFinder() => s_testHelperInternal.GetTypeFinder();
public static TypeLoader GetMockedTypeLoader() => s_testHelperInternal.GetMockedTypeLoader();
public static Lazy<ISqlContext> GetMockSqlContext()
{
ISqlContext sqlContext = Mock.Of<ISqlContext>();
var syntax = new SqlServerSyntaxProvider();
Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(syntax);
return new Lazy<ISqlContext>(() => sqlContext);
}
Netcore: Alternate approach for MSDI refactor (#9247) * Doesn't make much sense to have Concrete on IRegister, only on IFactory * Handle FilesTreeController requires IFileSystem of type PhysicalFileSystem * Handle registration of default MediaFileSystem without using RegisterUniqueFor * Remove RegisterFor / RegisterUniqueFor from IRegister * Switch over from LightInject to wrappers around MSDI * Made mapper dependencies more explicit * Remove registration for AngularJsonMediaTypeFormatter It's dependencies aren't registered so container validation fails * Resolve lifetime issue for EnsureValidSessionId by service locating else resolve scoped in singleton * Make registration more explicit for backoffice UserManager * Make install step registrations more explicit * Disable service provider validation so site can launch Maybe this is a problem maybe not, we build about 8000 service providers so maybe everything is fine later... * Further cleanup of IFactory interface * Further cleanup of IRegister interface * Revert "Make registration more explicit for backoffice UserManager" This reverts commit 7215fe836103c597cd0873c66737a79b91ed4c49. * Resolve issue where NewInstallStep would fail to reset password for "SuperUser" Before MSDI, somehow BackOfficeIdentityOptions would be configured with token provider map from IdentityBuilder.AddDefaultTokenProviders. After switchover those config actions are lost. Subclass IdentityBuilder to ensure BackOfficeIdentityOptions doesn't miss config setup upstream. * Initialize current. * Add todo to turn container validation back on. * Migrated ScopeFileSystemsTests to integration tests Signed-off-by: Bjarke Berg <mail@bergmania.dk> * Resolve issue where MediaFileSystem was skipping ShadowFileSystem * Attempt to fix ScopeFileSystemsTests on azure devops Signed-off-by: Bjarke Berg <mail@bergmania.dk> * Be interesting to know what the actual full path is in pipeline. * Clarify intent of CreateMediaTest Doesn't help resolve weird UnauthorizedAccessException but it cuts so much cognitive overhead for the future. * Use ILoggerfactory rather than mock for the manually constructed file PhysicalFileSystem * Maybe resolve failing test on azure pipeline. Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2020-10-26 10:47:14 +00:00
public static MapperConfigurationStore CreateMaps()
=> new MapperConfigurationStore();
//// public static Configs GetConfigs() => _testHelperInternal.GetConfigs();
public static IBackOfficeInfo GetBackOfficeInfo() => s_testHelperInternal.GetBackOfficeInfo();
//// public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory();
/// <summary>
/// Gets the working directory of the test project.
/// </summary>
/// <value>The assembly directory.</value>
public static string WorkingDirectory => s_testHelperInternal.WorkingDirectory;
public static IShortStringHelper ShortStringHelper => s_testHelperInternal.ShortStringHelper;
public static IJsonSerializer JsonSerializer => s_testHelperInternal.JsonSerializer;
public static IVariationContextAccessor VariationContextAccessor => s_testHelperInternal.VariationContextAccessor;
public static IDbProviderFactoryCreator DbProviderFactoryCreator => s_testHelperInternal.DbProviderFactoryCreator;
public static IBulkSqlInsertProvider BulkSqlInsertProvider => s_testHelperInternal.BulkSqlInsertProvider;
public static IMarchal Marchal => s_testHelperInternal.Marchal;
public static CoreDebugSettings CoreDebugSettings => s_testHelperInternal.CoreDebugSettings;
public static IIOHelper IOHelper => s_testHelperInternal.IOHelper;
public static IMainDom MainDom => s_testHelperInternal.MainDom;
public static UriUtility UriUtility => s_testHelperInternal.UriUtility;
public static IEmailSender EmailSender { get; } = new EmailSender(Options.Create(new GlobalSettings()));
/// <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 static string MapPathForTestFiles(string relativePath) => s_testHelperInternal.MapPathForTestFiles(relativePath);
public static void InitializeContentDirectories() => CreateDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath, Constants.SystemDirectories.AppPlugins });
public static void CleanContentDirectories() => CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath });
public static void CreateDirectories(string[] directories)
{
foreach (var directory in directories)
{
var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory));
if (directoryInfo.Exists == false)
{
Directory.CreateDirectory(IOHelper.MapPath(directory));
}
}
}
public static void CleanDirectories(string[] directories)
{
var preserves = new Dictionary<string, string[]>
{
{ Constants.SystemDirectories.MvcViews, new[] { "dummy.txt" } }
};
foreach (var directory in directories)
{
var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory));
var preserve = preserves.ContainsKey(directory) ? preserves[directory] : null;
if (directoryInfo.Exists)
{
foreach (FileInfo fileInfo in directoryInfo.GetFiles().Where(x => preserve == null || preserve.Contains(x.Name) == false))
{
fileInfo.Delete();
}
}
}
}
public static void CleanUmbracoSettingsConfig()
{
var currDir = new DirectoryInfo(WorkingDirectory);
var umbracoSettingsFile = Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config");
if (File.Exists(umbracoSettingsFile))
{
File.Delete(umbracoSettingsFile);
}
}
// TODO: Move to Assertions or AssertHelper
// FIXME: obsolete the dateTimeFormat thing and replace with dateDelta
public static void AssertPropertyValuesAreEqual(object actual, object expected, string dateTimeFormat = null, Func<IEnumerable, IEnumerable> sorter = null, string[] ignoreProperties = null)
{
const int dateDeltaMilliseconds = 500; // .5s
PropertyInfo[] properties = expected.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
// ignore properties that are attributed with EditorBrowsableState.Never
EditorBrowsableAttribute 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 enumerable)
{
// 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);
}
// compare lists
AssertListsAreEqual(property, (IEnumerable)actual, enumerable, 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;
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();
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)
{
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 IUmbracoVersion GetUmbracoVersion() => s_testHelperInternal.GetUmbracoVersion();
public static IServiceCollection GetServiceCollection() => new ServiceCollection().AddLazySupport();
public static IHostingEnvironment GetHostingEnvironment() => s_testHelperInternal.GetHostingEnvironment();
public static ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv) => s_testHelperInternal.GetLoggingConfiguration(hostingEnv);
public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => s_testHelperInternal.GetHostingEnvironmentLifetime();
public static IIpResolver GetIpResolver() => s_testHelperInternal.GetIpResolver();
public static IRequestCache GetRequestCache() => s_testHelperInternal.GetRequestCache();
public static IPublishedUrlProvider GetPublishedUrlProvider() => s_testHelperInternal.GetPublishedUrlProvider();
}
}