// Copyright (c) Umbraco. // See LICENSE for more details. using System; using System.IO; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; 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.DistributedLocking; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Net; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; using Umbraco.Cms.Infrastructure.Scoping; using Umbraco.Cms.Infrastructure.Serialization; using Umbraco.Cms.Tests.Common.TestHelpers; using Umbraco.Extensions; namespace Umbraco.Cms.Tests.Common; /// /// Common helper properties and methods useful to testing /// public abstract class TestHelperBase { private readonly ITypeFinder _typeFinder; private IIOHelper _ioHelper; private UriUtility _uriUtility; private string _workingDir; protected TestHelperBase(Assembly entryAssembly) { MainDom = new SimpleMainDom(); _typeFinder = new TypeFinder(NullLoggerFactory.Instance.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly, NullLoggerFactory.Instance), null); } /// /// Gets the working directory of the test project. /// public string WorkingDirectory { get { if (_workingDir != null) { return _workingDir; } // Azure DevOps can only store a database in certain locations so we will need to detect if we are running // on a build server and if so we'll use the temp path. var dir = string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("System_DefaultWorkingDirectory")) ? Path.Combine(Assembly.GetExecutingAssembly().GetRootDirectorySafe(), "TEMP") : Path.Combine(Path.GetTempPath(), "UmbracoTests", "TEMP"); if (!Directory.Exists(dir)) { _ = Directory.CreateDirectory(dir); } _workingDir = dir; return _workingDir; } } public IShortStringHelper ShortStringHelper { get; } = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); public IScopeProvider ScopeProvider { get { var loggerFactory = NullLoggerFactory.Instance; var fileSystems = new FileSystems( loggerFactory, Mock.Of(), Mock.Of>(), Mock.Of()); var mediaFileManager = new MediaFileManager( Mock.Of(), Mock.Of(), loggerFactory.CreateLogger(), Mock.Of(), Mock.Of(), Options.Create(new ContentSettings())); var databaseFactory = new Mock(); var database = new Mock(); var sqlContext = new Mock(); var lockingMechanism = new Mock(); lockingMechanism.Setup(x => x.ReadLock(It.IsAny(), It.IsAny())) .Returns(Mock.Of()); lockingMechanism.Setup(x => x.WriteLock(It.IsAny(), It.IsAny())) .Returns(Mock.Of()); var lockingMechanismFactory = new Mock(); lockingMechanismFactory.Setup(x => x.DistributedLockingMechanism) .Returns(lockingMechanism.Object); // Setup mock of database factory to return mock of database. databaseFactory.Setup(x => x.CreateDatabase()).Returns(database.Object); databaseFactory.Setup(x => x.SqlContext).Returns(sqlContext.Object); // Setup mock of database to return mock of sql SqlContext database.Setup(x => x.SqlContext).Returns(sqlContext.Object); var syntaxProviderMock = new Mock(); // Setup mock of ISqlContext to return syntaxProviderMock sqlContext.Setup(x => x.SqlSyntax).Returns(syntaxProviderMock.Object); return new ScopeProvider( new AmbientScopeStack(), new AmbientScopeContextStack(), lockingMechanismFactory.Object, databaseFactory.Object, fileSystems, new TestOptionsMonitor(new CoreDebugSettings()), mediaFileManager, loggerFactory, Mock.Of()); } } public IJsonSerializer JsonSerializer { get; } = new SystemTextJsonSerializer(); public IVariationContextAccessor VariationContextAccessor { get; } = new TestVariationContextAccessor(); public abstract IBulkSqlInsertProvider BulkSqlInsertProvider { get; } public abstract IMarchal Marchal { get; } public CoreDebugSettings CoreDebugSettings { get; } = new(); public IIOHelper IOHelper { get { if (_ioHelper == null) { var hostingEnvironment = GetHostingEnvironment(); if (TestEnvironment.IsWindows) { _ioHelper = new IOHelperWindows(hostingEnvironment); } else if (TestEnvironment.IsLinux) { _ioHelper = new IOHelperLinux(hostingEnvironment); } else if (TestEnvironment.IsOSX) { _ioHelper = new IOHelperOSX(hostingEnvironment); } else { throw new NotSupportedException("Unexpected OS"); } } return _ioHelper; } } public IMainDom MainDom { get; } public UriUtility UriUtility { get { if (_uriUtility == null) { _uriUtility = new UriUtility(GetHostingEnvironment()); } return _uriUtility; } } public ITypeFinder GetTypeFinder() => _typeFinder; public TypeLoader GetMockedTypeLoader() => new( Mock.Of(), new VaryingRuntimeHash(), Mock.Of(), new DirectoryInfo(GetHostingEnvironment() .MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); /// /// 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 /// public virtual string MapPathForTestFiles(string relativePath) { if (!relativePath.StartsWith("~/")) { throw new ArgumentException("relativePath must start with '~/'", nameof(relativePath)); } var codeBase = typeof(TestHelperBase).Assembly.CodeBase; var uri = new Uri(codeBase); var path = uri.LocalPath; var bin = Path.GetDirectoryName(path); return relativePath.Replace("~/", bin + "/"); } public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(); public IServiceCollection GetRegister() => new ServiceCollection(); public abstract IHostingEnvironment GetHostingEnvironment(); public abstract IApplicationShutdownRegistry GetHostingEnvironmentLifetime(); public abstract IIpResolver GetIpResolver(); public IRequestCache GetRequestCache() => new DictionaryAppCache(); public IPublishedUrlProvider GetPublishedUrlProvider() { var mock = new Mock(); return mock.Object; } public ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv = null) { hostingEnv ??= GetHostingEnvironment(); return new LoggingConfiguration( Path.Combine(hostingEnv.ApplicationPhysicalPath, "umbraco", "Logs")); } }