diff --git a/.gitattributes b/.gitattributes index c8987ade67..3241b6511c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -43,6 +43,7 @@ *.hs text=auto *.json text=auto *.xml text=auto +*.resx text=auto *.csproj text=auto merge=union *.vbproj text=auto merge=union diff --git a/.gitignore b/.gitignore index 022acb5db7..ea2ddfbb68 100644 --- a/.gitignore +++ b/.gitignore @@ -191,6 +191,7 @@ src/Umbraco.Web.UI/Umbraco/telemetrics-id.umb /src/Umbraco.Web.UI.NetCore/App_Data/Smidge/Cache/* /src/Umbraco.Web.UI.NetCore/umbraco/logs +src/Umbraco.Tests.Integration/umbraco/Data/ src/Umbraco.Tests.Integration/umbraco/logs/ src/Umbraco.Tests.Integration/Views/ diff --git a/NuGet.Config b/NuGet.Config index d6c63173f8..92eaf83792 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,13 +1,15 @@  - - - - - - + + + + + + + diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index a88f260431..bf2ca3c5a2 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -62,6 +62,7 @@ + diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index 8a99f941b0..92c2cb13ed 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -8,6 +8,19 @@ # Variables & their default values variables: buildConfiguration: 'Release' + SA_PASSWORD: UmbracoIntegration123! + +resources: + containers: + - container: mssql + image: mcr.microsoft.com/mssql/server:2017-latest + env: + ACCEPT_EULA: Y + SA_PASSWORD: $(SA_PASSWORD) + MSSQL_PID: Developer + ports: + - 1433:1433 + options: --name mssql stages: - stage: Linux @@ -31,27 +44,48 @@ stages: command: test projects: '**/*.Tests.UnitTests.csproj' -- stage: macOS_X + - job: Integration_Tests + services: + mssql: mssql + timeoutInMinutes: 120 + displayName: 'Integration Tests' + pool: + vmImage: 'ubuntu-latest' + steps: + + - task: UseDotNet@2 + displayName: 'Use .Net Core sdk 3.1.x' + inputs: + version: 3.1.x + + - task: DotNetCoreCLI@2 + displayName: 'dotnet test' + inputs: + command: test + projects: '**/Umbraco.Tests.Integration.csproj' + env: + UmbracoIntegrationTestConnectionString: 'Server=localhost,1433;User Id=sa;Password=$(SA_PASSWORD);' + +- stage: MacOS dependsOn: [] # this removes the implicit dependency on previous stage and causes this to run in parallel jobs: - - job: Unit_Tests - displayName: 'Unit Tests' - pool: - vmImage: 'macOS-latest' - steps: + - job: Unit_Tests + displayName: 'Unit Tests' + pool: + vmImage: 'macOS-latest' + steps: - - task: UseDotNet@2 - displayName: 'Use .Net Core sdk 3.1.x' - inputs: - version: 3.1.x - - - task: DotNetCoreCLI@2 - displayName: 'dotnet test' - inputs: - command: test - projects: '**/*.Tests.UnitTests.csproj' + - task: UseDotNet@2 + displayName: 'Use .Net Core sdk 3.1.x' + inputs: + version: 3.1.x + - task: DotNetCoreCLI@2 + displayName: 'dotnet test' + inputs: + command: test + projects: '**/*.Tests.UnitTests.csproj' - stage: Windows dependsOn: [] # this removes the implicit dependency on previous stage and causes this to run in parallel @@ -74,7 +108,6 @@ stages: command: test projects: '**\*.Tests.UnitTests.csproj' - - job: Integration_Tests timeoutInMinutes: 120 displayName: 'Integration Tests' @@ -87,11 +120,6 @@ stages: inputs: version: 3.1.x - - task: DotNetCoreCLI@2 - displayName: 'dotnet build' - inputs: - projects: '**\Umbraco.Tests.Integration.csproj' - - powershell: 'sqllocaldb start mssqllocaldb' displayName: 'Start MSSQL LocalDb' @@ -100,8 +128,6 @@ stages: inputs: command: test projects: '**\Umbraco.Tests.Integration.csproj' - arguments: '--no-build' - - job: Build_Artifacts displayName: 'Build Artifacts' @@ -144,6 +170,13 @@ stages: $continuous = "$($version.Release)-alpha.$(Build.BuildNumber)" } $ubuild.SetUmbracoVersion($continuous) + + #Update the version in template also + $templatePath = 'build/templates/UmbracoSolution/.template.config/template.json' + $a = Get-Content $templatePath -raw | ConvertFrom-Json + $a.symbols.version.defaultValue = $continuous + $a | ConvertTo-Json -depth 32| set-content $templatePath + Write-Host "Building: $continuous" - task: PowerShell@1 diff --git a/build/templates/UmbracoSolution/.template.config/template.json b/build/templates/UmbracoSolution/.template.config/template.json index 04f77a556e..6dc582ca26 100644 --- a/build/templates/UmbracoSolution/.template.config/template.json +++ b/build/templates/UmbracoSolution/.template.config/template.json @@ -9,7 +9,7 @@ "language": "C#", "type": "project" }, - "sourceName": "UmbracoSolution", // Will be replaced with the value provided via -n + "sourceName": "UmbracoSolution", "preferNameDirectory": true, "symbols": { "version": { diff --git a/src/Umbraco.Core/Cache/DistributedCache.cs b/src/Umbraco.Core/Cache/DistributedCache.cs index 698e97c610..7ad9f9569f 100644 --- a/src/Umbraco.Core/Cache/DistributedCache.cs +++ b/src/Umbraco.Core/Cache/DistributedCache.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), getNumericId, instances); @@ -61,7 +61,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == default(int)) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), id); } @@ -75,7 +75,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == Guid.Empty) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), id); } @@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || payload == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), payload); } @@ -97,7 +97,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || payloads == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), payloads.ToArray()); } @@ -125,7 +125,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty) return; - _serverMessenger.PerformRefreshAll( + _serverMessenger.QueueRefreshAll( GetRefresherById(refresherGuid)); } @@ -138,7 +138,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == default(int)) return; - _serverMessenger.PerformRemove( + _serverMessenger.QueueRemove( GetRefresherById(refresherGuid), id); } @@ -155,7 +155,7 @@ namespace Umbraco.Web.Cache /// public void Remove(Guid refresherGuid, Func getNumericId, params T[] instances) { - _serverMessenger.PerformRemove( + _serverMessenger.QueueRemove( GetRefresherById(refresherGuid), getNumericId, instances); @@ -164,9 +164,15 @@ namespace Umbraco.Web.Cache #endregion // helper method to get an ICacheRefresher by its unique identifier - private ICacheRefresher GetRefresherById(Guid refresherGuid) + private ICacheRefresher GetRefresherById(Guid refresherGuid) { - return _cacheRefreshers[refresherGuid]; + ICacheRefresher refresher = _cacheRefreshers[refresherGuid]; + if (refresher == null) + { + throw new InvalidOperationException($"No cache refresher found with id {refresherGuid}"); + } + + return refresher; } } } diff --git a/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs b/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs deleted file mode 100644 index 31e876892e..0000000000 --- a/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Cache -{ - public class DistributedCacheBinderComponent : IComponent - { - private readonly IDistributedCacheBinder _binder; - - public DistributedCacheBinderComponent(IDistributedCacheBinder distributedCacheBinder) - { - _binder = distributedCacheBinder; - } - - public void Initialize() - { - _binder.BindEvents(); - } - - public void Terminate() - { } - } -} diff --git a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs index 1c4de6cd8e..14089ba924 100644 --- a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Composing { diff --git a/src/Umbraco.Core/Composing/Composers.cs b/src/Umbraco.Core/Composing/Composers.cs index 47f272cbf4..91c8244324 100644 --- a/src/Umbraco.Core/Composing/Composers.cs +++ b/src/Umbraco.Core/Composing/Composers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -70,7 +70,6 @@ namespace Umbraco.Core.Composing foreach (var composer in composers) { - var componentType = composer.GetType(); composer.Compose(_builder); } } diff --git a/src/Umbraco.Core/Composing/CompositionExtensions.cs b/src/Umbraco.Core/Composing/CompositionExtensions.cs index e4e02443eb..d7b143df38 100644 --- a/src/Umbraco.Core/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Core/Composing/CompositionExtensions.cs @@ -1,5 +1,4 @@ -using System; -using Umbraco.Core; +using System; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Web.PublishedCache; diff --git a/src/Umbraco.Core/Composing/IPublishedCacheComposer .cs b/src/Umbraco.Core/Composing/IPublishedCacheComposer .cs deleted file mode 100644 index d88eb44ea3..0000000000 --- a/src/Umbraco.Core/Composing/IPublishedCacheComposer .cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Umbraco.Core.Composing -{ - public interface IPublishedCacheComposer : ICoreComposer - { } -} diff --git a/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs index edbf554a2c..9229a95cc3 100644 --- a/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Composing { diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs deleted file mode 100644 index 58aac7b811..0000000000 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.HealthCheck; -using Umbraco.Core.Manifest; -using Umbraco.Core.PropertyEditors; -using Umbraco.Web.Actions; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Dashboards; -using Umbraco.Web.Editors; -using Umbraco.Web.Routing; -using Umbraco.Web.Sections; -using Umbraco.Web.Tour; - -namespace Umbraco.Core -{ - public static partial class CompositionExtensions - { - - #region Collection Builders - - /// - /// Gets the actions collection builder. - /// - /// The builder. - /// - public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the content apps collection builder. - /// - /// The builder. - /// - public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the content finders collection builder. - /// - /// The builder. - /// - public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the editor validators collection builder. - /// - /// The builder. - /// - public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the health checks collection builder. - /// - /// The builder. - public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the TourFilters collection builder. - /// - public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the URL providers collection builder. - /// - /// The builder. - public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the media url providers collection builder. - /// - /// The builder. - public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the backoffice sections/applications collection builder. - /// - /// The builder. - public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the components collection builder. - /// - public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - - /// - /// Gets the backoffice dashboards collection builder. - /// - /// The builder. - public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add(); - - - /// - /// Gets the content finders collection builder. - /// - /// The builder. - /// - public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - #endregion - } -} diff --git a/src/Umbraco.Infrastructure/Configuration/Extensions/HealthCheckSettingsExtensions.cs b/src/Umbraco.Core/Configuration/Extensions/HealthCheckSettingsExtensions.cs similarity index 90% rename from src/Umbraco.Infrastructure/Configuration/Extensions/HealthCheckSettingsExtensions.cs rename to src/Umbraco.Core/Configuration/Extensions/HealthCheckSettingsExtensions.cs index 92c3608ac1..ae842cb040 100644 --- a/src/Umbraco.Infrastructure/Configuration/Extensions/HealthCheckSettingsExtensions.cs +++ b/src/Umbraco.Core/Configuration/Extensions/HealthCheckSettingsExtensions.cs @@ -1,9 +1,7 @@ using System; -using NCrontab; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -namespace Umbraco.Infrastructure.Configuration.Extensions +namespace Umbraco.Core.Configuration.Extensions { public static class HealthCheckSettingsExtensions { diff --git a/src/Umbraco.Core/Configuration/Models/UmbracoPluginSettings.cs b/src/Umbraco.Core/Configuration/Models/UmbracoPluginSettings.cs new file mode 100644 index 0000000000..907b29490d --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/UmbracoPluginSettings.cs @@ -0,0 +1,27 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; + +namespace Umbraco.Core.Configuration.Models +{ + /// + /// Typed configuration options for the plugins. + /// + public class UmbracoPluginSettings + { + /// + /// Gets or sets the allowed file extensions (including the period ".") that should be accessible from the browser. + /// + public ISet BrowsableFileExtensions { get; set; } = new HashSet(new[] + { + ".html", // markup + ".css", // styles + ".js", // scripts + ".jpg", ".jpeg", ".gif", ".png", ".svg", // images + ".eot", ".ttf", ".woff", // fonts + ".xml", ".json", ".config", // configurations + ".lic" // license + }); + } +} diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs index 2c9fe3caee..a60f29c39d 100644 --- a/src/Umbraco.Core/Constants-Configuration.cs +++ b/src/Umbraco.Core/Constants-Configuration.cs @@ -39,6 +39,7 @@ public const string ConfigMemberPassword = ConfigPrefix + "Security:MemberPassword"; public const string ConfigModelsBuilder = ConfigPrefix + "ModelsBuilder"; public const string ConfigNuCache = ConfigPrefix + "NuCache"; + public const string ConfigPlugins = ConfigPrefix + "Plugins"; public const string ConfigRequestHandler = ConfigPrefix + "RequestHandler"; public const string ConfigRuntime = ConfigPrefix + "Runtime"; public const string ConfigRuntimeMinification = ConfigPrefix + "RuntimeMinification"; diff --git a/src/Umbraco.Core/Constants-SystemDirectories.cs b/src/Umbraco.Core/Constants-SystemDirectories.cs index 6145f4190b..464896edd9 100644 --- a/src/Umbraco.Core/Constants-SystemDirectories.cs +++ b/src/Umbraco.Core/Constants-SystemDirectories.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core /// /// This is not the same as the Umbraco web folder which is configurable for serving front-end files. /// - public const string Umbraco = "~/Umbraco"; + public const string Umbraco = "~/umbraco"; /// /// The Umbraco data folder in the content root diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index 5d059d8a23..8199d9fbd0 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core +namespace Umbraco.Core { public static partial class Constants { @@ -7,10 +7,6 @@ /// public static class Web { - public const string UmbracoContextDataToken = "umbraco-context"; - public const string UmbracoDataToken = "umbraco"; - public const string PublishedDocumentRequestDataToken = "umbraco-doc-request"; - public const string CustomRouteDataToken = "umbraco-custom-route"; public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def"; /// diff --git a/src/Umbraco.Core/ServiceCollectionExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs similarity index 89% rename from src/Umbraco.Core/ServiceCollectionExtensions.cs rename to src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs index d1c89ea17e..97e70da9be 100644 --- a/src/Umbraco.Core/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,9 +1,10 @@ -using System; +using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Umbraco.Core; using Umbraco.Core.Composing; -namespace Umbraco.Core +namespace Umbraco.Core.DependencyInjection { public static class ServiceCollectionExtensions { @@ -21,7 +22,7 @@ namespace Umbraco.Core where TImplementing : class, TService1, TService2 { services.AddUnique(); - services.AddUnique(factory => (TImplementing) factory.GetRequiredService()); + services.AddUnique(factory => (TImplementing)factory.GetRequiredService()); } public static void AddUnique(this IServiceCollection services) @@ -48,9 +49,9 @@ namespace Umbraco.Core /// public static void AddUnique(this IServiceCollection services, TService instance) where TService : class - => services.Replace(ServiceDescriptor.Singleton(instance)); + => services.Replace(ServiceDescriptor.Singleton(instance)); - public static IServiceCollection AddLazySupport(this IServiceCollection services) + internal static IServiceCollection AddLazySupport(this IServiceCollection services) { services.Replace(ServiceDescriptor.Transient(typeof(Lazy<>), typeof(LazyResolve<>))); return services; diff --git a/src/Umbraco.Core/ServiceProviderExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs similarity index 96% rename from src/Umbraco.Core/ServiceProviderExtensions.cs rename to src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs index e0d3da2c03..a1cc779500 100644 --- a/src/Umbraco.Core/ServiceProviderExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; +using System; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.Composing; -namespace Umbraco.Core +namespace Umbraco.Core.DependencyInjection { /// /// Provides extension methods to the class. diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs new file mode 100644 index 0000000000..f6dc6fd6ff --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -0,0 +1,275 @@ +using System.Security.Cryptography; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.Manifest; +using Umbraco.Core.PackageActions; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Strings; +using Umbraco.Core.Trees; +using Umbraco.Web.Actions; +using Umbraco.Web.ContentApps; +using Umbraco.Web.Dashboards; +using Umbraco.Web.Editors; +using Umbraco.Web.HealthCheck; +using Umbraco.Web.HealthCheck.NotificationMethods; +using Umbraco.Web.Media.EmbedProviders; +using Umbraco.Web.Routing; +using Umbraco.Web.Sections; +using Umbraco.Web.Tour; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds all core collection builders + /// + internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder) + { + builder.CacheRefreshers().Add(() => builder.TypeLoader.GetCacheRefreshers()); + builder.DataEditors().Add(() => builder.TypeLoader.GetDataEditors()); + builder.Actions().Add(() => builder.TypeLoader.GetTypes()); + // register known content apps + builder.ContentApps() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + // all built-in finders in the correct order, + // devs can then modify this list on application startup + builder.ContentFinders() + .Append() + .Append() + .Append() + /*.Append() // disabled, this is an odd finder */ + .Append() + .Append(); + builder.EditorValidators().Add(() => builder.TypeLoader.GetTypes()); + builder.HealthChecks().Add(() => builder.TypeLoader.GetTypes()); + builder.HealthCheckNotificationMethods().Add(() => builder.TypeLoader.GetTypes()); + builder.TourFilters(); + builder.UrlProviders() + .Append() + .Append(); + builder.MediaUrlProviders() + .Append(); + // register back office sections in the order we want them rendered + builder.Sections() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + builder.Components(); + // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards + builder.Dashboards() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(builder.TypeLoader.GetTypes()); + builder.PackageActions().Add(() => builder.TypeLoader.GetPackageActions()); + builder.DataValueReferenceFactories(); + builder.PropertyValueConverters().Append(builder.TypeLoader.GetTypes()); + builder.UrlSegmentProviders().Append(); + builder.ManifestValueValidators() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(); + builder.ManifestFilters(); + builder.MediaUrlGenerators(); + // register OEmbed providers - no type scanning - all explicit opt-in of adding types, IEmbedProvider is not IDiscoverable + builder.OEmbedProviders() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + builder.SearchableTrees().Add(() => builder.TypeLoader.GetTypes()); + } + + /// + /// Gets the actions collection builder. + /// + /// The builder. + public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the content apps collection builder. + /// + /// The builder. + public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the content finders collection builder. + /// + /// The builder. + public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the editor validators collection builder. + /// + /// The builder. + public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the health checks collection builder. + /// + /// The builder. + public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + public static HealthCheckNotificationMethodCollectionBuilder HealthCheckNotificationMethods(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the TourFilters collection builder. + /// + public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the URL providers collection builder. + /// + /// The builder. + public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the media url providers collection builder. + /// + /// The builder. + public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice sections/applications collection builder. + /// + /// The builder. + public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the components collection builder. + /// + public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice dashboards collection builder. + /// + /// The builder. + public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the cache refreshers collection builder. + /// + /// The builder. + public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the package actions collection builder. + /// + /// The builder. + internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data editor collection builder. + /// + /// The builder. + public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data value reference factory collection builder. + /// + /// The builder. + public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the property value converters collection builder. + /// + /// The builder. + public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the url segment providers collection builder. + /// + /// The builder. + public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the validators collection builder. + /// + /// The builder. + internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the manifest filter collection builder. + /// + /// The builder. + public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the content finders collection builder. + /// + /// The builder. + public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice OEmbed Providers collection builder. + /// + /// The builder. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the back office searchable tree collection builder + /// + public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + } +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs new file mode 100644 index 0000000000..5bd2fe9e8c --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds Umbraco composers for plugins + /// + public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) + { + // TODO: Should have a better name + + IEnumerable composerTypes = builder.TypeLoader.GetTypes(); + IEnumerable enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); + new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); + + return builder; + } + } +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs new file mode 100644 index 0000000000..a31a44beeb --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Add Umbraco configuration services and options + /// + public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder) + { + // Register configuration validators. + builder.Services.AddSingleton, ContentSettingsValidator>(); + builder.Services.AddSingleton, GlobalSettingsValidator>(); + builder.Services.AddSingleton, HealthChecksSettingsValidator>(); + builder.Services.AddSingleton, RequestHandlerSettingsValidator>(); + + // Register configuration sections. + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigActiveDirectory)); + builder.Services.Configure(builder.Config.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigContent)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigCoreDebug)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExceptionFilter)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHealthChecks)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHosting)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigImaging)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExamine)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigKeepAlive)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigLogging)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigMemberPassword)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigNuCache)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRequestHandler)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntime)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigSecurity)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTours)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigUserPassword)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigWebRouting)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigPlugins)); + + return builder; + } + } +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs index a21ae74976..c24936b4fb 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Core.Events; namespace Umbraco.Core.DependencyInjection @@ -23,7 +24,15 @@ namespace Umbraco.Core.DependencyInjection where TNotification : INotification { // Register the handler as transient. This ensures that anything can be injected into it. - builder.Services.AddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); + var descriptor = new ServiceDescriptor(typeof(INotificationHandler), typeof(TNotificationHandler), ServiceLifetime.Transient); + + // TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 about whether + // we perform this duplicate check or not. + if (!builder.Services.Contains(descriptor)) + { + builder.Services.Add(descriptor); + } + return builder; } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index d56712cdcf..96f01d111a 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -3,28 +3,65 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Mail; +using Umbraco.Core.Manifest; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Runtime; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Core.Sync; +using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.Editors; +using Umbraco.Web.Features; +using Umbraco.Web.Install; +using Umbraco.Web.Models.PublishedContent; +using Umbraco.Web.Routing; +using Umbraco.Web.Services; +using Umbraco.Web.Templates; namespace Umbraco.Core.DependencyInjection { public class UmbracoBuilder : IUmbracoBuilder { - public IServiceCollection Services { get; } - public IConfiguration Config { get; } - public TypeLoader TypeLoader { get; } - public ILoggerFactory BuilderLoggerFactory { get; } - private readonly Dictionary _builders = new Dictionary(); + public IServiceCollection Services { get; } + + public IConfiguration Config { get; } + + public TypeLoader TypeLoader { get; } + + public ILoggerFactory BuilderLoggerFactory { get; } + + /// + /// Initializes a new instance of the class. + /// public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader) : this(services, config, typeLoader, NullLoggerFactory.Instance) { } + /// + /// Initializes a new instance of the class. + /// public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory) { Services = services; @@ -43,10 +80,12 @@ namespace Umbraco.Core.DependencyInjection public TBuilder WithCollectionBuilder() where TBuilder : ICollectionBuilder, new() { - var typeOfBuilder = typeof(TBuilder); + Type typeOfBuilder = typeof(TBuilder); - if (_builders.TryGetValue(typeOfBuilder, out var o)) + if (_builders.TryGetValue(typeOfBuilder, out ICollectionBuilder o)) + { return (TBuilder)o; + } var builder = new TBuilder(); _builders[typeOfBuilder] = builder; @@ -55,8 +94,10 @@ namespace Umbraco.Core.DependencyInjection public void Build() { - foreach (var builder in _builders.Values) + foreach (ICollectionBuilder builder in _builders.Values) + { builder.RegisterWith(Services); + } _builders.Clear(); } @@ -66,6 +107,115 @@ namespace Umbraco.Core.DependencyInjection // Register as singleton to allow injection everywhere. Services.AddSingleton(p => p.GetService); Services.AddSingleton(); + + Services.AddLazySupport(); + + // Adds no-op registrations as many core services require these dependencies but these + // dependencies cannot be fulfilled in the Core project + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(factory => + { + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return new IOHelperLinux(hostingEnvironment); + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return new IOHelperOSX(hostingEnvironment); + } + + return new IOHelperWindows(hostingEnvironment); + }); + + Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); + Services.AddUnique(factory => factory.GetRequiredService().RequestCache); + Services.AddUnique(); + Services.AddUnique(); + + this.AddAllCoreCollectionBuilders(); + this.AddNotificationHandler(); + + Services.AddSingleton(); + this.AddNotificationHandler(); + + Services.AddUnique(); + + // by default, register a noop factory + Services.AddUnique(); + + Services.AddUnique(); + Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); + + Services.AddUnique(); + + Services.AddUnique(); + + // will be injected in controllers when needed to invoke rest endpoints on Our + Services.AddUnique(); + Services.AddUnique(); + + // Grid config is not a real config file as we know them + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + // register properties fallback + Services.AddUnique(); + + Services.AddUnique(); + + // register published router + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + // register distributed cache + Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); + + // register the http context and umbraco context accessors + // we *should* use the HttpContextUmbracoContextAccessor, however there are cases when + // we have no http context, eg when booting Umbraco or in background threads, so instead + // let's use an hybrid accessor that can fall back to a ThreadStatic context. + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + // register a server registrar, by default it's the db registrar + Services.AddUnique(f => + { + GlobalSettings globalSettings = f.GetRequiredService>().Value; + var singleServer = globalSettings.DisableElectionForSingleServer; + return singleServer + ? (IServerRoleAccessor)new SingleServerRoleAccessor() + : new ElectedServerRoleAccessor(f.GetRequiredService()); + }); } } } diff --git a/src/Umbraco.Infrastructure/Diagnostics/IMarchal.cs b/src/Umbraco.Core/Diagnostics/IMarchal.cs similarity index 58% rename from src/Umbraco.Infrastructure/Diagnostics/IMarchal.cs rename to src/Umbraco.Core/Diagnostics/IMarchal.cs index 30e6a9e619..cde4592b1b 100644 --- a/src/Umbraco.Infrastructure/Diagnostics/IMarchal.cs +++ b/src/Umbraco.Core/Diagnostics/IMarchal.cs @@ -7,6 +7,10 @@ namespace Umbraco.Core.Diagnostics /// public interface IMarchal { + /// + /// Retrieves a computer-independent description of an exception, and information about the state that existed for the thread when the exception occurred. + /// + /// A pointer to an EXCEPTION_POINTERS structure. IntPtr GetExceptionPointers(); } } diff --git a/src/Umbraco.Infrastructure/Diagnostics/MiniDump.cs b/src/Umbraco.Core/Diagnostics/MiniDump.cs similarity index 98% rename from src/Umbraco.Infrastructure/Diagnostics/MiniDump.cs rename to src/Umbraco.Core/Diagnostics/MiniDump.cs index f2f730078f..51f595bfb2 100644 --- a/src/Umbraco.Infrastructure/Diagnostics/MiniDump.cs +++ b/src/Umbraco.Core/Diagnostics/MiniDump.cs @@ -2,9 +2,7 @@ using System; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -using Umbraco.Core.Composing; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; namespace Umbraco.Core.Diagnostics { @@ -12,7 +10,7 @@ namespace Umbraco.Core.Diagnostics // and https://blogs.msdn.microsoft.com/dondu/2010/10/31/writing-minidumps-from-exceptions-in-c/ // which itself got it from http://blog.kalmbach-software.de/2008/12/13/writing-minidumps-in-c/ - internal static class MiniDump + public static class MiniDump { private static readonly object LockO = new object(); @@ -92,7 +90,9 @@ namespace Umbraco.Core.Diagnostics exp.ExceptionPointers = IntPtr.Zero; if (withException) + { exp.ExceptionPointers = marchal.GetExceptionPointers(); + } var bRet = exp.ExceptionPointers == IntPtr.Zero ? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) diff --git a/src/Umbraco.Core/Diagnostics/NoopMarchal.cs b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs new file mode 100644 index 0000000000..09629f9595 --- /dev/null +++ b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Core.Diagnostics +{ + internal class NoopMarchal : IMarchal + { + public IntPtr GetExceptionPointers() => IntPtr.Zero; + } +} diff --git a/src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionary.cs b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs similarity index 98% rename from src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionary.cs rename to src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs index b0690c944b..1f23ec645c 100644 --- a/src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionary.cs +++ b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Dictionary /// The ILocalizationService is the service used for interacting with this data from the database which isn't all that fast /// (even though there is caching involved, if there's lots of dictionary items the caching is not great) /// - public class DefaultCultureDictionary : ICultureDictionary + internal class DefaultCultureDictionary : ICultureDictionary { private readonly ILocalizationService _localizationService; private readonly IAppCache _requestCache; diff --git a/src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionaryFactory.cs b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionaryFactory.cs similarity index 92% rename from src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionaryFactory.cs rename to src/Umbraco.Core/Dictionary/UmbracoCultureDictionaryFactory.cs index a2d1fa12d3..e2e30f3d76 100644 --- a/src/Umbraco.Infrastructure/Dictionary/UmbracoCultureDictionaryFactory.cs +++ b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionaryFactory.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Dictionary /// /// In the future this will allow use to potentially store dictionary items elsewhere and allows for maximum flexibility. /// - internal class DefaultCultureDictionaryFactory : ICultureDictionaryFactory + public class DefaultCultureDictionaryFactory : ICultureDictionaryFactory { private readonly ILocalizationService _localizationService; private readonly AppCaches _appCaches; diff --git a/src/Umbraco.Core/DisposableObjectSlim.cs b/src/Umbraco.Core/DisposableObjectSlim.cs index 4992f8bc0f..6874ad8001 100644 --- a/src/Umbraco.Core/DisposableObjectSlim.cs +++ b/src/Umbraco.Core/DisposableObjectSlim.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Umbraco.Core { @@ -6,8 +6,7 @@ namespace Umbraco.Core /// Abstract implementation of managed IDisposable. /// /// - /// This is for objects that do NOT have unmanaged resources. Use - /// for objects that DO have unmanaged resources and need to deal with them when disposing. + /// This is for objects that do NOT have unmanaged resources. /// /// Can also be used as a pattern for when inheriting is not possible. /// @@ -19,35 +18,39 @@ namespace Umbraco.Core /// public abstract class DisposableObjectSlim : IDisposable { - private readonly object _locko = new object(); - - // gets a value indicating whether this instance is disposed. - // for internal tests only (not thread safe) + /// + /// Gets a value indicating whether this instance is disposed. + /// + /// + /// for internal tests only (not thread safe) + /// public bool Disposed { get; private set; } - // implements IDisposable - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Disposes managed resources + /// + protected abstract void DisposeResources(); - private void Dispose(bool disposing) + /// + /// Disposes managed resources + /// + /// True if disposing via Dispose method and not a finalizer. Always true for this class. + protected virtual void Dispose(bool disposing) { - // can happen if the object construction failed - if (_locko == null) - return; - - lock (_locko) + if (!Disposed) { - if (Disposed) return; + if (disposing) + { + DisposeResources(); + } + Disposed = true; } - - if (disposing) - DisposeResources(); } - protected virtual void DisposeResources() { } + /// +#pragma warning disable CA1063 // Implement IDisposable Correctly + public void Dispose() => Dispose(disposing: true); // We do not use GC.SuppressFinalize because this has no finalizer +#pragma warning restore CA1063 // Implement IDisposable Correctly } } diff --git a/src/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelper.cs b/src/Umbraco.Core/Editors/UserEditorAuthorizationHelper.cs similarity index 100% rename from src/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelper.cs rename to src/Umbraco.Core/Editors/UserEditorAuthorizationHelper.cs diff --git a/src/Umbraco.Core/Events/IEventAggregator.cs b/src/Umbraco.Core/Events/IEventAggregator.cs index bd01ad0b57..d78aed36b7 100644 --- a/src/Umbraco.Core/Events/IEventAggregator.cs +++ b/src/Umbraco.Core/Events/IEventAggregator.cs @@ -22,27 +22,4 @@ namespace Umbraco.Core.Events Task PublishAsync(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification; } - - /// - /// A marker interface to represent a notification. - /// - public interface INotification - { - } - - /// - /// Defines a handler for a notification. - /// - /// The type of notification being handled. - public interface INotificationHandler - where TNotification : INotification - { - /// - /// Handles a notification - /// - /// The notification - /// The cancellation token. - /// A representing the asynchronous operation. - Task HandleAsync(TNotification notification, CancellationToken cancellationToken); - } } diff --git a/src/Umbraco.Core/Events/INotification.cs b/src/Umbraco.Core/Events/INotification.cs new file mode 100644 index 0000000000..3030b0836f --- /dev/null +++ b/src/Umbraco.Core/Events/INotification.cs @@ -0,0 +1,12 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Core.Events +{ + /// + /// A marker interface to represent a notification. + /// + public interface INotification + { + } +} diff --git a/src/Umbraco.Core/Events/INotificationHandler.cs b/src/Umbraco.Core/Events/INotificationHandler.cs new file mode 100644 index 0000000000..dc5d83e0f7 --- /dev/null +++ b/src/Umbraco.Core/Events/INotificationHandler.cs @@ -0,0 +1,24 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Threading; +using System.Threading.Tasks; + +namespace Umbraco.Core.Events +{ + /// + /// Defines a handler for a notification. + /// + /// The type of notification being handled. + public interface INotificationHandler + where TNotification : INotification + { + /// + /// Handles a notification + /// + /// The notification + /// The cancellation token. + /// A representing the asynchronous operation. + Task HandleAsync(TNotification notification, CancellationToken cancellationToken); + } +} diff --git a/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs b/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs new file mode 100644 index 0000000000..422673a823 --- /dev/null +++ b/src/Umbraco.Core/Events/UmbracoApplicationStarting.cs @@ -0,0 +1,16 @@ +namespace Umbraco.Core.Events +{ + public class UmbracoApplicationStarting : INotification + { + /// + /// Initializes a new instance of the class. + /// + /// The runtime level + public UmbracoApplicationStarting(RuntimeLevel runtimeLevel) => RuntimeLevel = runtimeLevel; + + /// + /// Gets the runtime level of execution. + /// + public RuntimeLevel RuntimeLevel { get; } + } +} diff --git a/src/Umbraco.Core/Events/UmbracoApplicationStopping.cs b/src/Umbraco.Core/Events/UmbracoApplicationStopping.cs new file mode 100644 index 0000000000..bef6f0de19 --- /dev/null +++ b/src/Umbraco.Core/Events/UmbracoApplicationStopping.cs @@ -0,0 +1,4 @@ +namespace Umbraco.Core.Events +{ + public class UmbracoApplicationStopping : INotification { } +} diff --git a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs index a22748094a..28e1de3996 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs @@ -32,22 +32,16 @@ namespace Umbraco.Core.HealthCheck.Checks.Permissions /// /// Get the status for this health check /// - /// - public override IEnumerable GetStatus() - { - //return the statuses - return new[] { CheckFolderPermissions(), CheckFilePermissions() }; - } + // TODO: This should really just run the IFilePermissionHelper.RunFilePermissionTestSuite and then we'd have a + // IFilePermissions interface resolved as a collection within the IFilePermissionHelper that runs checks against all + // IFilePermissions registered. Then there's no hard coding things done here and the checks here will be consistent + // with the checks run in IFilePermissionHelper.RunFilePermissionTestSuite which occurs on install too. + public override IEnumerable GetStatus() => new[] { CheckFolderPermissions(), CheckFilePermissions() }; /// /// Executes the action and returns it's status /// - /// - /// - public override HealthCheckStatus ExecuteAction(HealthCheckAction action) - { - throw new InvalidOperationException("FolderAndFilePermissionsCheck has no executable actions"); - } + public override HealthCheckStatus ExecuteAction(HealthCheckAction action) => throw new InvalidOperationException("FolderAndFilePermissionsCheck has no executable actions"); private HealthCheckStatus CheckFolderPermissions() { @@ -67,8 +61,8 @@ namespace Umbraco.Core.HealthCheck.Checks.Permissions { Constants.SystemDirectories.MvcViews, PermissionCheckRequirement.Optional } }; - //These are special paths to check that will restart an app domain if a file is written to them, - //so these need to be tested differently + // These are special paths to check that will restart an app domain if a file is written to them, + // so these need to be tested differently var pathsToCheckWithRestarts = new Dictionary { { Constants.SystemDirectories.Bin, PermissionCheckRequirement.Optional } @@ -80,7 +74,7 @@ namespace Umbraco.Core.HealthCheck.Checks.Permissions var optionalPathCheckResult = _filePermissionHelper.EnsureDirectories( GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out var optionalFailedPaths); - //now check the special folders + // now check the special folders var requiredPathCheckResult2 = _filePermissionHelper.EnsureDirectories( GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Required), out var requiredFailedPaths2, writeCausesRestart: true); var optionalPathCheckResult2 = _filePermissionHelper.EnsureDirectories( @@ -89,7 +83,7 @@ namespace Umbraco.Core.HealthCheck.Checks.Permissions requiredPathCheckResult = requiredPathCheckResult && requiredPathCheckResult2; optionalPathCheckResult = optionalPathCheckResult && optionalPathCheckResult2; - //combine the paths + // combine the paths requiredFailedPaths = requiredFailedPaths.Concat(requiredFailedPaths2).ToList(); optionalFailedPaths = requiredFailedPaths.Concat(optionalFailedPaths2).ToList(); @@ -106,23 +100,19 @@ namespace Umbraco.Core.HealthCheck.Checks.Permissions }; // Run checks for required and optional paths for modify permission - IEnumerable requiredFailedPaths; - IEnumerable optionalFailedPaths; - var requiredPathCheckResult = _filePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out requiredFailedPaths); - var optionalPathCheckResult = _filePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out optionalFailedPaths); + var requiredPathCheckResult = _filePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Required), out IEnumerable requiredFailedPaths); + var optionalPathCheckResult = _filePermissionHelper.EnsureFiles(GetPathsToCheck(pathsToCheck, PermissionCheckRequirement.Optional), out IEnumerable optionalFailedPaths); return GetStatus(requiredPathCheckResult, requiredFailedPaths, optionalPathCheckResult, optionalFailedPaths, PermissionCheckFor.File); } - private string[] GetPathsToCheck(Dictionary pathsToCheck, - PermissionCheckRequirement requirement) - { - return pathsToCheck + private string[] GetPathsToCheck( + Dictionary pathsToCheck, + PermissionCheckRequirement requirement) => pathsToCheck .Where(x => x.Value == requirement) .Select(x => _hostingEnvironment.MapPathContentRoot(x.Key)) .OrderBy(x => x) .ToArray(); - } private HealthCheckStatus GetStatus(bool requiredPathCheckResult, IEnumerable requiredFailedPaths, bool optionalPathCheckResult, IEnumerable optionalFailedPaths, PermissionCheckFor checkingFor) { diff --git a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckNotificationMethodCollection.cs b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodCollection.cs similarity index 100% rename from src/Umbraco.Infrastructure/HealthCheck/HealthCheckNotificationMethodCollection.cs rename to src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodCollection.cs diff --git a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckNotificationMethodCollectionBuilder.cs b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodCollectionBuilder.cs similarity index 100% rename from src/Umbraco.Infrastructure/HealthCheck/HealthCheckNotificationMethodCollectionBuilder.cs rename to src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodCollectionBuilder.cs diff --git a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs b/src/Umbraco.Core/HealthCheck/HealthCheckResults.cs similarity index 85% rename from src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs rename to src/Umbraco.Core/HealthCheck/HealthCheckResults.cs index 37159b4a49..44955bfaae 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckResults.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using HeyRed.MarkdownSharp; using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.HealthCheck; @@ -120,33 +119,9 @@ namespace Umbraco.Infrastructure.HealthCheck return sb.ToString(); } - public string ResultsAsHtml(HealthCheckNotificationVerbosity verbosity) - { - var mark = new Markdown(); - var html = mark.Transform(ResultsAsMarkDown(verbosity)); - html = ApplyHtmlHighlighting(html); - return html; - } internal Dictionary> ResultsAsDictionary => _results; - private string ApplyHtmlHighlighting(string html) - { - const string SuccessHexColor = "5cb85c"; - const string WarningHexColor = "f0ad4e"; - const string ErrorHexColor = "d9534f"; - - html = ApplyHtmlHighlightingForStatus(html, StatusResultType.Success, SuccessHexColor); - html = ApplyHtmlHighlightingForStatus(html, StatusResultType.Warning, WarningHexColor); - return ApplyHtmlHighlightingForStatus(html, StatusResultType.Error, ErrorHexColor); - } - - private string ApplyHtmlHighlightingForStatus(string html, StatusResultType status, string color) - { - return html - .Replace("Result: '" + status + "'", "Result: " + status + ""); - } - private string SimpleHtmlToMarkDown(string html) { return html.Replace("", "**") diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs similarity index 89% rename from src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs rename to src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index 4d7444447f..ad92886ecd 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.HealthCheck; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Infrastructure.HealthCheck; @@ -17,6 +18,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private readonly ILocalizedTextService _textService; private readonly IRequestAccessor _requestAccessor; private readonly IEmailSender _emailSender; + private readonly IMarkdownToHtmlConverter _markdownToHtmlConverter; private readonly ContentSettings _contentSettings; @@ -25,7 +27,8 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods IRequestAccessor requestAccessor, IEmailSender emailSender, IOptions healthChecksSettings, - IOptions contentSettings) + IOptions contentSettings, + IMarkdownToHtmlConverter markdownToHtmlConverter) : base(healthChecksSettings) { var recipientEmail = Settings?["RecipientEmail"]; @@ -40,6 +43,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _requestAccessor = requestAccessor; _emailSender = emailSender; + _markdownToHtmlConverter = markdownToHtmlConverter; _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } @@ -61,7 +65,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods { DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString(), - results.ResultsAsHtml(Verbosity) + _markdownToHtmlConverter.ToHtml(results, Verbosity) }); // Include the umbraco Application URL host in the message subject so that diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs b/src/Umbraco.Core/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs similarity index 100% rename from src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs rename to src/Umbraco.Core/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs diff --git a/src/Umbraco.Core/HealthCheck/NotificationMethods/IMarkdownToHtmlConverter.cs b/src/Umbraco.Core/HealthCheck/NotificationMethods/IMarkdownToHtmlConverter.cs new file mode 100644 index 0000000000..20d8f0f07e --- /dev/null +++ b/src/Umbraco.Core/HealthCheck/NotificationMethods/IMarkdownToHtmlConverter.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.HealthCheck; +using Umbraco.Infrastructure.HealthCheck; + +namespace Umbraco.Web.HealthCheck.NotificationMethods +{ + public interface IMarkdownToHtmlConverter + { + string ToHtml(HealthCheckResults results, HealthCheckNotificationVerbosity verbosity); + } +} diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs b/src/Umbraco.Core/HealthCheck/NotificationMethods/NotificationMethodBase.cs similarity index 100% rename from src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs rename to src/Umbraco.Core/HealthCheck/NotificationMethods/NotificationMethodBase.cs diff --git a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs similarity index 73% rename from src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs rename to src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs index a032720d46..a4368a2634 100644 --- a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs @@ -1,25 +1,20 @@ using System; -namespace Umbraco.Net +namespace Umbraco.Core.Hosting { - // TODO: This shouldn't be in this namespace? public interface IUmbracoApplicationLifetime { /// /// A value indicating whether the application is restarting after the current request. /// bool IsRestarting { get; } + /// /// Terminates the current application. The application restarts the next time a request is received for it. /// void Restart(); + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications event EventHandler ApplicationInit; } - - - public interface IUmbracoApplicationLifetimeManager - { - void InvokeApplicationInit(); - } } diff --git a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs new file mode 100644 index 0000000000..778edc24dd --- /dev/null +++ b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Hosting +{ + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications + public interface IUmbracoApplicationLifetimeManager + { + void InvokeApplicationInit(); + } +} diff --git a/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs new file mode 100644 index 0000000000..3ffef04410 --- /dev/null +++ b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Hosting +{ + internal class NoopApplicationShutdownRegistry : IApplicationShutdownRegistry + { + public void RegisterObject(IRegisteredObject registeredObject) { } + public void UnregisterObject(IRegisteredObject registeredObject) { } + } +} diff --git a/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs new file mode 100644 index 0000000000..7833fd1224 --- /dev/null +++ b/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Hosting +{ + internal class NoopUmbracoApplicationLifetimeManager : IUmbracoApplicationLifetimeManager + { + public void InvokeApplicationInit() { } + } +} diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index b078172213..62f46edce4 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.IO { diff --git a/src/Umbraco.Core/Install/IFilePermissionHelper.cs b/src/Umbraco.Core/Install/IFilePermissionHelper.cs index b60839cb00..ab521d214e 100644 --- a/src/Umbraco.Core/Install/IFilePermissionHelper.cs +++ b/src/Umbraco.Core/Install/IFilePermissionHelper.cs @@ -1,11 +1,26 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace Umbraco.Core.Install { public interface IFilePermissionHelper { bool RunFilePermissionTestSuite(out Dictionary> report); + + /// + /// This will test the directories for write access + /// + /// The directories to check + /// The resulting errors, if any + /// + /// If this is false, the easiest way to test for write access is to write a temp file, however some folder will cause + /// an App Domain restart if a file is written to the folder, so in that case we need to use the ACL APIs which aren't as + /// reliable but we cannot write a file since it will cause an app domain restart. + /// + /// Returns true if test succeeds + // TODO: This shouldn't exist, see notes in FolderAndFilePermissionsCheck.GetStatus bool EnsureDirectories(string[] dirs, out IEnumerable errors, bool writeCausesRestart = false); + + // TODO: This shouldn't exist, see notes in FolderAndFilePermissionsCheck.GetStatus bool EnsureFiles(string[] files, out IEnumerable errors); } } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs similarity index 98% rename from src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs rename to src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs index 4cd25c16bb..4866c472e6 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs @@ -2,11 +2,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Umbraco.Core.Hosting; using Umbraco.Core.Security; -using Umbraco.Net; using Umbraco.Core.Services; using Umbraco.Web.Install.Models; -using Umbraco.Web.Security; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Infrastructure/Install/Models/InstallInstructions.cs b/src/Umbraco.Core/Install/Models/InstallInstructions.cs similarity index 100% rename from src/Umbraco.Infrastructure/Install/Models/InstallInstructions.cs rename to src/Umbraco.Core/Install/Models/InstallInstructions.cs diff --git a/src/Umbraco.Core/Logging/VoidProfiler.cs b/src/Umbraco.Core/Logging/NoopProfiler.cs similarity index 89% rename from src/Umbraco.Core/Logging/VoidProfiler.cs rename to src/Umbraco.Core/Logging/NoopProfiler.cs index d771fd7630..e7b43e5e2d 100644 --- a/src/Umbraco.Core/Logging/VoidProfiler.cs +++ b/src/Umbraco.Core/Logging/NoopProfiler.cs @@ -1,8 +1,8 @@ -using System; +using System; namespace Umbraco.Core.Logging { - public class VoidProfiler : IProfiler + public class NoopProfiler : IProfiler { private readonly VoidDisposable _disposable = new VoidDisposable(); diff --git a/src/Umbraco.Core/IEmailSender.cs b/src/Umbraco.Core/Mail/IEmailSender.cs similarity index 78% rename from src/Umbraco.Core/IEmailSender.cs rename to src/Umbraco.Core/Mail/IEmailSender.cs index aab944e04d..3862d0e717 100644 --- a/src/Umbraco.Core/IEmailSender.cs +++ b/src/Umbraco.Core/Mail/IEmailSender.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Umbraco.Core.Models; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// Simple abstraction to send an email message diff --git a/src/Umbraco.Core/ISmsSender.cs b/src/Umbraco.Core/Mail/ISmsSender.cs similarity index 84% rename from src/Umbraco.Core/ISmsSender.cs rename to src/Umbraco.Core/Mail/ISmsSender.cs index f296a2ea9b..a2ff054c48 100644 --- a/src/Umbraco.Core/ISmsSender.cs +++ b/src/Umbraco.Core/Mail/ISmsSender.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// Service to send an SMS diff --git a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs new file mode 100644 index 0000000000..bb8d787cbf --- /dev/null +++ b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Mail +{ + internal class NotImplementedEmailSender : IEmailSender + { + public Task SendAsync(EmailMessage message) + => throw new NotImplementedException("To send an Email ensure IEmailSender is implemented with a custom implementation"); + } +} diff --git a/src/Umbraco.Infrastructure/NotImplementedSmsSender.cs b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs similarity index 90% rename from src/Umbraco.Infrastructure/NotImplementedSmsSender.cs rename to src/Umbraco.Core/Mail/NotImplementedSmsSender.cs index ffc33373d0..16c3d04711 100644 --- a/src/Umbraco.Infrastructure/NotImplementedSmsSender.cs +++ b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs @@ -1,7 +1,7 @@ -using System; +using System; using System.Threading.Tasks; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// An that throws diff --git a/src/Umbraco.Core/Manifest/ManifestWatcher.cs b/src/Umbraco.Core/Manifest/ManifestWatcher.cs index 6bd893d298..b6cd82b31f 100644 --- a/src/Umbraco.Core/Manifest/ManifestWatcher.cs +++ b/src/Umbraco.Core/Manifest/ManifestWatcher.cs @@ -1,14 +1,13 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Net; namespace Umbraco.Core.Manifest { - public class ManifestWatcher : DisposableObjectSlim + public class ManifestWatcher : IDisposable { private static readonly object Locker = new object(); private static volatile bool _isRestarting; @@ -16,6 +15,7 @@ namespace Umbraco.Core.Manifest private readonly ILogger _logger; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly List _fws = new List(); + private bool _disposed; public ManifestWatcher(ILogger logger, IUmbracoApplicationLifetime umbracoApplicationLifetime) { @@ -48,7 +48,10 @@ namespace Umbraco.Core.Manifest private void FswChanged(object sender, FileSystemEventArgs e) { - if (e.Name.InvariantContains("package.manifest") == false) return; + if (!e.Name.InvariantContains("package.manifest")) + { + return; + } // ensure the app is not restarted multiple times for multiple // savings during the same app domain execution - restart once @@ -59,14 +62,25 @@ namespace Umbraco.Core.Manifest _isRestarting = true; _logger.LogInformation("Manifest has changed, app pool is restarting ({Path})", e.FullPath); _umbracoApplicationLifetime.Restart(); - Dispose(); // uh? if the app restarts then this should be disposed anyways? } } - protected override void DisposeResources() + private void Dispose(bool disposing) { - foreach (var fw in _fws) - fw.Dispose(); + // ReSharper disable InvertIf + if (disposing && !_disposed) + { + foreach (FileSystemWatcher fw in _fws) + { + fw.Dispose(); + } + + _disposed = true; + } + + // ReSharper restore InvertIf } + + public void Dispose() => Dispose(true); } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/DailyMotion.cs b/src/Umbraco.Core/Media/EmbedProviders/DailyMotion.cs similarity index 86% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/DailyMotion.cs rename to src/Umbraco.Core/Media/EmbedProviders/DailyMotion.cs index 78ea0b8662..f56a29c2d5 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/DailyMotion.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/DailyMotion.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"dailymotion.com/video/.*" }; - + public override Dictionary RequestParams => new Dictionary() { //ApiUrl/?format=xml @@ -24,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public DailyMotion(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProviderBase.cs b/src/Umbraco.Core/Media/EmbedProviders/EmbedProviderBase.cs similarity index 88% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProviderBase.cs rename to src/Umbraco.Core/Media/EmbedProviders/EmbedProviderBase.cs index 539c01f69b..cc7f5d2349 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProviderBase.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/EmbedProviderBase.cs @@ -1,16 +1,23 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Text; using System.Xml; using Umbraco.Core.Media; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { public abstract class EmbedProviderBase : IEmbedProvider { + private readonly IJsonSerializer _jsonSerializer; + + protected EmbedProviderBase(IJsonSerializer jsonSerializer) + { + _jsonSerializer = jsonSerializer; + } + private static HttpClient _httpClient; public abstract string ApiEndpoint { get; } @@ -58,7 +65,7 @@ namespace Umbraco.Web.Media.EmbedProviders public virtual T GetJsonResponse(string url) where T : class { var response = DownloadResponse(url); - return JsonConvert.DeserializeObject(response); + return _jsonSerializer.Deserialize(response); } public virtual XmlDocument GetXmlResponse(string url) diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProvidersCollection.cs b/src/Umbraco.Core/Media/EmbedProviders/EmbedProvidersCollection.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProvidersCollection.cs rename to src/Umbraco.Core/Media/EmbedProviders/EmbedProvidersCollection.cs diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs b/src/Umbraco.Core/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs rename to src/Umbraco.Core/Media/EmbedProviders/EmbedProvidersCollectionBuilder.cs diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Flickr.cs b/src/Umbraco.Core/Media/EmbedProviders/Flickr.cs similarity index 90% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Flickr.cs rename to src/Umbraco.Core/Media/EmbedProviders/Flickr.cs index d067060014..a6ead2df3a 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Flickr.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Flickr.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -27,5 +28,9 @@ namespace Umbraco.Web.Media.EmbedProviders return string.Format("\"{3}\"", imageUrl, imageWidth, imageHeight, WebUtility.HtmlEncode(imageTitle)); } + + public Flickr(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/GettyImages.cs b/src/Umbraco.Core/Media/EmbedProviders/GettyImages.cs similarity index 86% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/GettyImages.cs rename to src/Umbraco.Core/Media/EmbedProviders/GettyImages.cs index 34b383614d..0db0a97b8e 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/GettyImages.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/GettyImages.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -23,5 +24,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public GettyImages(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Giphy.cs b/src/Umbraco.Core/Media/EmbedProviders/Giphy.cs similarity index 83% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Giphy.cs rename to src/Umbraco.Core/Media/EmbedProviders/Giphy.cs index 1069de749c..319afda5b6 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Giphy.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Giphy.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -28,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public Giphy(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Hulu.cs b/src/Umbraco.Core/Media/EmbedProviders/Hulu.cs similarity index 85% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Hulu.cs rename to src/Umbraco.Core/Media/EmbedProviders/Hulu.cs index 150439832a..4deea8c23d 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Hulu.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Hulu.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"hulu.com/watch/.*" }; - + public override Dictionary RequestParams => new Dictionary(); public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public Hulu(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Issuu.cs b/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs similarity index 86% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Issuu.cs rename to src/Umbraco.Core/Media/EmbedProviders/Issuu.cs index 2b33473453..3baaf7ea35 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Issuu.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"issuu.com/.*/docs/.*" }; - + public override Dictionary RequestParams => new Dictionary() { //ApiUrl/?format=xml @@ -24,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public Issuu(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Kickstarter.cs b/src/Umbraco.Core/Media/EmbedProviders/Kickstarter.cs similarity index 84% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Kickstarter.cs rename to src/Umbraco.Core/Media/EmbedProviders/Kickstarter.cs index 4de45ae2e3..ef75b6ebe8 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Kickstarter.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Kickstarter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public Kickstarter(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/OEmbedResponse.cs b/src/Umbraco.Core/Media/EmbedProviders/OEmbedResponse.cs similarity index 78% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/OEmbedResponse.cs rename to src/Umbraco.Core/Media/EmbedProviders/OEmbedResponse.cs index cc3e34931e..8178a97742 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/OEmbedResponse.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/OEmbedResponse.cs @@ -1,11 +1,12 @@ using System.Net; -using Newtonsoft.Json; +using System.Runtime.Serialization; namespace Umbraco.Web.Media.EmbedProviders { /// /// Wrapper class for OEmbed response /// + [DataContract] public class OEmbedResponse { public string Type { get; set; } @@ -14,25 +15,25 @@ namespace Umbraco.Web.Media.EmbedProviders public string Title { get; set; } - [JsonProperty("author_name")] + [DataMember(Name ="author_name")] public string AuthorName { get; set; } - [JsonProperty("author_url")] + [DataMember(Name ="author_url")] public string AuthorUrl { get; set; } - [JsonProperty("provider_name")] + [DataMember(Name ="provider_name")] public string ProviderName { get; set; } - [JsonProperty("provider_url")] + [DataMember(Name ="provider_url")] public string ProviderUrl { get; set; } - [JsonProperty("thumbnail_url")] + [DataMember(Name ="thumbnail_url")] public string ThumbnailUrl { get; set; } - [JsonProperty("thumbnail_height")] + [DataMember(Name ="thumbnail_height")] public double? ThumbnailHeight { get; set; } - [JsonProperty("thumbnail_width")] + [DataMember(Name ="thumbnail_width")] public double? ThumbnailWidth { get; set; } public string Html { get; set; } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Slideshare.cs b/src/Umbraco.Core/Media/EmbedProviders/Slideshare.cs similarity index 85% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Slideshare.cs rename to src/Umbraco.Core/Media/EmbedProviders/Slideshare.cs index 6d3a010c7a..7fa149d145 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Slideshare.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Slideshare.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public Slideshare(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/SoundCloud.cs b/src/Umbraco.Core/Media/EmbedProviders/SoundCloud.cs similarity index 84% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/SoundCloud.cs rename to src/Umbraco.Core/Media/EmbedProviders/SoundCloud.cs index 080437a246..43cc92b0b4 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/SoundCloud.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/SoundCloud.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"soundcloud.com\/*" }; - + public override Dictionary RequestParams => new Dictionary(); public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public Soundcloud(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Ted.cs b/src/Umbraco.Core/Media/EmbedProviders/Ted.cs similarity index 85% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Ted.cs rename to src/Umbraco.Core/Media/EmbedProviders/Ted.cs index aa14423349..cd4b78d065 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Ted.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Ted.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"ted.com\/talks\/*" }; - + public override Dictionary RequestParams => new Dictionary(); public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public Ted(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Twitter.cs b/src/Umbraco.Core/Media/EmbedProviders/Twitter.cs similarity index 85% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Twitter.cs rename to src/Umbraco.Core/Media/EmbedProviders/Twitter.cs index 9286934a4d..2bb4203411 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Twitter.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Twitter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public Twitter(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Vimeo.cs b/src/Umbraco.Core/Media/EmbedProviders/Vimeo.cs similarity index 85% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Vimeo.cs rename to src/Umbraco.Core/Media/EmbedProviders/Vimeo.cs index 806f40a10c..709ba61b3b 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Vimeo.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Vimeo.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders { @"vimeo\.com/" }; - + public override Dictionary RequestParams => new Dictionary(); public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) @@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders return GetXmlProperty(xmlDocument, "/oembed/html"); } + + public Vimeo(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/EmbedProviders/Youtube.cs b/src/Umbraco.Core/Media/EmbedProviders/Youtube.cs similarity index 86% rename from src/Umbraco.Infrastructure/Media/EmbedProviders/Youtube.cs rename to src/Umbraco.Core/Media/EmbedProviders/Youtube.cs index 4e6f437047..30b83caa88 100644 --- a/src/Umbraco.Infrastructure/Media/EmbedProviders/Youtube.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Youtube.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.Media.EmbedProviders { @@ -11,7 +12,7 @@ namespace Umbraco.Web.Media.EmbedProviders @"youtu.be/.*", @"youtube.com/watch.*" }; - + public override Dictionary RequestParams => new Dictionary() { //ApiUrl/?format=json @@ -25,5 +26,9 @@ namespace Umbraco.Web.Media.EmbedProviders return oembed.GetHtml(); } + + public YouTube(IJsonSerializer jsonSerializer) : base(jsonSerializer) + { + } } } diff --git a/src/Umbraco.Infrastructure/Media/Exif/BitConverterEx.cs b/src/Umbraco.Core/Media/Exif/BitConverterEx.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/BitConverterEx.cs rename to src/Umbraco.Core/Media/Exif/BitConverterEx.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifBitConverter.cs b/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifBitConverter.cs rename to src/Umbraco.Core/Media/Exif/ExifBitConverter.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifEnums.cs b/src/Umbraco.Core/Media/Exif/ExifEnums.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifEnums.cs rename to src/Umbraco.Core/Media/Exif/ExifEnums.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifExceptions.cs b/src/Umbraco.Core/Media/Exif/ExifExceptions.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifExceptions.cs rename to src/Umbraco.Core/Media/Exif/ExifExceptions.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifExtendedProperty.cs b/src/Umbraco.Core/Media/Exif/ExifExtendedProperty.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifExtendedProperty.cs rename to src/Umbraco.Core/Media/Exif/ExifExtendedProperty.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifFileTypeDescriptor.cs b/src/Umbraco.Core/Media/Exif/ExifFileTypeDescriptor.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifFileTypeDescriptor.cs rename to src/Umbraco.Core/Media/Exif/ExifFileTypeDescriptor.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifInterOperability.cs b/src/Umbraco.Core/Media/Exif/ExifInterOperability.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifInterOperability.cs rename to src/Umbraco.Core/Media/Exif/ExifInterOperability.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifProperty.cs b/src/Umbraco.Core/Media/Exif/ExifProperty.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifProperty.cs rename to src/Umbraco.Core/Media/Exif/ExifProperty.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifPropertyCollection.cs b/src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifPropertyCollection.cs rename to src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifPropertyFactory.cs b/src/Umbraco.Core/Media/Exif/ExifPropertyFactory.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifPropertyFactory.cs rename to src/Umbraco.Core/Media/Exif/ExifPropertyFactory.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifTag.cs b/src/Umbraco.Core/Media/Exif/ExifTag.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifTag.cs rename to src/Umbraco.Core/Media/Exif/ExifTag.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ExifTagFactory.cs b/src/Umbraco.Core/Media/Exif/ExifTagFactory.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ExifTagFactory.cs rename to src/Umbraco.Core/Media/Exif/ExifTagFactory.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/IFD.cs b/src/Umbraco.Core/Media/Exif/IFD.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/IFD.cs rename to src/Umbraco.Core/Media/Exif/IFD.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ImageFile.cs b/src/Umbraco.Core/Media/Exif/ImageFile.cs similarity index 94% rename from src/Umbraco.Infrastructure/Media/Exif/ImageFile.cs rename to src/Umbraco.Core/Media/Exif/ImageFile.cs index acd8ce8eec..f59f9dc73f 100644 --- a/src/Umbraco.Infrastructure/Media/Exif/ImageFile.cs +++ b/src/Umbraco.Core/Media/Exif/ImageFile.cs @@ -1,5 +1,4 @@ using System.ComponentModel; -using System.Drawing; using System.IO; using System.Text; using Umbraco.Web.Media.TypeDetector; @@ -52,11 +51,6 @@ namespace Umbraco.Web.Media.Exif #endregion #region Instance Methods - /// - /// Converts the to a . - /// - /// Returns a containing image data. - public abstract Image ToImage (); /// /// Saves the to the specified file. diff --git a/src/Umbraco.Infrastructure/Media/Exif/ImageFileDirectory.cs b/src/Umbraco.Core/Media/Exif/ImageFileDirectory.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ImageFileDirectory.cs rename to src/Umbraco.Core/Media/Exif/ImageFileDirectory.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ImageFileDirectoryEntry.cs b/src/Umbraco.Core/Media/Exif/ImageFileDirectoryEntry.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ImageFileDirectoryEntry.cs rename to src/Umbraco.Core/Media/Exif/ImageFileDirectoryEntry.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/ImageFileFormat.cs b/src/Umbraco.Core/Media/Exif/ImageFileFormat.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/ImageFileFormat.cs rename to src/Umbraco.Core/Media/Exif/ImageFileFormat.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JFIFEnums.cs b/src/Umbraco.Core/Media/Exif/JFIFEnums.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JFIFEnums.cs rename to src/Umbraco.Core/Media/Exif/JFIFEnums.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JFIFExtendedProperty.cs b/src/Umbraco.Core/Media/Exif/JFIFExtendedProperty.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JFIFExtendedProperty.cs rename to src/Umbraco.Core/Media/Exif/JFIFExtendedProperty.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JFIFThumbnail.cs b/src/Umbraco.Core/Media/Exif/JFIFThumbnail.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JFIFThumbnail.cs rename to src/Umbraco.Core/Media/Exif/JFIFThumbnail.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JPEGExceptions.cs b/src/Umbraco.Core/Media/Exif/JPEGExceptions.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JPEGExceptions.cs rename to src/Umbraco.Core/Media/Exif/JPEGExceptions.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JPEGFile.cs b/src/Umbraco.Core/Media/Exif/JPEGFile.cs similarity index 99% rename from src/Umbraco.Infrastructure/Media/Exif/JPEGFile.cs rename to src/Umbraco.Core/Media/Exif/JPEGFile.cs index 35c3788abd..83e6a81eec 100644 --- a/src/Umbraco.Infrastructure/Media/Exif/JPEGFile.cs +++ b/src/Umbraco.Core/Media/Exif/JPEGFile.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Text; @@ -260,15 +259,6 @@ namespace Umbraco.Web.Media.Exif Save(stream, true); } - /// - /// Returns a System.Drawing.Image created with image data. - /// - public override Image ToImage() - { - MemoryStream stream = new MemoryStream(); - Save(stream); - return Image.FromStream(stream); - } #endregion #region Private Helper Methods diff --git a/src/Umbraco.Infrastructure/Media/Exif/JPEGMarker.cs b/src/Umbraco.Core/Media/Exif/JPEGMarker.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JPEGMarker.cs rename to src/Umbraco.Core/Media/Exif/JPEGMarker.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/JPEGSection.cs b/src/Umbraco.Core/Media/Exif/JPEGSection.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/JPEGSection.cs rename to src/Umbraco.Core/Media/Exif/JPEGSection.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/MathEx.cs b/src/Umbraco.Core/Media/Exif/MathEx.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/MathEx.cs rename to src/Umbraco.Core/Media/Exif/MathEx.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/SvgFile.cs b/src/Umbraco.Core/Media/Exif/SvgFile.cs similarity index 86% rename from src/Umbraco.Infrastructure/Media/Exif/SvgFile.cs rename to src/Umbraco.Core/Media/Exif/SvgFile.cs index 8916ac0801..1213bb513f 100644 --- a/src/Umbraco.Infrastructure/Media/Exif/SvgFile.cs +++ b/src/Umbraco.Core/Media/Exif/SvgFile.cs @@ -1,6 +1,4 @@ -using System; -using System.Drawing; -using System.IO; +using System.IO; using System.Linq; using System.Xml.Linq; @@ -29,9 +27,5 @@ namespace Umbraco.Web.Media.Exif { } - public override Image ToImage() - { - throw new NotImplementedException(); - } } } diff --git a/src/Umbraco.Infrastructure/Media/Exif/TIFFFile.cs b/src/Umbraco.Core/Media/Exif/TIFFFile.cs similarity index 93% rename from src/Umbraco.Infrastructure/Media/Exif/TIFFFile.cs rename to src/Umbraco.Core/Media/Exif/TIFFFile.cs index 4f5301d526..19575eaff2 100644 --- a/src/Umbraco.Infrastructure/Media/Exif/TIFFFile.cs +++ b/src/Umbraco.Core/Media/Exif/TIFFFile.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; namespace Umbraco.Web.Media.Exif @@ -162,16 +161,6 @@ namespace Umbraco.Web.Media.Exif } } - /// - /// Converts the to a . - /// - /// Returns a containing image data. - public override Image ToImage() - { - MemoryStream stream = new MemoryStream(); - Save(stream); - return Image.FromStream(stream); - } #endregion } } diff --git a/src/Umbraco.Infrastructure/Media/Exif/TIFFHeader.cs b/src/Umbraco.Core/Media/Exif/TIFFHeader.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/TIFFHeader.cs rename to src/Umbraco.Core/Media/Exif/TIFFHeader.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/TIFFStrip.cs b/src/Umbraco.Core/Media/Exif/TIFFStrip.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/TIFFStrip.cs rename to src/Umbraco.Core/Media/Exif/TIFFStrip.cs diff --git a/src/Umbraco.Infrastructure/Media/Exif/Utility.cs b/src/Umbraco.Core/Media/Exif/Utility.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/Exif/Utility.cs rename to src/Umbraco.Core/Media/Exif/Utility.cs diff --git a/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs b/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs new file mode 100644 index 0000000000..441d2d6170 --- /dev/null +++ b/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using Umbraco.Web.Media.Exif; + +namespace Umbraco.Core.Media +{ + public static class ExifImageDimensionExtractor + { + public static bool TryGetDimensions(Stream stream, out int width, out int height) + { + var jpgInfo = ImageFile.FromStream(stream); + height = -1; + width = -1; + if (jpgInfo != null + && jpgInfo.Format != ImageFileFormat.Unknown + && jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension) + && jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension)) + { + height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value); + width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value); + } + + return height > 0 && width > 0; + } + } +} diff --git a/src/Umbraco.Core/Media/IImageDimensionExtractor.cs b/src/Umbraco.Core/Media/IImageDimensionExtractor.cs new file mode 100644 index 0000000000..3da7f37393 --- /dev/null +++ b/src/Umbraco.Core/Media/IImageDimensionExtractor.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace Umbraco.Web.Media +{ + public interface IImageDimensionExtractor + { + public ImageSize GetDimensions(Stream stream); + } +} diff --git a/src/Umbraco.Core/Media/ImageSize.cs b/src/Umbraco.Core/Media/ImageSize.cs new file mode 100644 index 0000000000..6d073ac196 --- /dev/null +++ b/src/Umbraco.Core/Media/ImageSize.cs @@ -0,0 +1,15 @@ +namespace Umbraco.Web.Media +{ + public struct ImageSize + { + public int Width { get; } + public int Height { get; } + + + public ImageSize(int width, int height) + { + Width = width; + Height = height; + } + } +} diff --git a/src/Umbraco.Infrastructure/Media/TypeDetector/JpegDetector.cs b/src/Umbraco.Core/Media/TypeDetector/JpegDetector.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/TypeDetector/JpegDetector.cs rename to src/Umbraco.Core/Media/TypeDetector/JpegDetector.cs diff --git a/src/Umbraco.Infrastructure/Media/TypeDetector/RasterizedTypeDetector.cs b/src/Umbraco.Core/Media/TypeDetector/RasterizedTypeDetector.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/TypeDetector/RasterizedTypeDetector.cs rename to src/Umbraco.Core/Media/TypeDetector/RasterizedTypeDetector.cs diff --git a/src/Umbraco.Infrastructure/Media/TypeDetector/SvgDetector.cs b/src/Umbraco.Core/Media/TypeDetector/SvgDetector.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/TypeDetector/SvgDetector.cs rename to src/Umbraco.Core/Media/TypeDetector/SvgDetector.cs diff --git a/src/Umbraco.Infrastructure/Media/TypeDetector/TIFFDetector.cs b/src/Umbraco.Core/Media/TypeDetector/TIFFDetector.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/TypeDetector/TIFFDetector.cs rename to src/Umbraco.Core/Media/TypeDetector/TIFFDetector.cs diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs similarity index 92% rename from src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs rename to src/Umbraco.Core/Media/UploadAutoFillProperties.cs index deeed7a07c..44d5f5c8c3 100644 --- a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; using System.IO; using Microsoft.Extensions.Logging; using Umbraco.Core; @@ -18,15 +17,18 @@ namespace Umbraco.Web.Media private readonly IMediaFileSystem _mediaFileSystem; private readonly ILogger _logger; private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly IImageDimensionExtractor _imageDimensionExtractor; public UploadAutoFillProperties( IMediaFileSystem mediaFileSystem, ILogger logger, - IImageUrlGenerator imageUrlGenerator) + IImageUrlGenerator imageUrlGenerator, + IImageDimensionExtractor imageDimensionExtractor) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); + _imageDimensionExtractor = imageDimensionExtractor ?? throw new ArgumentNullException(nameof(imageDimensionExtractor)); } /// @@ -71,7 +73,7 @@ namespace Umbraco.Web.Media using (var filestream = _mediaFileSystem.OpenFile(filepath)) { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } @@ -105,12 +107,12 @@ namespace Umbraco.Web.Media else { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } - private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment) + private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, ImageSize? size, long length, string extension, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); diff --git a/src/Umbraco.Core/Models/ContentEditing/ContentItemBasic.cs b/src/Umbraco.Core/Models/ContentEditing/ContentItemBasic.cs index 6689e133fc..5f5bc3cebd 100644 --- a/src/Umbraco.Core/Models/ContentEditing/ContentItemBasic.cs +++ b/src/Umbraco.Core/Models/ContentEditing/ContentItemBasic.cs @@ -91,6 +91,7 @@ namespace Umbraco.Web.Models.ContentEditing private IEnumerable _properties; + [DataMember(Name = "properties")] public virtual IEnumerable Properties { get => _properties; diff --git a/src/Umbraco.Core/Models/IContentModel.cs b/src/Umbraco.Core/Models/IContentModel.cs index d0d4f175d7..692547aa3e 100644 --- a/src/Umbraco.Core/Models/IContentModel.cs +++ b/src/Umbraco.Core/Models/IContentModel.cs @@ -1,10 +1,30 @@ -using Umbraco.Core.Models; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Models { + /// + /// The basic view model returned for front-end Umbraco controllers + /// + /// + /// + /// exists in order to unify all view models in Umbraco, whether it's a normal template view or a partial view macro, or + /// a user's custom model that they have created when doing route hijacking or custom routes. + /// + /// + /// By default all front-end template views inherit from UmbracoViewPage which has a model of but the model returned + /// from the controllers is which in normal circumstances would not work. This works with UmbracoViewPage because it + /// performs model binding between IContentModel and IPublishedContent. This offers a lot of flexibility when rendering views. In some cases if you + /// are route hijacking and returning a custom implementation of and your view is strongly typed to this model, you can still + /// render partial views created in the back office that have the default model of IPublishedContent without having to worry about explicitly passing + /// that model to the view. + /// + /// public interface IContentModel { + /// + /// Gets the + /// IPublishedContent Content { get; } } } diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index be514eaf44..cf48d6ac53 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Xml.Linq; namespace Umbraco.Core.Models.Packaging @@ -40,6 +39,8 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable Languages { get; set; } // TODO: make strongly typed public IEnumerable DictionaryItems { get; set; } // TODO: make strongly typed public IEnumerable DocumentTypes { get; set; } // TODO: make strongly typed - public IEnumerable Documents { get; set; } + public IEnumerable MediaTypes { get; set; } // TODO: make strongly typed + public IEnumerable Documents { get; set; } + public IEnumerable Media { get; set; } } } diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackageContentBase.cs similarity index 52% rename from src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs rename to src/Umbraco.Core/Models/Packaging/CompiledPackageContentBase.cs index c41966dfe1..7b668796a4 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackageDocument.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackageContentBase.cs @@ -1,20 +1,18 @@ -using System; using System.Xml.Linq; namespace Umbraco.Core.Models.Packaging { - public class CompiledPackageDocument + /// + /// Compiled representation of a content base (Document or Media) + /// + public class CompiledPackageContentBase { - public static CompiledPackageDocument Create(XElement xml) - { - if (xml.Name.LocalName != "DocumentSet") - throw new ArgumentException("The xml isn't formatted correctly, a document element is defined by ", nameof(xml)); - return new CompiledPackageDocument + public static CompiledPackageContentBase Create(XElement xml) => + new CompiledPackageContentBase { XmlData = xml, ImportMode = xml.AttributeValue("importMode") }; - } public string ImportMode { get; set; } //this is never used @@ -23,4 +21,4 @@ namespace Umbraco.Core.Models.Packaging /// public XElement XmlData { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentType.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentType.cs index cfc789324a..f9330176aa 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace Umbraco.Core.Models.PublishedContent @@ -8,21 +8,13 @@ namespace Umbraco.Core.Models.PublishedContent /// /// Instances implementing the interface should be /// immutable, ie if the content type changes, then a new instance needs to be created. - public interface IPublishedContentType2 : IPublishedContentType + public interface IPublishedContentType { /// /// Gets the unique key for the content type. /// Guid Key { get; } - } - /// - /// Represents an type. - /// - /// Instances implementing the interface should be - /// immutable, ie if the content type changes, then a new instance needs to be created. - public interface IPublishedContentType - { /// /// Gets the content type identifier. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs index 14c26442eb..daf75f5c50 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.PublishedContent /// /// Instances of the class are immutable, ie /// if the content type changes, then a new class needs to be created. - public class PublishedContentType : IPublishedContentType2 + public class PublishedContentType : IPublishedContentType { private readonly IPublishedPropertyType[] _propertyTypes; diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeExtensions.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeExtensions.cs deleted file mode 100644 index feab33c1d6..0000000000 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Umbraco.Core.Models.PublishedContent -{ - public static class PublishedContentTypeExtensions - { - /// - /// Get the GUID key from an - /// - /// - /// - /// - public static bool TryGetKey(this IPublishedContentType publishedContentType, out Guid key) - { - if (publishedContentType is IPublishedContentType2 contentTypeWithKey) - { - key = contentTypeWithKey.Key; - return true; - } - key = Guid.Empty; - return false; - } - } -} diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index b4cd2bd03f..be3f38cb22 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -6,7 +6,6 @@ using System.Xml.Linq; using Microsoft.Extensions.Options; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Packaging; -using File = System.IO.File; namespace Umbraco.Core.Packaging { @@ -64,7 +63,9 @@ namespace Umbraco.Core.Packaging Languages = xml.Root.Element("Languages")?.Elements("Language") ?? Enumerable.Empty(), DictionaryItems = xml.Root.Element("DictionaryItems")?.Elements("DictionaryItem") ?? Enumerable.Empty(), DocumentTypes = xml.Root.Element("DocumentTypes")?.Elements("DocumentType") ?? Enumerable.Empty(), - Documents = xml.Root.Element("Documents")?.Elements("DocumentSet")?.Select(CompiledPackageDocument.Create) ?? Enumerable.Empty(), + MediaTypes = xml.Root.Element("MediaTypes")?.Elements("MediaType") ?? Enumerable.Empty(), + Documents = xml.Root.Element("Documents")?.Elements("DocumentSet")?.Select(CompiledPackageContentBase.Create) ?? Enumerable.Empty(), + Media = xml.Root.Element("MediaItems")?.Elements()?.Select(CompiledPackageContentBase.Create) ?? Enumerable.Empty(), }; def.Warnings = GetPreInstallWarnings(def, applicationRootFolder); diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index 1cab17e220..abeaa82bc1 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -17,11 +17,13 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable FilesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable DocumentTypesInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MediaTypesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable StylesheetsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MediaInstalled { get; set; } = Enumerable.Empty(); public IEnumerable Actions { get; set; } = Enumerable.Empty(); public IEnumerable ActionErrors { get; set; } = Enumerable.Empty(); - + } } diff --git a/src/Umbraco.Core/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Packaging/PackageDefinition.cs index 29a1919a2b..379b400e75 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinition.cs @@ -4,7 +4,6 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.Serialization; -using Umbraco.Core.Composing; namespace Umbraco.Core.Models.Packaging { @@ -114,6 +113,9 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "documentTypes")] public IList DocumentTypes { get; set; } = new List(); + [DataMember(Name = "mediaTypes")] + public IList MediaTypes { get; set; } = new List(); + [DataMember(Name = "stylesheets")] public IList Stylesheets { get; set; } = new List(); @@ -133,6 +135,12 @@ namespace Umbraco.Core.Models.Packaging [DataMember(Name = "iconUrl")] public string IconUrl { get; set; } = string.Empty; + [DataMember(Name = "mediaUdis")] + public IList MediaUdis { get; set; } = Array.Empty(); + + [DataMember(Name = "mediaLoadChildNodes")] + public bool MediaLoadChildNodes { get; set; } + } diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index a9516d7e25..d194b0ea56 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -46,10 +46,13 @@ namespace Umbraco.Core.Packaging Actions = xml.Element("actions")?.ToString(SaveOptions.None) ?? "", //take the entire outer xml value ContentNodeId = xml.Element("content")?.AttributeValue("nodeId") ?? string.Empty, ContentLoadChildNodes = xml.Element("content")?.AttributeValue("loadChildNodes") ?? false, + MediaUdis = xml.Element("media")?.Elements("nodeUdi").Select(x => (GuidUdi)UdiParser.Parse(x.Value)).ToList() ?? new List(), + MediaLoadChildNodes = xml.Element("media")?.AttributeValue("loadChildNodes") ?? false, Macros = xml.Element("macros")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), Templates = xml.Element("templates")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), Stylesheets = xml.Element("stylesheets")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DocumentTypes = xml.Element("documentTypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), + MediaTypes = xml.Element("mediaTypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), Languages = xml.Element("languages")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DictionaryItems = xml.Element("dictionaryitems")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), DataTypes = xml.Element("datatypes")?.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List(), @@ -103,11 +106,17 @@ namespace Umbraco.Core.Packaging new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), new XElement("stylesheets", string.Join(",", def.Stylesheets ?? Array.Empty())), new XElement("documentTypes", string.Join(",", def.DocumentTypes ?? Array.Empty())), + new XElement("mediaTypes", string.Join(",", def.MediaTypes ?? Array.Empty())), new XElement("macros", string.Join(",", def.Macros ?? Array.Empty())), new XElement("files", (def.Files ?? Array.Empty()).Where(x => !x.IsNullOrWhiteSpace()).Select(x => new XElement("file", x))), new XElement("languages", string.Join(",", def.Languages ?? Array.Empty())), - new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty()))); + new XElement("dictionaryitems", string.Join(",", def.DictionaryItems ?? Array.Empty())), + new XElement( + "media", + def.MediaUdis.Select(x=> (object)new XElement("nodeUdi", x)) + .Union(new []{new XAttribute("loadChildNodes", def.MediaLoadChildNodes) })) + ); return packageXml; } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 59741ab1ce..b89448d891 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -5,8 +5,8 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Xml.Linq; -using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; @@ -38,6 +38,8 @@ namespace Umbraco.Core.Packaging private readonly string _tempFolderPath; private readonly PackageDefinitionXmlParser _parser; private readonly IUmbracoVersion _umbracoVersion; + private readonly IMediaService _mediaService; + private readonly IMediaTypeService _mediaTypeService; /// /// Constructor @@ -65,6 +67,8 @@ namespace Umbraco.Core.Packaging ILoggerFactory loggerFactory, IUmbracoVersion umbracoVersion, IOptions globalSettings, + IMediaService mediaService, + IMediaTypeService mediaTypeService, string packageRepositoryFileName, string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null) { @@ -87,6 +91,8 @@ namespace Umbraco.Core.Packaging _parser = new PackageDefinitionXmlParser(_loggerFactory.CreateLogger(), umbracoVersion); _umbracoVersion = umbracoVersion; + _mediaService = mediaService; + _mediaTypeService = mediaTypeService; } private string CreatedPackagesFile => _packagesFolderPath.EnsureEndsWith('/') + _packageRepositoryFileName; @@ -181,12 +187,15 @@ namespace Umbraco.Core.Packaging PackageDocumentsAndTags(definition, root); PackageDocumentTypes(definition, root); + PackageMediaTypes(definition, root); PackageTemplates(definition, root); PackageStylesheets(definition, root); PackageMacros(definition, root, filesXml, temporaryPath); PackageDictionaryItems(definition, root); PackageLanguages(definition, root); PackageDataTypes(definition, root); + PackageMedia(definition, root); + // TODO: This needs to be split into content vs web files, for now we are going to // assume all files are web (www) files. But this is a larger discussion/change since @@ -194,13 +203,13 @@ namespace Umbraco.Core.Packaging //Files foreach (var fileName in definition.Files) - AppendFileToPackage(fileName, temporaryPath, filesXml, true); + AppendFileToPackage(fileName, temporaryPath, filesXml); //Load view on install... if (!string.IsNullOrEmpty(definition.PackageView)) { var control = new XElement("view", definition.PackageView); - AppendFileToPackage(definition.PackageView, temporaryPath, filesXml, true); + AppendFileToPackage(definition.PackageView, temporaryPath, filesXml); root.Add(control); } @@ -310,7 +319,7 @@ namespace Umbraco.Core.Packaging macros.Add(macroXml); //if the macro has a file copy it to the xml if (!string.IsNullOrEmpty(macro.MacroSource)) - AppendFileToPackage(macro.MacroSource, temporaryPath, filesXml, false); + AppendFileToPackage(macro.MacroSource, temporaryPath, filesXml); } root.Add(macros); } @@ -358,6 +367,23 @@ namespace Umbraco.Core.Packaging root.Add(docTypesXml); } + private void PackageMediaTypes(PackageDefinition definition, XContainer root) + { + var mediaTypes = new HashSet(); + var mediaTypesXml = new XElement("MediaTypes"); + foreach (var mediaTypeId in definition.MediaTypes) + { + if (!int.TryParse(mediaTypeId, out var outInt)) continue; + var mediaType = _mediaTypeService.Get(outInt); + if (mediaType == null) continue; + AddMediaType(mediaType, mediaTypes); + } + foreach (var mediaType in mediaTypes) + mediaTypesXml.Add(_serializer.Serialize(mediaType)); + + root.Add(mediaTypesXml); + } + private void PackageDocumentsAndTags(PackageDefinition definition, XContainer root) { //Documents and tags @@ -442,6 +468,18 @@ namespace Umbraco.Core.Packaging } } + + private void PackageMedia(PackageDefinition definition, XElement root) + { + IEnumerable medias = _mediaService.GetByIds(definition.MediaUdis); + + root.Add( + new XElement( + "MediaItems", + medias.Select(x => new XElement("MediaSet", _serializer.Serialize(x, definition.MediaLoadChildNodes))))); + } + + /// /// Zips the package. /// @@ -461,12 +499,12 @@ namespace Umbraco.Core.Packaging /// The package directory. /// The files xml node /// true if it's a web file, false if it's a content file - private void AppendFileToPackage(string path, string packageDirectory, XContainer filesXml, bool isWebFile) + private void AppendFileToPackage(string path, string packageDirectory, XContainer filesXml) { if (!path.StartsWith("~/") && !path.StartsWith("/")) path = "~/" + path; - var serverPath = isWebFile ? _hostingEnvironment.MapPathWebRoot(path) : _hostingEnvironment.MapPathContentRoot(path); + var serverPath = _hostingEnvironment.MapPathContentRoot(path); if (File.Exists(serverPath)) AppendFileXml(new FileInfo(serverPath), path, packageDirectory, filesXml); @@ -562,6 +600,19 @@ namespace Umbraco.Core.Packaging dtl.Add(dt); } + private void AddMediaType(IMediaType mediaType, HashSet mediaTypes) + { + if (mediaType.ParentId > 0) + { + var parent = _mediaTypeService.Get(mediaType.ParentId); + if (parent != null) // could be a container + AddMediaType(parent, mediaTypes); + } + + if (!mediaTypes.Contains(mediaType)) + mediaTypes.Add(mediaType); + } + private static XElement GetPackageInfoXml(PackageDefinition definition, IUmbracoVersion umbracoVersion) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs b/src/Umbraco.Core/PropertyEditors/BlockListConfiguration.cs similarity index 76% rename from src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/BlockListConfiguration.cs index 1af3aa1303..f0aa1f0b77 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/BlockListConfiguration.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System; +using System; +using System.Runtime.Serialization; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -12,37 +12,38 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("blocks", "Available Blocks", "views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.html", Description = "Define the available blocks.")] public BlockConfiguration[] Blocks { get; set; } + [DataContract] public class BlockConfiguration { - [JsonProperty("backgroundColor")] + [DataMember(Name ="backgroundColor")] public string BackgroundColor { get; set; } - [JsonProperty("iconColor")] + [DataMember(Name ="iconColor")] public string IconColor { get; set; } - [JsonProperty("thumbnail")] + [DataMember(Name ="thumbnail")] public string Thumbnail { get; set; } - [JsonProperty("contentElementTypeKey")] + [DataMember(Name ="contentElementTypeKey")] public Guid ContentElementTypeKey { get; set; } - [JsonProperty("settingsElementTypeKey")] + [DataMember(Name ="settingsElementTypeKey")] public Guid? SettingsElementTypeKey { get; set; } - [JsonProperty("view")] + [DataMember(Name ="view")] public string View { get; set; } - [JsonProperty("stylesheet")] + [DataMember(Name ="stylesheet")] public string Stylesheet { get; set; } - [JsonProperty("label")] + [DataMember(Name ="label")] public string Label { get; set; } - [JsonProperty("editorSize")] + [DataMember(Name ="editorSize")] public string EditorSize { get; set; } - [JsonProperty("forceHideContentEditorInOverlay")] + [DataMember(Name ="forceHideContentEditorInOverlay")] public bool ForceHideContentEditorInOverlay { get; set; } } @@ -51,10 +52,10 @@ namespace Umbraco.Web.PropertyEditors public class NumberRange { - [JsonProperty("min")] + [DataMember(Name ="min")] public int? Min { get; set; } - [JsonProperty("max")] + [DataMember(Name ="max")] public int? Max { get; set; } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs b/src/Umbraco.Core/PropertyEditors/DataEditor.cs similarity index 92% rename from src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs rename to src/Umbraco.Core/PropertyEditors/DataEditor.cs index d74f285553..ef533aa083 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataEditor.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Runtime.Serialization; using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -26,13 +27,21 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - public DataEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, EditorType type = EditorType.PropertyValue) + public DataEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + EditorType type = EditorType.PropertyValue) { LoggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); DataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); LocalizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); LocalizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); ShortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); + JsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer)); // defaults @@ -58,6 +67,7 @@ namespace Umbraco.Core.PropertyEditors protected DataEditorAttribute Attribute { get; } protected IShortStringHelper ShortStringHelper { get; } + public IJsonSerializer JsonSerializer { get; } protected ILocalizedTextService LocalizedTextService { get; } protected ILocalizationService LocalizationService { get; } protected ILoggerFactory LoggerFactory { get; } @@ -65,7 +75,7 @@ namespace Umbraco.Core.PropertyEditors /// [DataMember(Name = "alias", IsRequired = true)] - public string Alias { get; internal set; } + public string Alias { get; set; } /// [IgnoreDataMember] @@ -174,7 +184,7 @@ namespace Umbraco.Core.PropertyEditors if (Attribute == null) throw new InvalidOperationException($"The editor is not attributed with {nameof(DataEditorAttribute)}"); - return new DataValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + return new DataValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer, Attribute); } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs similarity index 93% rename from src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs rename to src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index fec245009f..237af042cf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -3,14 +3,13 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using System.Runtime.Serialization; using System.Xml.Linq; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -19,20 +18,28 @@ namespace Umbraco.Core.PropertyEditors /// /// Represents a value editor. /// + [DataContract] public class DataValueEditor : IDataValueEditor { private readonly ILocalizedTextService _localizedTextService; private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; protected IDataTypeService DataTypeService { get; } protected ILocalizationService LocalizationService { get; } /// /// Initializes a new instance of the class. /// - public DataValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) // for tests, and manifest + public DataValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) // for tests, and manifest { _localizedTextService = localizedTextService; _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; ValueType = ValueTypes.String; Validators = new List(); DataTypeService = dataTypeService; @@ -42,11 +49,18 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - public DataValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) + public DataValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute) { if (attribute == null) throw new ArgumentNullException(nameof(attribute)); _localizedTextService = localizedTextService; _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; var view = attribute.View; if (string.IsNullOrWhiteSpace(view)) @@ -72,13 +86,14 @@ namespace Umbraco.Core.PropertyEditors /// The view can be three things: (1) the full virtual path, or (2) the relative path to the current Umbraco /// folder, or (3) a view name which maps to views/propertyeditors/{view}/{view}.html. /// - [JsonProperty("view", Required = Required.Always)] + [Required] + [DataMember(Name = "view")] public string View { get; set; } /// /// The value type which reflects how it is validated and stored in the database /// - [JsonProperty("valueType")] + [DataMember(Name = "valueType")] public string ValueType { get; set; } /// @@ -111,7 +126,7 @@ namespace Umbraco.Core.PropertyEditors /// /// A collection of validators for the pre value editor /// - [JsonProperty("validation")] + [DataMember(Name = "validation")] public List Validators { get; private set; } = new List(); /// @@ -127,7 +142,7 @@ namespace Umbraco.Core.PropertyEditors /// /// If this is true than the editor will be displayed full width without a label /// - [JsonProperty("hideLabel")] + [DataMember(Name = "hideLabel")] public bool HideLabel { get; set; } /// @@ -142,8 +157,8 @@ namespace Umbraco.Core.PropertyEditors /// internal Attempt TryConvertValueToCrlType(object value) { - if (value is JValue) - value = value.ToString(); + // if (value is JValue) + // value = value.ToString(); //this is a custom check to avoid any errors, if it's a string and it's empty just make it null if (value is string s && string.IsNullOrWhiteSpace(s)) @@ -250,7 +265,7 @@ namespace Umbraco.Core.PropertyEditors { try { - var json = JsonConvert.DeserializeObject(asString); + var json = _jsonSerializer.Deserialize(asString); return json; } catch diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DateValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs similarity index 70% rename from src/Umbraco.Infrastructure/PropertyEditors/DateValueEditor.cs rename to src/Umbraco.Core/PropertyEditors/DateValueEditor.cs index 8973dd812b..b6208197c7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DateValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,8 +14,14 @@ namespace Umbraco.Web.PropertyEditors /// internal class DateValueEditor : DataValueEditor { - public DateValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public DateValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { Validators.Add(new DateTimeValidator()); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs similarity index 88% rename from src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs index 8d2280b23b..4aea9f944f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -26,8 +27,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs similarity index 72% rename from src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs index 417ec112d7..43b988a49f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -18,8 +19,14 @@ namespace Umbraco.Web.PropertyEditors ValueType = ValueTypes.Integer)] public class IntegerPropertyEditor : DataEditor { - public IntegerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public IntegerPropertyEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IShortStringHelper shortStringHelper, + ILocalizedTextService localizedTextService, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs similarity index 81% rename from src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs index eb50d02284..34448b3816 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,8 +21,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs similarity index 83% rename from src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs index 3676340aee..b572f47cfd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,8 +21,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } protected override IConfigurationEditor CreateConfigurationEditor() => new MemberPickerConfiguration(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs similarity index 85% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs index 2da9e184c3..619fd89692 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -23,8 +24,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", false); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs similarity index 86% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs index d416cf111a..5110dfdc79 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -24,8 +25,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiPicker", "1"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs similarity index 82% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs index 613d6a6a5e..ff08420cd9 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +18,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", true); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs similarity index 81% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs index 73a3b42610..a2750447a8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs @@ -1,6 +1,7 @@ -using Umbraco.Core; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,8 +26,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { DefaultConfiguration.Add("multiPicker", "1"); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs similarity index 84% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs index 16cd596fc8..22571db975 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +18,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", true); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs similarity index 84% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs index e9576fab02..251d982777 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +18,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", "1"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs similarity index 84% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs index 345afa3b46..aabef3e1b0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +18,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", "0"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs b/src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs similarity index 83% rename from src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs rename to src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs index be682a35d3..c3178d3138 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +18,9 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { // configure DefaultConfiguration.Add("multiple", "0"); diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs index 2149ece02a..a3c02aeb0d 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs @@ -1,11 +1,9 @@ -using System.Linq; +using System.Linq; using Umbraco.Core.Composing; using Umbraco.Core.Manifest; namespace Umbraco.Core.PropertyEditors { - - public class PropertyEditorCollection : BuilderCollectionBase { public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextConfiguration.cs b/src/Umbraco.Core/PropertyEditors/RichTextConfiguration.cs similarity index 92% rename from src/Umbraco.Infrastructure/PropertyEditors/RichTextConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/RichTextConfiguration.cs index c6d4e3ce70..c1fb61bde8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/RichTextConfiguration.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json.Linq; -using Umbraco.Core; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -11,7 +10,7 @@ namespace Umbraco.Web.PropertyEditors { // TODO: Make these strongly typed, for now this works though [ConfigurationField("editor", "Editor", "views/propertyeditors/rte/rte.prevalues.html", HideLabel = true)] - public JObject Editor { get; set; } + public object Editor { get; set; } [ConfigurationField("hideLabel", "Hide Label", "boolean")] public bool HideLabel { get; set; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs similarity index 80% rename from src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs rename to src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs index ec48cf8b57..aeac87079c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs @@ -1,6 +1,7 @@ using System; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -12,8 +13,14 @@ namespace Umbraco.Web.PropertyEditors /// public class TextOnlyValueEditor : DataValueEditor { - public TextOnlyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, DataEditorAttribute attribute, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public TextOnlyValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + DataEditorAttribute attribute, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/TextStringValueConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TextStringValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/TextStringValueConverter.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs similarity index 82% rename from src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs index 891fb54ee3..f22c3d94dc 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,8 +21,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } protected override IConfigurationEditor CreateConfigurationEditor() => new UserPickerConfiguration(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorElementTypeValidationResult.cs b/src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorElementTypeValidationResult.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorElementTypeValidationResult.cs rename to src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorElementTypeValidationResult.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorPropertyTypeValidationResult.cs b/src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorPropertyTypeValidationResult.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorPropertyTypeValidationResult.cs rename to src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorPropertyTypeValidationResult.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorValidationResult.cs b/src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorValidationResult.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/Validation/ComplexEditorValidationResult.cs rename to src/Umbraco.Core/PropertyEditors/Validation/ComplexEditorValidationResult.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/MemberPickerValueConverter.cs diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs similarity index 95% rename from src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs index 51471f6da7..64ecba5c7c 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Strings; @@ -8,7 +8,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters /// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used. /// [DefaultPropertyValueConverter] - public class TinyMceValueConverter : PropertyValueConverterBase + public class SimpleTinyMceValueConverter : PropertyValueConverterBase { public override bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs deleted file mode 100644 index 7caa9a90cc..0000000000 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Linq; -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Core.PropertyEditors.ValueConverters -{ - [DefaultPropertyValueConverter] - public class TextStringValueConverter : PropertyValueConverterBase - { - private static readonly string[] PropertyTypeAliases = - { - Constants.PropertyEditors.Aliases.TextBox, - Constants.PropertyEditors.Aliases.TextArea - }; - - public override bool IsConverter(IPublishedPropertyType propertyType) - => PropertyTypeAliases.Contains(propertyType.EditorAlias); - - public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (string); - - public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => PropertyCacheLevel.Element; - - public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - { - // in xml a string is: string - // in the database a string is: string - // default value is: null - return source; - } - - public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - // source should come from ConvertSource and be a string (or null) already - return inter ?? string.Empty; - } - - public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - // source should come from ConvertSource and be a string (or null) already - return inter; - } - } -} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs similarity index 73% rename from src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs rename to src/Umbraco.Core/PropertyEditors/VoidEditor.cs index e26cd4129a..d2e84b7952 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -14,6 +15,8 @@ namespace Umbraco.Core.PropertyEditors [HideFromTypeFinder] public class VoidEditor : DataEditor { + private readonly IJsonSerializer _jsonSerializer; + /// /// Initializes a new instance of the class. /// @@ -21,8 +24,15 @@ namespace Umbraco.Core.PropertyEditors /// A logger factory. /// The default alias of the editor is "Umbraco.Void". When a suffix is provided, /// it is appended to the alias. Eg if the suffix is "Foo" the alias is "Umbraco.Void.Foo". - public VoidEditor(string aliasSuffix, ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public VoidEditor( + string aliasSuffix, + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { Alias = "Umbraco.Void"; if (string.IsNullOrWhiteSpace(aliasSuffix)) return; @@ -34,8 +44,8 @@ namespace Umbraco.Core.PropertyEditors /// /// A logger factory. /// The alias of the editor is "Umbraco.Void". - public VoidEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : this(null, loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public VoidEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer) + : this(null, loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } } } diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs index 68b2367ce0..7307ba97f9 100644 --- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs +++ b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Models.Membership; +using System.Threading.Tasks; using Umbraco.Web.Cache; namespace Umbraco.Web.PublishedCache @@ -11,8 +11,6 @@ namespace Umbraco.Web.PublishedCache /// public interface IPublishedSnapshotService : IDisposable { - #region PublishedSnapshot - /* Various places (such as Node) want to access the XML content, today as an XmlDocument * but to migrate to a new cache, they're migrating to an XPathNavigator. Still, they need * to find out how to get that navigator. @@ -36,85 +34,23 @@ namespace Umbraco.Web.PublishedCache IPublishedSnapshot CreatePublishedSnapshot(string previewToken); /// - /// Gets the published snapshot accessor. - /// - IPublishedSnapshotAccessor PublishedSnapshotAccessor { get; } - - /// - /// Ensures that the published snapshot has the proper environment to run. - /// - /// The errors, if any. - /// A value indicating whether the published snapshot has the proper environment to run. - bool EnsureEnvironment(out IEnumerable errors); - - #endregion - - #region Rebuild - - /// - /// Rebuilds internal caches (but does not reload). + /// Rebuilds internal database caches (but does not reload). /// + /// The operation batch size to process the items + /// If not null will process content for the matching content types, if empty will process all content + /// If not null will process content for the matching media types, if empty will process all media + /// If not null will process content for the matching members types, if empty will process all members /// - /// Forces the snapshot service to rebuild its internal caches. For instance, some caches + /// Forces the snapshot service to rebuild its internal database caches. For instance, some caches /// may rely on a database table to store pre-serialized version of documents. /// This does *not* reload the caches. Caches need to be reloaded, for instance via /// RefreshAllPublishedSnapshot method. /// - void Rebuild(); - - #endregion - - #region Preview - - /* Later on we can imagine that EnterPreview would handle a "level" that would be either - * the content only, or the content's branch, or the whole tree + it could be possible - * to register filters against the factory to filter out which nodes should be preview - * vs non preview. - * - * EnterPreview() returns the previewToken. It is up to callers to store that token - * wherever they want, most probably in a cookie. - * - */ - - /// - /// Enters preview for specified user and content. - /// - /// The user. - /// The content identifier. - /// A preview token. - /// - /// Tells the caches that they should prepare any data that they would be keeping - /// in order to provide preview to a give user. In the Xml cache this means creating the Xml - /// file, though other caches may do things differently. - /// Does not handle the preview token storage (cookie, etc) that must be handled separately. - /// - string EnterPreview(IUser user, int contentId); - - /// - /// Refreshes preview for a specified content. - /// - /// The preview token. - /// The content identifier. - /// Tells the caches that they should update any data that they would be keeping - /// in order to provide preview to a given user. In the Xml cache this means updating the Xml - /// file, though other caches may do things differently. - void RefreshPreview(string previewToken, int contentId); - - /// - /// Exits preview for a specified preview token. - /// - /// The preview token. - /// - /// Tells the caches that they can dispose of any data that they would be keeping - /// in order to provide preview to a given user. In the Xml cache this means deleting the Xml file, - /// though other caches may do things differently. - /// Does not handle the preview token storage (cookie, etc) that must be handled separately. - /// - void ExitPreview(string previewToken); - - #endregion - - #region Changes + void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null); /* An IPublishedCachesService implementation can rely on transaction-level events to update * its internal, database-level data, as these events are purely internal. However, it cannot @@ -160,16 +96,9 @@ namespace Umbraco.Web.PublishedCache /// The changes. void Notify(DomainCacheRefresher.JsonPayload[] payloads); - #endregion - - #region Status - - string GetStatus(); - - string StatusUrl { get; } - - #endregion - - void Collect(); + /// + /// Cleans up unused snapshots + /// + Task CollectAsync(); } } diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs new file mode 100644 index 0000000000..0f88bd4085 --- /dev/null +++ b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotStatus.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Web.PublishedCache +{ + /// + /// Returns the currents status for nucache + /// + public interface IPublishedSnapshotStatus + { + /// + /// Gets the status report as a string + /// + string GetStatus(); + + /// + /// Gets the URL used to retreive the status + /// + string StatusUrl { get; } + } +} diff --git a/src/Umbraco.Core/ITagQuery.cs b/src/Umbraco.Core/PublishedCache/ITagQuery.cs similarity index 100% rename from src/Umbraco.Core/ITagQuery.cs rename to src/Umbraco.Core/PublishedCache/ITagQuery.cs diff --git a/src/Umbraco.Core/PublishedCache/PublishedSnapshotServiceBase.cs b/src/Umbraco.Core/PublishedCache/PublishedSnapshotServiceBase.cs deleted file mode 100644 index 9c71bdc04b..0000000000 --- a/src/Umbraco.Core/PublishedCache/PublishedSnapshotServiceBase.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Cache; - -namespace Umbraco.Web.PublishedCache -{ - public abstract class PublishedSnapshotServiceBase : IPublishedSnapshotService - { - protected PublishedSnapshotServiceBase(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) - { - PublishedSnapshotAccessor = publishedSnapshotAccessor; - VariationContextAccessor = variationContextAccessor; - } - - public IPublishedSnapshotAccessor PublishedSnapshotAccessor { get; } - public IVariationContextAccessor VariationContextAccessor { get; } - - // note: NOT setting _publishedSnapshotAccessor.PublishedSnapshot here because it is the - // responsibility of the caller to manage what the 'current' facade is - public abstract IPublishedSnapshot CreatePublishedSnapshot(string previewToken); - - protected IPublishedSnapshot CurrentPublishedSnapshot => PublishedSnapshotAccessor.PublishedSnapshot; - - public abstract bool EnsureEnvironment(out IEnumerable errors); - - public abstract string EnterPreview(IUser user, int contentId); - public abstract void RefreshPreview(string previewToken, int contentId); - public abstract void ExitPreview(string previewToken); - public abstract void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged); - public abstract void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged); - public abstract void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads); - public abstract void Notify(DataTypeCacheRefresher.JsonPayload[] payloads); - public abstract void Notify(DomainCacheRefresher.JsonPayload[] payloads); - - public virtual void Rebuild() - { } - - public virtual void Dispose() - { } - - public abstract string GetStatus(); - - public virtual string StatusUrl => "views/dashboard/settings/publishedsnapshotcache.html"; - - public virtual void Collect() - { - } - } -} diff --git a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs b/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs index 7e0ebc6f13..874da1f3aa 100644 --- a/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs +++ b/src/Umbraco.Core/PublishedCache/UmbracoContextPublishedSnapshotAccessor.cs @@ -1,6 +1,11 @@ -using System; +using System; namespace Umbraco.Web.PublishedCache { + // TODO: This is a mess. This is a circular reference: + // IPublishedSnapshotAccessor -> PublishedSnapshotService -> UmbracoContext -> PublishedSnapshotService -> IPublishedSnapshotAccessor + // Injecting IPublishedSnapshotAccessor into PublishedSnapshotService seems pretty strange + // The underlying reason for this mess is because IPublishedContent is both a service and a model. + // Until that is fixed, IPublishedContent will need to have a IPublishedSnapshotAccessor public class UmbracoContextPublishedSnapshotAccessor : IPublishedSnapshotAccessor { private readonly IUmbracoContextAccessor _umbracoContextAccessor; diff --git a/src/Umbraco.Core/Routing/IPublishedRequest.cs b/src/Umbraco.Core/Routing/IPublishedRequest.cs index f357108a4e..51fc9ccf64 100644 --- a/src/Umbraco.Core/Routing/IPublishedRequest.cs +++ b/src/Umbraco.Core/Routing/IPublishedRequest.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.Routing /// /// Gets the UmbracoContext. /// - IUmbracoContext UmbracoContext { get; } + IUmbracoContext UmbracoContext { get; } // TODO: This should be injected and removed from here /// /// Gets or sets the cleaned up Uri used for routing. diff --git a/src/Umbraco.Core/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs index 9b7354de74..10986b941a 100644 --- a/src/Umbraco.Core/Routing/PublishedRouter.cs +++ b/src/Umbraco.Core/Routing/PublishedRouter.cs @@ -138,7 +138,7 @@ namespace Umbraco.Web.Routing Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = request.Culture; SetVariationContext(request.Culture.Name); - //find the published content if it's not assigned. This could be manually assigned with a custom route handler, or + // find the published content if it's not assigned. This could be manually assigned with a custom route handler, or // with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method // to setup the rest of the pipeline but we don't want to run the finders since there's one assigned. if (request.PublishedContent == null) @@ -156,15 +156,13 @@ namespace Umbraco.Web.Routing // trigger the Prepared event - at that point it is still possible to change about anything // even though the request might be flagged for redirection - we'll redirect _after_ the event - // // also, OnPrepared() will make the PublishedRequest readonly, so nothing can change - // request.OnPrepared(); // we don't take care of anything so if the content has changed, it's up to the user // to find out the appropriate template - //complete the PCR and assign the remaining values + // complete the PCR and assign the remaining values return ConfigureRequest(request); } @@ -201,7 +199,6 @@ namespace Umbraco.Web.Routing // can't go beyond that point without a PublishedContent to render // it's ok not to have a template, in order to give MVC a chance to hijack routes - return true; } diff --git a/src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs b/src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs new file mode 100644 index 0000000000..5f219ac51f --- /dev/null +++ b/src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Umbraco.Core.Events; +using Umbraco.Core.Hosting; +using Umbraco.Core.Manifest; + +namespace Umbraco.Core.Runtime +{ + /// + /// Starts monitoring AppPlugins directory during debug runs, to restart site when a plugin manifest changes. + /// + public sealed class AppPluginsManifestWatcherNotificationHandler : INotificationHandler + { + private readonly ManifestWatcher _manifestWatcher; + private readonly IHostingEnvironment _hostingEnvironment; + + public AppPluginsManifestWatcherNotificationHandler(ManifestWatcher manifestWatcher, IHostingEnvironment hostingEnvironment) + { + _manifestWatcher = manifestWatcher ?? throw new ArgumentNullException(nameof(manifestWatcher)); + _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); + } + + public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken) + { + if (!_hostingEnvironment.IsDebugMode) + { + return Task.CompletedTask; + } + + var appPlugins = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins); + + if (!Directory.Exists(appPlugins)) + { + return Task.CompletedTask; + } + + _manifestWatcher.Start(Directory.GetDirectories(appPlugins)); + + return Task.CompletedTask; + } + } +} diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs b/src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs similarity index 70% rename from src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs rename to src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs index 73318208b6..92ad5808b3 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs +++ b/src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs @@ -1,25 +1,27 @@ -using Microsoft.Extensions.Options; -using Umbraco.Core.Composing; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.IO; namespace Umbraco.Core.Runtime { - public class CoreInitialComponent : IComponent + public class EssentialDirectoryCreator : INotificationHandler { private readonly IIOHelper _ioHelper; private readonly IHostingEnvironment _hostingEnvironment; private readonly GlobalSettings _globalSettings; - public CoreInitialComponent(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IOptions globalSettings) + public EssentialDirectoryCreator(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IOptions globalSettings) { _ioHelper = ioHelper; _hostingEnvironment = hostingEnvironment; _globalSettings = globalSettings.Value; } - public void Initialize() + public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken) { // ensure we have some essential directories // every other component can then initialize safely @@ -28,9 +30,8 @@ namespace Umbraco.Core.Runtime _ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MvcViews)); _ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.PartialViews)); _ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MacroPartials)); - } - public void Terminate() - { } + return Task.CompletedTask; + } } } diff --git a/src/Umbraco.Core/Runtime/MainDom.cs b/src/Umbraco.Core/Runtime/MainDom.cs index c413557a27..f1f6ee3afc 100644 --- a/src/Umbraco.Core/Runtime/MainDom.cs +++ b/src/Umbraco.Core/Runtime/MainDom.cs @@ -157,7 +157,15 @@ namespace Umbraco.Core.Runtime _logger.LogInformation("Acquiring."); // Get the lock - var acquired = _mainDomLock.AcquireLockAsync(LockTimeoutMilliseconds).GetAwaiter().GetResult(); + var acquired = false; + try + { + acquired = _mainDomLock.AcquireLockAsync(LockTimeoutMilliseconds).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while acquiring"); + } if (!acquired) { diff --git a/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs similarity index 92% rename from src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs rename to src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs index eed13f5060..74dea6742c 100644 --- a/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs +++ b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -29,7 +29,7 @@ namespace Umbraco.Core.Runtime _logger = logger; } - //WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread + // WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread public Task ListenAsync() => _signal.WaitOneAsync(); public Task AcquireLockAsync(int millisecondsTimeout) @@ -44,7 +44,7 @@ namespace Umbraco.Core.Runtime // if more than 1 instance reach that point, one will get the lock // and the other one will timeout, which is accepted - //This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset. + // This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset. try { _lockRelease = _systemLock.Lock(millisecondsTimeout); diff --git a/src/Umbraco.Core/Services/Implement/DashboardService.cs b/src/Umbraco.Core/Services/DashboardService.cs similarity index 100% rename from src/Umbraco.Core/Services/Implement/DashboardService.cs rename to src/Umbraco.Core/Services/DashboardService.cs diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 25428f420b..61504b0a98 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Querying; @@ -10,7 +9,7 @@ namespace Umbraco.Core.Services /// /// Defines the ContentService, which is an easy access to operations involving /// - public interface IContentService : IContentServiceBase + public interface IContentService : IContentServiceBase { #region Blueprints diff --git a/src/Umbraco.Core/Services/IContentServiceBase.cs b/src/Umbraco.Core/Services/IContentServiceBase.cs index c40f49347f..ca87382494 100644 --- a/src/Umbraco.Core/Services/IContentServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentServiceBase.cs @@ -1,7 +1,16 @@ -using Umbraco.Core.Models; +using System; +using System.Collections.Generic; +using Umbraco.Core.Models; namespace Umbraco.Core.Services { + public interface IContentServiceBase : IContentServiceBase + where TItem: class, IContentBase + { + TItem GetById(Guid key); + Attempt Save(IEnumerable contents, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); + } + /// /// Placeholder for sharing logic between the content, media (and member) services /// TODO: Start sharing the logic! diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs index 4c818aa87c..3c91091f8c 100644 --- a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs @@ -58,7 +58,6 @@ namespace Umbraco.Core.Services void Save(TItem item, int userId = Constants.Security.SuperUserId); void Save(IEnumerable items, int userId = Constants.Security.SuperUserId); - void Delete(TItem item, int userId = Constants.Security.SuperUserId); void Delete(IEnumerable item, int userId = Constants.Security.SuperUserId); diff --git a/src/Umbraco.Infrastructure/Services/Implement/IInstallationService.cs b/src/Umbraco.Core/Services/IInstallationService.cs similarity index 100% rename from src/Umbraco.Infrastructure/Services/Implement/IInstallationService.cs rename to src/Umbraco.Core/Services/IInstallationService.cs diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index c1537adbc8..aa6363cc36 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Querying; @@ -10,7 +9,7 @@ namespace Umbraco.Core.Services /// /// Defines the Media Service, which is an easy access to operations involving /// - public interface IMediaService : IContentServiceBase + public interface IMediaService : IContentServiceBase { int CountNotTrashed(string contentTypeAlias = null); int Count(string mediaTypeAlias = null); diff --git a/src/Umbraco.Core/Services/IRuntime.cs b/src/Umbraco.Core/Services/IRuntime.cs index 8a1be721d0..d1254c219f 100644 --- a/src/Umbraco.Core/Services/IRuntime.cs +++ b/src/Umbraco.Core/Services/IRuntime.cs @@ -1,22 +1,15 @@ -using System; +using Microsoft.Extensions.Hosting; namespace Umbraco.Core { /// /// Defines the Umbraco runtime. /// - public interface IRuntime + public interface IRuntime : IHostedService { /// /// Gets the runtime state. /// IRuntimeState State { get; } - - void Start(); - - /// - /// Terminates the runtime. - /// - void Terminate(); } } diff --git a/src/Umbraco.Core/Services/IServerRegistrationService.cs b/src/Umbraco.Core/Services/IServerRegistrationService.cs index 62bb68eb14..f0246dd287 100644 --- a/src/Umbraco.Core/Services/IServerRegistrationService.cs +++ b/src/Umbraco.Core/Services/IServerRegistrationService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Sync; @@ -11,9 +11,8 @@ namespace Umbraco.Core.Services /// Touches a server to mark it as active; deactivate stale servers. /// /// The server URL. - /// The server unique identity. /// The time after which a server is considered stale. - void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout); + void TouchServer(string serverAddress, TimeSpan staleTimeout); /// /// Deactivates a server. @@ -38,11 +37,6 @@ namespace Umbraco.Core.Services /// from the database. IEnumerable GetActiveServers(bool refresh = false); - /// - /// Gets the current server identity. - /// - string CurrentServerIdentity { get; } - /// /// Gets the role of the current server. /// diff --git a/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs b/src/Umbraco.Core/Services/InstallationService.cs similarity index 87% rename from src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs rename to src/Umbraco.Core/Services/InstallationService.cs index a1f74e0862..6e283a61d7 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs +++ b/src/Umbraco.Core/Services/InstallationService.cs @@ -1,8 +1,8 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -namespace Umbraco.Core.Services.Implement +namespace Umbraco.Core.Services { public class InstallationService : IInstallationService { diff --git a/src/Umbraco.Core/Services/UpgradeService.cs b/src/Umbraco.Core/Services/UpgradeService.cs index ead5270b41..b36eac7789 100644 --- a/src/Umbraco.Core/Services/UpgradeService.cs +++ b/src/Umbraco.Core/Services/UpgradeService.cs @@ -1,10 +1,9 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Semver; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -using Umbraco.Core.Services; -namespace Umbraco.Core +namespace Umbraco.Core.Services { public class UpgradeService : IUpgradeService { diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs b/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs index 7438762295..f7dafac7a6 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; namespace Umbraco.Core.Sync { /// - /// Holds a list of callbacks associated with implementations of . + /// Holds a list of callbacks associated with implementations of . /// public class DatabaseServerMessengerCallbacks { diff --git a/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs b/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs deleted file mode 100644 index f361eb7a67..0000000000 --- a/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Sync -{ - /// - /// A registrar that stores registered server nodes in the database. - /// - /// - /// This is the default registrar which determines a server's role by using a master election process. - /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. - /// - public sealed class DatabaseServerRegistrar : IServerRegistrar - { - private readonly Lazy _registrationService; - - /// - /// Initializes a new instance of the class. - /// - /// The registration service. - /// Some options. - public DatabaseServerRegistrar(Lazy registrationService) - { - _registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService)); - } - - /// - /// Gets the registered servers. - /// - public IEnumerable Registrations => _registrationService.Value.GetActiveServers(); - - /// - /// Gets the role of the current server in the application environment. - /// - public ServerRole GetCurrentServerRole() - { - var service = _registrationService.Value; - return service.GetCurrentServerRole(); - } - - } -} diff --git a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs new file mode 100644 index 0000000000..e4accd046b --- /dev/null +++ b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs @@ -0,0 +1,29 @@ +using System; +using Umbraco.Core.Services; + +namespace Umbraco.Core.Sync +{ + /// + /// Gets the current server's based on active servers registered with + /// + /// + /// This is the default service which determines a server's role by using a master election process. + /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. + /// + public sealed class ElectedServerRoleAccessor : IServerRoleAccessor + { + private readonly IServerRegistrationService _registrationService; + + /// + /// Initializes a new instance of the class. + /// + /// The registration service. + /// Some options. + public ElectedServerRoleAccessor(IServerRegistrationService registrationService) => _registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService)); + + /// + /// Gets the role of the current server in the application environment. + /// + public ServerRole CurrentServerRole => _registrationService.GetCurrentServerRole(); + } +} diff --git a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs deleted file mode 100644 index 560b7fb235..0000000000 --- a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Umbraco.Core.Sync -{ - /// - /// An implementation that works by storing messages in the database. - /// - public interface IBatchedDatabaseServerMessenger : IDatabaseServerMessenger - { - void FlushBatch(); - DatabaseServerMessengerCallbacks Callbacks { get; } - void Startup(); - } -} diff --git a/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs deleted file mode 100644 index a49cfdd023..0000000000 --- a/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Sync -{ - public interface IDatabaseServerMessenger: IServerMessenger - { - void Sync(); - } -} diff --git a/src/Umbraco.Core/Sync/IServerMessenger.cs b/src/Umbraco.Core/Sync/IServerMessenger.cs index b8300b2d6d..df2d665057 100644 --- a/src/Umbraco.Core/Sync/IServerMessenger.cs +++ b/src/Umbraco.Core/Sync/IServerMessenger.cs @@ -1,21 +1,30 @@ -using System; -using System.Collections.Generic; +using System; using Umbraco.Core.Cache; namespace Umbraco.Core.Sync { /// - /// Broadcasts distributed cache notifications to all servers of a load balanced environment. + /// Transmits distributed cache notifications for all servers of a load balanced environment. /// /// Also ensures that the notification is processed on the local environment. public interface IServerMessenger { + /// + /// Called to synchronize a server with queued notifications + /// + void Sync(); + + /// + /// Called to send/commit the queued messages created with the Perform methods + /// + void SendMessages(); + /// /// Notifies the distributed cache, for a specified . /// /// The ICacheRefresher. /// The notification content. - void PerformRefresh(ICacheRefresher refresher, TPayload[] payload); + void QueueRefresh(ICacheRefresher refresher, TPayload[] payload); /// /// Notifies the distributed cache of specified item invalidation, for a specified . @@ -24,7 +33,7 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The invalidated items. - void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances); + void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances); /// /// Notifies the distributed cache of specified item invalidation, for a specified . @@ -33,7 +42,7 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The invalidated items. - void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances); + void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances); /// /// Notifies all servers of specified items removal, for a specified . @@ -42,33 +51,33 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The removed items. - void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances); + void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances); /// /// Notifies all servers of specified items removal, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the removed items. - void PerformRemove(ICacheRefresher refresher, params int[] numericIds); + void QueueRemove(ICacheRefresher refresher, params int[] numericIds); /// /// Notifies all servers of specified items invalidation, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the invalidated items. - void PerformRefresh(ICacheRefresher refresher, params int[] numericIds); + void QueueRefresh(ICacheRefresher refresher, params int[] numericIds); /// /// Notifies all servers of specified items invalidation, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the invalidated items. - void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds); + void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds); /// /// Notifies all servers of a global invalidation for a specified . /// /// The ICacheRefresher. - void PerformRefreshAll(ICacheRefresher refresher); + void QueueRefreshAll(ICacheRefresher refresher); } } diff --git a/src/Umbraco.Core/Sync/IServerRegistrar.cs b/src/Umbraco.Core/Sync/IServerRegistrar.cs deleted file mode 100644 index 780f865ad7..0000000000 --- a/src/Umbraco.Core/Sync/IServerRegistrar.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Sync -{ - /// - /// Provides server registrations to the distributed cache. - /// - public interface IServerRegistrar - { - /// - /// Gets the server registrations. - /// - IEnumerable Registrations { get; } - - /// - /// Gets the role of the current server in the application environment. - /// - ServerRole GetCurrentServerRole(); - - } -} diff --git a/src/Umbraco.Core/Sync/IServerRoleAccessor.cs b/src/Umbraco.Core/Sync/IServerRoleAccessor.cs new file mode 100644 index 0000000000..b23acbac7c --- /dev/null +++ b/src/Umbraco.Core/Sync/IServerRoleAccessor.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Sync +{ + /// + /// Gets the current server's + /// + public interface IServerRoleAccessor + { + /// + /// Gets the role of the current server in the application environment. + /// + ServerRole CurrentServerRole { get; } + } +} diff --git a/src/Umbraco.Core/Sync/SingleServerRegistrar.cs b/src/Umbraco.Core/Sync/SingleServerRegistrar.cs deleted file mode 100644 index fe03e195b2..0000000000 --- a/src/Umbraco.Core/Sync/SingleServerRegistrar.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Web; - -namespace Umbraco.Core.Sync -{ - /// - /// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance - /// - /// - /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the - /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup - /// so this micro optimization doesn't really affect the primary startup phase. - /// - public class SingleServerRegistrar : IServerRegistrar - { - private readonly IRequestAccessor _requestAccessor; - private readonly Lazy _registrations; - - public IEnumerable Registrations => _registrations.Value; - - public SingleServerRegistrar(IRequestAccessor requestAccessor) - { - _requestAccessor = requestAccessor; - _registrations = new Lazy(() => new IServerAddress[] { new ServerAddressImpl(_requestAccessor.GetApplicationUrl().ToString()) }); - } - - public ServerRole GetCurrentServerRole() - { - return ServerRole.Single; - } - - - private class ServerAddressImpl : IServerAddress - { - public ServerAddressImpl(string serverAddress) - { - ServerAddress = serverAddress; - } - - public string ServerAddress { get; } - } - } -} diff --git a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs new file mode 100644 index 0000000000..65b9559522 --- /dev/null +++ b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using Umbraco.Web; + +namespace Umbraco.Core.Sync +{ + /// + /// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance + /// + /// + /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the + /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup + /// so this micro optimization doesn't really affect the primary startup phase. + /// + public class SingleServerRoleAccessor : IServerRoleAccessor + { + public ServerRole CurrentServerRole => ServerRole.Single; + } +} diff --git a/src/Umbraco.Core/Trees/ISearchableTree.cs b/src/Umbraco.Core/Trees/ISearchableTree.cs index 3d82d548c8..8f31c2c6ab 100644 --- a/src/Umbraco.Core/Trees/ISearchableTree.cs +++ b/src/Umbraco.Core/Trees/ISearchableTree.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Composing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Web.Trees +namespace Umbraco.Core.Trees { public interface ISearchableTree : IDiscoverable { diff --git a/src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs b/src/Umbraco.Core/Trees/SearchableApplicationTree.cs similarity index 92% rename from src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs rename to src/Umbraco.Core/Trees/SearchableApplicationTree.cs index 346f106b84..ad6fb7f43f 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs +++ b/src/Umbraco.Core/Trees/SearchableApplicationTree.cs @@ -1,6 +1,4 @@ -using Umbraco.Web.Trees; - -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableApplicationTree { diff --git a/src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs b/src/Umbraco.Core/Trees/SearchableTreeCollection.cs similarity index 97% rename from src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs rename to src/Umbraco.Core/Trees/SearchableTreeCollection.cs index 5c251a857d..e562b763d4 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs +++ b/src/Umbraco.Core/Trees/SearchableTreeCollection.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Umbraco.Core; @@ -6,7 +6,7 @@ using Umbraco.Core.Composing; using Umbraco.Web.Services; using Umbraco.Web.Trees; -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableTreeCollection : BuilderCollectionBase { diff --git a/src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs b/src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs similarity index 81% rename from src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs rename to src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs index a5e940b4a6..7922cf36ad 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs +++ b/src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs @@ -1,8 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Composing; -using Umbraco.Web.Trees; -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableTreeCollectionBuilder : LazyCollectionBuilderBase { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 28695d1673..febe8bd7ec 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -16,8 +16,10 @@ + + diff --git a/src/Umbraco.Core/UmbracoContextAccessorExtensions.cs b/src/Umbraco.Core/UmbracoContextAccessorExtensions.cs index 74e2dd7380..a8521762c6 100644 --- a/src/Umbraco.Core/UmbracoContextAccessorExtensions.cs +++ b/src/Umbraco.Core/UmbracoContextAccessorExtensions.cs @@ -3,6 +3,7 @@ using Umbraco.Web; namespace Umbraco.Core { + public static class UmbracoContextAccessorExtensions { public static IUmbracoContext GetRequiredUmbracoContext(this IUmbracoContextAccessor umbracoContextAccessor) diff --git a/src/Umbraco.Core/UmbracoContextExtensions.cs b/src/Umbraco.Core/UmbracoContextExtensions.cs new file mode 100644 index 0000000000..06ae2aa497 --- /dev/null +++ b/src/Umbraco.Core/UmbracoContextExtensions.cs @@ -0,0 +1,12 @@ +using Umbraco.Web; + +namespace Umbraco.Core +{ + public static class UmbracoContextExtensions + { + /// + /// Boolean value indicating whether the current request is a front-end umbraco request + /// + public static bool IsFrontEndUmbracoRequest(this IUmbracoContext umbracoContext) => umbracoContext.PublishedRequest != null; + } +} diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 0452373d55..ea846f7f7a 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; @@ -100,16 +100,13 @@ namespace Umbraco.Core return false; } - //if its anything else we can assume it's back office + // if its anything else we can assume it's back office return true; } /// /// Checks if the current uri is an install request /// - /// - /// - /// public static bool IsInstallerRequest(this Uri url, IHostingEnvironment hostingEnvironment) { var authority = url.GetLeftPart(UriPartial.Authority); @@ -117,18 +114,14 @@ namespace Umbraco.Core .TrimStart(authority) .TrimStart("/"); - //check if this is in the umbraco back office + // check if this is in the umbraco back office return afterAuthority.InvariantStartsWith(hostingEnvironment.ToAbsolute(Constants.SystemDirectories.Install).TrimStart("/")); } /// /// Checks if the uri is a request for the default back office page /// - /// - /// - /// - /// - internal static bool IsDefaultBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static bool IsDefaultBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var backOfficePath = globalSettings.GetBackOfficePath(hostingEnvironment); if (url.AbsolutePath.InvariantEquals(backOfficePath.TrimEnd("/")) @@ -138,6 +131,7 @@ namespace Umbraco.Core { return true; } + return false; } diff --git a/src/Umbraco.Core/HybridUmbracoContextAccessor.cs b/src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs similarity index 100% rename from src/Umbraco.Core/HybridUmbracoContextAccessor.cs rename to src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs diff --git a/src/Umbraco.Core/IUmbracoContext.cs b/src/Umbraco.Core/Web/IUmbracoContext.cs similarity index 90% rename from src/Umbraco.Core/IUmbracoContext.cs rename to src/Umbraco.Core/Web/IUmbracoContext.cs index 681dedbfd2..c034997d7e 100644 --- a/src/Umbraco.Core/IUmbracoContext.cs +++ b/src/Umbraco.Core/Web/IUmbracoContext.cs @@ -6,7 +6,7 @@ using Umbraco.Web.Routing; namespace Umbraco.Web { - public interface IUmbracoContext + public interface IUmbracoContext : IDisposable { /// /// This is used internally for performance calculations, the ObjectCreated DateTime is set as soon as this @@ -46,14 +46,10 @@ namespace Umbraco.Web /// IDomainCache Domains { get; } - /// - /// Boolean value indicating whether the current request is a front-end umbraco request - /// - bool IsFrontEndUmbracoRequest { get; } - /// /// Gets/sets the PublishedRequest object /// + // TODO: Can we refactor this and not expose this mutable object here? Instead just expose IPublishedContent? A bunch of stuff would need to change but would be better IPublishedRequest PublishedRequest { get; set; } /// @@ -73,6 +69,5 @@ namespace Umbraco.Web bool InPreviewMode { get; } IDisposable ForcedPreview(bool preview); - void Dispose(); } } diff --git a/src/Umbraco.Core/IUmbracoContextAccessor.cs b/src/Umbraco.Core/Web/IUmbracoContextAccessor.cs similarity index 100% rename from src/Umbraco.Core/IUmbracoContextAccessor.cs rename to src/Umbraco.Core/Web/IUmbracoContextAccessor.cs diff --git a/src/Umbraco.Core/IUmbracoContextFactory.cs b/src/Umbraco.Core/Web/IUmbracoContextFactory.cs similarity index 100% rename from src/Umbraco.Core/IUmbracoContextFactory.cs rename to src/Umbraco.Core/Web/IUmbracoContextFactory.cs diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs index e2f2460d58..05315b05fe 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs @@ -1,5 +1,4 @@ using System.Runtime.InteropServices; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs new file mode 100644 index 0000000000..5b4dd4f0ed --- /dev/null +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -0,0 +1,96 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Events; +using Umbraco.Core.Persistence; +using Umbraco.Core.Sync; +using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.Routing; + +namespace Umbraco.Infrastructure.Cache +{ + /// + /// Ensures that distributed cache events are setup and the is initialized + /// + public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler + { + private readonly IServerMessenger _messenger; + private readonly IRequestAccessor _requestAccessor; + private readonly IUmbracoDatabaseFactory _databaseFactory; + private readonly IDistributedCacheBinder _distributedCacheBinder; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public DatabaseServerMessengerNotificationHandler( + IServerMessenger serverMessenger, + IRequestAccessor requestAccessor, + IUmbracoDatabaseFactory databaseFactory, + IDistributedCacheBinder distributedCacheBinder, + ILogger logger) + { + _requestAccessor = requestAccessor; + _databaseFactory = databaseFactory; + _distributedCacheBinder = distributedCacheBinder; + _logger = logger; + _messenger = serverMessenger; + } + + /// + public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken) + { + // The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services. + // The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL + // being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured). + // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available + // for the hosted services to use when the HTTP request is not available. + _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; + _requestAccessor.EndRequest += EndRequest; + + Startup(); + + return Task.CompletedTask; + } + + private void Startup() + { + if (_databaseFactory.CanConnect == false) + { + _logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server."); + } + else + { + _distributedCacheBinder.BindEvents(); + + // Sync on startup, this will run through the messenger's initialization sequence + _messenger?.Sync(); + } + } + + // TODO: I don't really know or think that the Application Url plays a role anymore with the DB dist cache, + // this might be really old stuff. I 'think' all this is doing is ensuring that the IRequestAccessor.GetApplicationUrl + // is definitely called during the first request. If that is still required, that logic doesn't belong here. That logic + // should be part of it's own service/middleware. There's also TODO notes within IRequestAccessor.GetApplicationUrl directly + // mentioning that the property doesn't belong on that service either. This should be investigated and resolved in a separate task. + private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) + { + if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) + { + _requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce; + EnsureApplicationUrl(); + } + } + + // By retrieving the application URL within the context of a request (as we are here in responding + // to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for + // future requests that may not be within an HTTP request (e.g. from hosted services). + private void EnsureApplicationUrl() => _requestAccessor.GetApplicationUrl(); + + /// + /// Clear the batch on end request + /// + private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.SendMessages(); + } +} diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs deleted file mode 100644 index 7279eaf10c..0000000000 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Cache -{ - /// - /// Installs listeners on service events in order to refresh our caches. - /// - [ComposeBefore(typeof(ICoreComposer))] // runs before every other IUmbracoCoreComponent! - public sealed class DistributedCacheBinderComposer : ComponentComposer, ICoreComposer - { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs deleted file mode 100644 index 8d2a2e19cc..0000000000 --- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Services.Changes; -using Umbraco.Core.Sync; -using Umbraco.Web.Cache; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Search; - -namespace Umbraco.Web.Compose -{ - /// - /// Ensures that servers are automatically registered in the database, when using the database server registrar. - /// - /// - /// At the moment servers are automatically registered upon first request and then on every - /// request but not more than once per (configurable) period. This really is "for information & debug" purposes so - /// we can look at the table and see what servers are registered - but the info is not used anywhere. - /// Should we actually want to use this, we would need a better and more deterministic way of figuring - /// out the "server address" ie the address to which server-to-server requests should be sent - because it - /// probably is not the "current request address" - especially in multi-domains configurations. - /// - // during Initialize / Startup, we end up checking Examine, which needs to be initialized beforehand - // TODO: should not be a strong dependency on "examine" but on an "indexing component" - [ComposeAfter(typeof(ExamineComposer))] - - public sealed class DatabaseServerRegistrarAndMessengerComposer : ComponentComposer, ICoreComposer - { - public static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory) - { - return new DatabaseServerMessengerCallbacks - { - //These callbacks will be executed if the server has not been synced - // (i.e. it is a new server or the lastsynced.txt file has been removed) - InitializingCallbacks = new Action[] - { - //rebuild the xml cache file if the server is not synced - () => - { - var publishedSnapshotService = factory.GetRequiredService(); - - // rebuild the published snapshot caches entirely, if the server is not synced - // this is equivalent to DistributedCache RefreshAll... but local only - // (we really should have a way to reuse RefreshAll... locally) - // note: refresh all content & media caches does refresh content types too - publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) }); - publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); - publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); - }, - - //rebuild indexes if the server is not synced - // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific - // indexes then they can adjust this logic themselves. - () => - { - var indexRebuilder = factory.GetRequiredService(); - indexRebuilder.RebuildIndexes(false, 5000); - } - } - }; - } - - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); - builder.SetServerMessenger(); - } - } - - public sealed class DatabaseServerRegistrarAndMessengerComponent : IComponent - { - private readonly IBatchedDatabaseServerMessenger _messenger; - private readonly IRequestAccessor _requestAccessor; - - public DatabaseServerRegistrarAndMessengerComponent( - IServerMessenger serverMessenger, - IRequestAccessor requestAccessor) - { - _requestAccessor = requestAccessor; - _messenger = serverMessenger as IBatchedDatabaseServerMessenger; - } - - public void Initialize() - { - // The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services. - // The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL - // being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured). - // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available - // for the hosted services to use when the HTTP request is not available. - _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; - - // Must come last, as it references some _variables - _messenger?.Startup(); - } - - public void Terminate() - { } - - private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) - { - if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) - { - _requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce; - EnsureApplicationUrl(); - } - } - - private void EnsureApplicationUrl() - { - // By retrieving the application URL within the context of a request (as we are here in responding - // to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for - // future requests that may not be within an HTTP request (e.g. from hosted services). - _requestAccessor.GetApplicationUrl(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs deleted file mode 100644 index dd3a800821..0000000000 --- a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.IO; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Composing; -using Umbraco.Core.Hosting; -using Umbraco.Core.Manifest; -using Umbraco.Net; - -namespace Umbraco.Core.Compose -{ - public sealed class ManifestWatcherComponent : IComponent - { - private readonly IHostingEnvironment _hosting; - private readonly ILoggerFactory _loggerFactory; - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; - - // if configured and in debug mode, a ManifestWatcher watches App_Plugins folders for - // package.manifest chances and restarts the application on any change - private ManifestWatcher _mw; - - public ManifestWatcherComponent(IHostingEnvironment hosting, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IUmbracoApplicationLifetime umbracoApplicationLifetime) - { - _hosting = hosting; - _loggerFactory = loggerFactory; - _hostingEnvironment = hostingEnvironment; - _umbracoApplicationLifetime = umbracoApplicationLifetime; - } - - public void Initialize() - { - if (_hosting.IsDebugMode == false) return; - - //if (ApplicationContext.Current.IsConfigured == false || GlobalSettings.DebugMode == false) - // return; - - var appPlugins = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins); - if (Directory.Exists(appPlugins) == false) return; - - _mw = new ManifestWatcher(_loggerFactory.CreateLogger(), _umbracoApplicationLifetime); - _mw.Start(Directory.GetDirectories(appPlugins)); - } - - public void Terminate() - { - if (_mw == null) return; - - _mw.Dispose(); - _mw = null; - } - } -} diff --git a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComposer.cs b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComposer.cs deleted file mode 100644 index 786a3ed0ce..0000000000 --- a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComposer.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Compose -{ - public class ManifestWatcherComposer : ComponentComposer, ICoreComposer - { } -} diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs index 0fee815560..79066dedd7 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; namespace Umbraco.Web.Compose diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs deleted file mode 100644 index 31b3133e4d..0000000000 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Web.Install; -using Umbraco.Web.Install.InstallSteps; -using Umbraco.Web.Install.Models; - -namespace Umbraco.Web.Composing.CompositionExtensions -{ - public static class Installer - { - public static IUmbracoBuilder ComposeInstaller(this IUmbracoBuilder builder) - { - // register the installer steps - - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - // TODO: Add these back once we have a compatible Starter kit - // composition.Services.AddScoped(); - // composition.Services.AddScoped(); - // composition.Services.AddScoped(); - - builder.Services.AddScoped(); - - builder.Services.AddTransient(); - builder.Services.AddUnique(); - - return builder; - } - } -} diff --git a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs deleted file mode 100644 index 7c17a8a338..0000000000 --- a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.Extensions.Hosting; - -namespace Umbraco.Core.Composing -{ - /// - /// Extends the to enable Umbraco to be used as the service container. - /// - public static class HostBuilderExtensions - { - /// - /// Assigns a custom service provider factory to use Umbraco's container - /// - /// - /// - public static IHostBuilder UseUmbraco(this IHostBuilder builder) - { - return builder; - } - } -} diff --git a/src/Umbraco.Infrastructure/CompositionExtensions.cs b/src/Umbraco.Infrastructure/CompositionExtensions.cs deleted file mode 100644 index 703c35e06b..0000000000 --- a/src/Umbraco.Infrastructure/CompositionExtensions.cs +++ /dev/null @@ -1,335 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Dictionary; -using Umbraco.Core.IO; -using Umbraco.Core.Logging.Viewer; -using Umbraco.Core.Manifest; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PackageActions; -using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Strings; -using Umbraco.Core.Sync; -using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Search; - -namespace Umbraco.Core -{ - /// - /// Provides extension methods to the class. - /// - public static partial class CompositionExtensions - { - #region Collection Builders - - /// - /// Gets the cache refreshers collection builder. - /// - /// The builder. - public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the mappers collection builder. - /// - /// The builder. - public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the package actions collection builder. - /// - /// The builder. - internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data editor collection builder. - /// - /// The builder. - public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data value reference factory collection builder. - /// - /// The builder. - public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the property value converters collection builder. - /// - /// The builder. - public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the url segment providers collection builder. - /// - /// The builder. - public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the validators collection builder. - /// - /// The builder. - internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the manifest filter collection builder. - /// - /// The builder. - public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the backoffice OEmbed Providers collection builder. - /// - /// The builder. - public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the back office searchable tree collection builder - /// - /// - /// - public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - #endregion - - #region Uniques - - /// - /// Sets the culture dictionary factory. - /// - /// The type of the factory. - /// The builder. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder) - where T : class, ICultureDictionaryFactory - { - builder.Services.AddUnique(); - } - - /// - /// Sets the culture dictionary factory. - /// - /// The builder. - /// A function creating a culture dictionary factory. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the culture dictionary factory. - /// - /// The builder. - /// A factory. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the published content model factory. - /// - /// The type of the factory. - /// The builder. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder) - where T : class, IPublishedModelFactory - { - builder.Services.AddUnique(); - } - - /// - /// Sets the published content model factory. - /// - /// The builder. - /// A function creating a published content model factory. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the published content model factory. - /// - /// The builder. - /// A published content model factory. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server registrar. - /// - /// The type of the server registrar. - /// The builder. - public static void SetServerRegistrar(this IUmbracoBuilder builder) - where T : class, IServerRegistrar - { - builder.Services.AddUnique(); - } - - /// - /// Sets the server registrar. - /// - /// The builder. - /// A function creating a server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server registrar. - /// - /// The builder. - /// A server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar) - { - builder.Services.AddUnique(registrar); - } - - /// - /// Sets the server messenger. - /// - /// The type of the server registrar. - /// The builder. - public static void SetServerMessenger(this IUmbracoBuilder builder) - where T : class, IServerMessenger - { - builder.Services.AddUnique(); - } - - /// - /// Sets the server messenger. - /// - /// The builder. - /// A function creating a server messenger. - public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server messenger. - /// - /// The builder. - /// A server messenger. - public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar) - { - builder.Services.AddUnique(registrar); - } - - /// - /// Sets the database server messenger options. - /// - /// The builder. - /// A function creating the options. - /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. - public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the database server messenger options. - /// - /// The builder. - /// Options. - /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. - public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) - { - builder.Services.AddUnique(options); - } - - /// - /// Sets the short string helper. - /// - /// The type of the short string helper. - /// The builder. - public static void SetShortStringHelper(this IUmbracoBuilder builder) - where T : class, IShortStringHelper - { - builder.Services.AddUnique(); - } - - /// - /// Sets the short string helper. - /// - /// The builder. - /// A function creating a short string helper. - public static void SetShortStringHelper(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the short string helper. - /// - /// A builder. - /// A short string helper. - public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper) - { - builder.Services.AddUnique(helper); - } - - /// - /// Sets the underlying media filesystem. - /// - /// A builder. - /// A filesystem factory. - /// - /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper - /// - public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) - => builder.Services.AddUnique(factory => - { - var fileSystems = factory.GetRequiredService(); - return fileSystems.GetFileSystem(filesystemFactory(factory)); - }); - - /// - /// Sets the log viewer. - /// - /// The type of the log viewer. - /// The builder. - public static void SetLogViewer(this IUmbracoBuilder builder) - where T : class, ILogViewer - { - builder.Services.AddUnique(); - } - - /// - /// Sets the log viewer. - /// - /// The builder. - /// A function creating a log viewer. - public static void SetLogViewer(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the log viewer. - /// - /// A builder. - /// A log viewer. - public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer) - { - builder.Services.AddUnique(viewer); - } - - #endregion - } -} diff --git a/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs b/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs index 5642c882e6..ca25563730 100644 --- a/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs +++ b/src/Umbraco.Infrastructure/Configuration/NCronTabParser.cs @@ -1,9 +1,8 @@ -using System; +using System; using NCrontab; namespace Umbraco.Core.Configuration { - public class NCronTabParser : ICronTabParser { public bool IsValidCronTab(string cronTab) diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs new file mode 100644 index 0000000000..4da9c93fb3 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs @@ -0,0 +1,25 @@ +using Umbraco.Core.Cache; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Manifest; +using Umbraco.Core.PackageActions; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using Umbraco.Core.Trees; +using Umbraco.Web.Media.EmbedProviders; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Gets the mappers collection builder. + /// + /// The builder. + public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs new file mode 100644 index 0000000000..94c1e3dcfa --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -0,0 +1,208 @@ +using System.Runtime.InteropServices; +using Examine; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Hosting; +using Umbraco.Core.Install; +using Umbraco.Core.Logging.Serilog.Enrichers; +using Umbraco.Core.Mail; +using Umbraco.Core.Manifest; +using Umbraco.Core.Media; +using Umbraco.Core.Migrations; +using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.PostMigrations; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Packaging; +using Umbraco.Core.Persistence; +using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Core.Runtime; +using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; +using Umbraco.Core.Templates; +using Umbraco.Examine; +using Umbraco.Infrastructure.Examine; +using Umbraco.Infrastructure.Logging.Serilog.Enrichers; +using Umbraco.Infrastructure.Media; +using Umbraco.Infrastructure.Runtime; +using Umbraco.Web; +using Umbraco.Web.HealthCheck; +using Umbraco.Web.HealthCheck.NotificationMethods; +using Umbraco.Web.Install; +using Umbraco.Web.Media; +using Umbraco.Web.Migrations.PostMigrations; +using Umbraco.Web.Models.PublishedContent; +using Umbraco.Web.PropertyEditors; +using Umbraco.Web.PropertyEditors.ValueConverters; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.Routing; +using Umbraco.Web.Search; +using Umbraco.Web.Trees; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds all core Umbraco services required to run which may be replaced later in the pipeline + /// + public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder) + { + builder + .AddMainDom() + .AddLogging(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => factory.GetRequiredService().CreateDatabase()); + builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // composers + builder + .AddRepositories() + .AddServices() + .AddCoreMappingProfiles() + .AddFileSystems(); + + // register persistence mappers - required by database factory so needs to be done here + // means the only place the collection can be modified is in a runtime - afterwards it + // has been frozen and it is too late + builder.Mappers().AddCoreMappers(); + + // register the scope provider + builder.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor + builder.Services.AddUnique(f => f.GetRequiredService()); + builder.Services.AddUnique(f => f.GetRequiredService()); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // register database builder + // *not* a singleton, don't want to keep it around + builder.Services.AddTransient(); + + // register manifest parser, will be injected in collection builders where needed + builder.Services.AddUnique(); + + // register the manifest filter collection builder (collection is empty by default) + builder.ManifestFilters(); + + builder.MediaUrlGenerators() + .Add() + .Add(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(factory + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); + + builder.Services.AddUnique(factory => new MigrationBuilder(factory)); + + builder.Services.AddUnique(); + + // register the published snapshot accessor - the "current" published snapshot is in the umbraco context + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + // Config manipulator + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be + // discovered when CoreBootManager configures the converters. We will remove the basic one defined + // in core so that the more enhanced version is active. + builder.PropertyValueConverters() + .Remove(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + // register *all* checks, except those marked [HideFromTypeFinder] of course + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddScoped(); + + // replace + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddScoped(); + + builder.Services.AddUnique(); + builder.Services.AddScoped(factory => + { + var umbCtx = factory.GetRequiredService(); + return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); + }); + + // register accessors for cultures + builder.Services.AddUnique(); + + builder.Services.AddSingleton(); + + builder.Services.AddUnique(); + + // Register noop versions for examine to be overridden by examine + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.AddInstaller(); + + return builder; + } + + /// + /// Adds logging requirements for Umbraco + /// + private static IUmbracoBuilder AddLogging(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + return builder; + } + + private static IUmbracoBuilder AddMainDom(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(factory => + { + var globalSettings = factory.GetRequiredService>().Value; + var connectionStrings = factory.GetRequiredService>().Value; + var hostingEnvironment = factory.GetRequiredService(); + + var dbCreator = factory.GetRequiredService(); + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var loggerFactory = factory.GetRequiredService(); + + return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false + ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment) + : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); + }); + + return builder; + } + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs new file mode 100644 index 0000000000..db1d22e86c --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -0,0 +1,131 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Events; +using Umbraco.Core.Services.Changes; +using Umbraco.Core.Sync; +using Umbraco.Infrastructure.Cache; +using Umbraco.Web.Cache; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.Search; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds distributed cache support + /// + public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder) + { + builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); + builder.SetServerMessenger(); + builder.AddNotificationHandler(); + + builder.Services.AddUnique(); + return builder; + } + + /// + /// Sets the server registrar. + /// + /// The type of the server registrar. + /// The builder. + public static void SetServerRegistrar(this IUmbracoBuilder builder) + where T : class, IServerRoleAccessor + => builder.Services.AddUnique(); + + /// + /// Sets the server registrar. + /// + /// The builder. + /// A function creating a server registrar. + public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the server registrar. + /// + /// The builder. + /// A server registrar. + public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar) + => builder.Services.AddUnique(registrar); + + /// + /// Sets the database server messenger options. + /// + /// The builder. + /// A function creating the options. + /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. + public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the database server messenger options. + /// + /// The builder. + /// Options. + /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. + public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) + => builder.Services.AddUnique(options); + + /// + /// Sets the server messenger. + /// + /// The type of the server registrar. + /// The builder. + public static void SetServerMessenger(this IUmbracoBuilder builder) + where T : class, IServerMessenger + => builder.Services.AddUnique(); + + /// + /// Sets the server messenger. + /// + /// The builder. + /// A function creating a server messenger. + public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the server messenger. + /// + /// The builder. + /// A server messenger. + public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar) + => builder.Services.AddUnique(registrar); + + private static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory) => new DatabaseServerMessengerCallbacks + { + // These callbacks will be executed if the server has not been synced + // (i.e. it is a new server or the lastsynced.txt file has been removed) + InitializingCallbacks = new Action[] + { + // rebuild the xml cache file if the server is not synced + () => + { + IPublishedSnapshotService publishedSnapshotService = factory.GetRequiredService(); + + // rebuild the published snapshot caches entirely, if the server is not synced + // this is equivalent to DistributedCache RefreshAll... but local only + // (we really should have a way to reuse RefreshAll... locally) + // note: refresh all content & media caches does refresh content types too + publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) }); + publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); + publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); + }, + + // rebuild indexes if the server is not synced + // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific + // indexes then they can adjust this logic themselves. + () => + { + var indexRebuilder = factory.GetRequiredService(); + indexRebuilder.RebuildIndexes(false, 5000); + } + } + }; + } +} diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs similarity index 88% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs index f098cfaf57..5c61fd2c60 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs @@ -1,16 +1,15 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; -using Umbraco.Core.Strings; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { - internal static class FileSystems + public static partial class UmbracoBuilderExtensions { /* * HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM @@ -34,16 +33,16 @@ namespace Umbraco.Core.Composing.CompositionExtensions * */ - public static IUmbracoBuilder ComposeFileSystems(this IUmbracoBuilder builder) + internal static IUmbracoBuilder AddFileSystems(this IUmbracoBuilder builder) { // register FileSystems, which manages all filesystems // it needs to be registered (not only the interface) because it provides additional // functionality eg for scoping, and is injected in the scope provider - whereas the // interface is really for end-users to get access to filesystems. - builder.Services.AddUnique(factory => factory.CreateInstance(factory)); + builder.Services.AddUnique(factory => factory.CreateInstance(factory)); // register IFileSystems, which gives access too all filesystems - builder.Services.AddUnique(factory => factory.GetRequiredService()); + builder.Services.AddUnique(factory => factory.GetRequiredService()); // register the scheme for media paths builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs new file mode 100644 index 0000000000..e5bdd844d8 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Web.Install; +using Umbraco.Web.Install.InstallSteps; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds the services for the Umbraco installer + /// + internal static IUmbracoBuilder AddInstaller(this IUmbracoBuilder builder) + { + // register the installer steps + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // TODO: Add these back once we have a compatible Starter kit + // composition.Services.AddScoped(); + // composition.Services.AddScoped(); + // composition.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddTransient(); + builder.Services.AddUnique(); + + return builder; + } + } +} diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs similarity index 80% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs index 72af10e31c..692342581e 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs @@ -5,17 +5,14 @@ using Umbraco.Core.Models.Mapping; using Umbraco.Core.Security; using Umbraco.Web.Models.Mapping; -namespace Umbraco.Core.Composing.CompositionExtensions - +namespace Umbraco.Infrastructure.DependencyInjection { - public static class CoreMappingProfiles + public static partial class UmbracoBuilderExtensions { /// /// Registers the core Umbraco mapper definitions /// - /// - /// - public static IUmbracoBuilder ComposeCoreMappingProfiles(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddCoreMappingProfiles(this IUmbracoBuilder builder) { builder.Services.AddUnique(); @@ -36,8 +33,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions .Add() .Add() .Add() - .Add() - ; + .Add(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs similarity index 91% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs index 05b7371d15..1e32eddb5c 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs @@ -1,15 +1,18 @@ -using Umbraco.Core.DependencyInjection; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { /// /// Composes repositories. /// - internal static class Repositories + public static partial class UmbracoBuilderExtensions { - public static IUmbracoBuilder ComposeRepositories(this IUmbracoBuilder builder) + /// + /// Adds the Umbraco repositories + /// + internal static IUmbracoBuilder AddRepositories(this IUmbracoBuilder builder) { // repositories builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs similarity index 89% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs index 696f846d13..918bdcb941 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs @@ -1,31 +1,30 @@ -using System; +using System; using System.IO; using System.Linq; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; -using Umbraco.Core.DependencyInjection; +using Microsoft.Extensions.Options; +using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Packaging; using Umbraco.Core.Routing; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { - internal static class Services + public static partial class UmbracoBuilderExtensions { - public static IUmbracoBuilder ComposeServices(this IUmbracoBuilder builder) + /// + /// Adds Umbraco services + /// + internal static IUmbracoBuilder AddServices(this IUmbracoBuilder builder) { - // register a transient messages factory, which will be replaced by the web - // boot manager when running in a web context - builder.Services.AddUnique(); - // register the service context builder.Services.AddUnique(); @@ -60,7 +59,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.Services.AddTransient(SourcesFactory); + builder.Services.AddTransient(SourcesFactory); builder.Services.AddUnique(factory => new LocalizedTextService( factory.GetRequiredService>(), factory.GetRequiredService>())); @@ -83,9 +82,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions /// /// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository /// - /// - /// - /// private static PackagesRepository CreatePackageRepository(IServiceProvider factory, string packageRepoFileName) => new PackagesRepository( factory.GetRequiredService(), @@ -99,15 +95,17 @@ namespace Umbraco.Core.Composing.CompositionExtensions factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService>(), + factory.GetRequiredService(), + factory.GetRequiredService(), packageRepoFileName); private static LocalizedTextServiceFileSources SourcesFactory(IServiceProvider container) { var hostingEnvironment = container.GetRequiredService(); var globalSettings = container.GetRequiredService>().Value; - var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath , "config","lang"))); + var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath, "config", "lang"))); var appPlugins = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins)); - var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config ,"lang"))); + var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config, "lang"))); var pluginLangFolders = appPlugins.Exists == false ? Enumerable.Empty() @@ -116,7 +114,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions .SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly)) .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false)); - //user defined langs that overwrite the default, these should not be used by plugin creators + // user defined langs that overwrite the default, these should not be used by plugin creators var userLangFolders = configLangFolder.Exists == false ? Enumerable.Empty() : configLangFolder diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs new file mode 100644 index 0000000000..f26b4442f8 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs @@ -0,0 +1,157 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Dictionary; +using Umbraco.Core.IO; +using Umbraco.Core.Logging.Viewer; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Strings; +using Umbraco.Core.Sync; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Sets the culture dictionary factory. + /// + /// The type of the factory. + /// The builder. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder) + where T : class, ICultureDictionaryFactory + { + builder.Services.AddUnique(); + } + + /// + /// Sets the culture dictionary factory. + /// + /// The builder. + /// A function creating a culture dictionary factory. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the culture dictionary factory. + /// + /// The builder. + /// A factory. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the published content model factory. + /// + /// The type of the factory. + /// The builder. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder) + where T : class, IPublishedModelFactory + { + builder.Services.AddUnique(); + } + + /// + /// Sets the published content model factory. + /// + /// The builder. + /// A function creating a published content model factory. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the published content model factory. + /// + /// The builder. + /// A published content model factory. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the short string helper. + /// + /// The type of the short string helper. + /// The builder. + public static void SetShortStringHelper(this IUmbracoBuilder builder) + where T : class, IShortStringHelper + { + builder.Services.AddUnique(); + } + + /// + /// Sets the short string helper. + /// + /// The builder. + /// A function creating a short string helper. + public static void SetShortStringHelper(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the short string helper. + /// + /// A builder. + /// A short string helper. + public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper) + { + builder.Services.AddUnique(helper); + } + + /// + /// Sets the underlying media filesystem. + /// + /// A builder. + /// A filesystem factory. + /// + /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper + /// + public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) + => builder.Services.AddUnique(factory => + { + var fileSystems = factory.GetRequiredService(); + return fileSystems.GetFileSystem(filesystemFactory(factory)); + }); + + /// + /// Sets the log viewer. + /// + /// The type of the log viewer. + /// The builder. + public static void SetLogViewer(this IUmbracoBuilder builder) + where T : class, ILogViewer + { + builder.Services.AddUnique(); + } + + /// + /// Sets the log viewer. + /// + /// The builder. + /// A function creating a log viewer. + public static void SetLogViewer(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the log viewer. + /// + /// A builder. + /// A log viewer. + public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer) + { + builder.Services.AddUnique(viewer); + } + } +} diff --git a/src/Umbraco.Infrastructure/EmailSender.cs b/src/Umbraco.Infrastructure/EmailSender.cs index 539adcb971..4c377f1ff1 100644 --- a/src/Umbraco.Infrastructure/EmailSender.cs +++ b/src/Umbraco.Infrastructure/EmailSender.cs @@ -7,6 +7,7 @@ using MimeKit; using MimeKit.Text; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using SmtpClient = MailKit.Net.Smtp.SmtpClient; diff --git a/src/Umbraco.Infrastructure/HealthCheck/MarkdownToHtmlConverter.cs b/src/Umbraco.Infrastructure/HealthCheck/MarkdownToHtmlConverter.cs new file mode 100644 index 0000000000..39c5fe0bf2 --- /dev/null +++ b/src/Umbraco.Infrastructure/HealthCheck/MarkdownToHtmlConverter.cs @@ -0,0 +1,35 @@ +using HeyRed.MarkdownSharp; +using Umbraco.Core.HealthCheck; +using Umbraco.Infrastructure.HealthCheck; +using Umbraco.Web.HealthCheck.NotificationMethods; + +namespace Umbraco.Web.HealthCheck +{ + public class MarkdownToHtmlConverter : IMarkdownToHtmlConverter + { + public string ToHtml(HealthCheckResults results, HealthCheckNotificationVerbosity verbosity) + { + var mark = new Markdown(); + var html = mark.Transform(results.ResultsAsMarkDown(verbosity)); + html = ApplyHtmlHighlighting(html); + return html; + } + + private string ApplyHtmlHighlighting(string html) + { + const string SuccessHexColor = "5cb85c"; + const string WarningHexColor = "f0ad4e"; + const string ErrorHexColor = "d9534f"; + + html = ApplyHtmlHighlightingForStatus(html, StatusResultType.Success, SuccessHexColor); + html = ApplyHtmlHighlightingForStatus(html, StatusResultType.Warning, WarningHexColor); + return ApplyHtmlHighlightingForStatus(html, StatusResultType.Error, ErrorHexColor); + } + + private string ApplyHtmlHighlightingForStatus(string html, StatusResultType status, string color) + { + return html + .Replace("Result: '" + status + "'", "Result: " + status + ""); + } + } +} diff --git a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs index 5c8bd0bc2f..c1412d4169 100644 --- a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs @@ -9,12 +9,12 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Extensions; using Umbraco.Core.Configuration.Models; using Umbraco.Core.HealthCheck; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Sync; -using Umbraco.Infrastructure.Configuration.Extensions; using Umbraco.Infrastructure.HealthCheck; using Umbraco.Web.HealthCheck; using Umbraco.Web.HealthCheck.NotificationMethods; @@ -30,7 +30,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IRuntimeState _runtimeState; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IMainDom _mainDom; private readonly IScopeProvider _scopeProvider; private readonly ILogger _logger; @@ -54,7 +54,7 @@ namespace Umbraco.Infrastructure.HostedServices HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IRuntimeState runtimeState, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IMainDom mainDom, IScopeProvider scopeProvider, ILogger logger, @@ -87,7 +87,7 @@ namespace Umbraco.Infrastructure.HostedServices return; } - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs index 6a56b6f98e..0ec237c6d6 100644 --- a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs +++ b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs @@ -24,7 +24,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly KeepAliveSettings _keepAliveSettings; private readonly ILogger _logger; private readonly IProfilingLogger _profilingLogger; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IHttpClientFactory _httpClientFactory; /// @@ -43,7 +43,7 @@ namespace Umbraco.Infrastructure.HostedServices IOptions keepAliveSettings, ILogger logger, IProfilingLogger profilingLogger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IHttpClientFactory httpClientFactory) : base(TimeSpan.FromMinutes(5), DefaultDelay) { @@ -64,7 +64,7 @@ namespace Umbraco.Infrastructure.HostedServices } // Don't run on replicas nor unknown role servers - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs index ca87d3e84e..c933ee2470 100644 --- a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs @@ -23,7 +23,7 @@ namespace Umbraco.Infrastructure.HostedServices public class LogScrubber : RecurringHostedServiceBase { private readonly IMainDom _mainDom; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IAuditService _auditService; private readonly LoggingSettings _settings; private readonly IProfilingLogger _profilingLogger; @@ -42,7 +42,7 @@ namespace Umbraco.Infrastructure.HostedServices /// The profiling logger. public LogScrubber( IMainDom mainDom, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IAuditService auditService, IOptions settings, IScopeProvider scopeProvider, @@ -61,7 +61,7 @@ namespace Umbraco.Infrastructure.HostedServices internal override Task PerformExecuteAsync(object state) { - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs index 4c235255c2..b42de1add5 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs @@ -27,7 +27,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly IRuntimeState _runtimeState; private readonly IServerMessenger _serverMessenger; private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IUmbracoContextFactory _umbracoContextFactory; /// @@ -44,7 +44,7 @@ namespace Umbraco.Infrastructure.HostedServices public ScheduledPublishing( IRuntimeState runtimeState, IMainDom mainDom, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, @@ -69,7 +69,7 @@ namespace Umbraco.Infrastructure.HostedServices return Task.CompletedTask; } - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); @@ -123,9 +123,9 @@ namespace Umbraco.Infrastructure.HostedServices finally { // If running on a temp context, we have to flush the messenger - if (contextReference.IsRoot && _serverMessenger is IBatchedDatabaseServerMessenger m) + if (contextReference.IsRoot) { - m.FlushBatch(); + _serverMessenger.SendMessages(); } } } diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs index 3c291f187b..8b194e32ef 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs @@ -17,7 +17,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration public class InstructionProcessTask : RecurringHostedServiceBase { private readonly IRuntimeState _runtimeState; - private readonly IDatabaseServerMessenger _messenger; + private readonly IServerMessenger _messenger; private readonly ILogger _logger; /// @@ -31,7 +31,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration : base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1)) { _runtimeState = runtimeState; - _messenger = messenger as IDatabaseServerMessenger ?? throw new ArgumentNullException(nameof(messenger)); + _messenger = messenger; _logger = logger; } diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs index 25e975582d..69f9280fc0 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs @@ -57,9 +57,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration try { - // TouchServer uses a proper unit of work etc underneath so even in a - // background task it is safe to call it without dealing with any scope. - _serverRegistrationService.TouchServer(serverAddress, _serverRegistrationService.CurrentServerIdentity, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout); + _serverRegistrationService.TouchServer(serverAddress, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout); } catch (Exception ex) { diff --git a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs index a12634f01d..00f7c80fe4 100644 --- a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs +++ b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.IO; @@ -20,7 +20,7 @@ namespace Umbraco.Web.Install private readonly string[] _packagesPermissionsDirs; // ensure Umbraco can write to these files (the directories must exist) - private readonly string[] _permissionFiles = { }; + private readonly string[] _permissionFiles = Array.Empty(); private readonly GlobalSettings _globalSettings; private readonly IIOHelper _ioHelper; private readonly IHostingEnvironment _hostingEnvironment; @@ -49,26 +49,13 @@ namespace Umbraco.Web.Install if (EnsureFiles(_permissionFiles, out errors) == false) report["File writing failed"] = errors.ToList(); - if (TestPublishedSnapshotService(out errors) == false) - report["Published snapshot environment check failed"] = errors.ToList(); - if (EnsureCanCreateSubDirectory(_globalSettings.UmbracoMediaPath, out errors) == false) report["Media folder creation failed"] = errors.ToList(); return report.Count == 0; } - /// - /// This will test the directories for write access - /// - /// - /// - /// - /// If this is false, the easiest way to test for write access is to write a temp file, however some folder will cause - /// an App Domain restart if a file is written to the folder, so in that case we need to use the ACL APIs which aren't as - /// reliable but we cannot write a file since it will cause an app domain restart. - /// - /// + /// public bool EnsureDirectories(string[] dirs, out IEnumerable errors, bool writeCausesRestart = false) { List temp = null; @@ -96,9 +83,16 @@ namespace Umbraco.Web.Install foreach (var file in files) { var canWrite = TryWriteFile(file); - if (canWrite) continue; + if (canWrite) + { + continue; + } + + if (temp == null) + { + temp = new List(); + } - if (temp == null) temp = new List(); temp.Add(file); success = false; } @@ -130,11 +124,6 @@ namespace Umbraco.Web.Install return success; } - public bool TestPublishedSnapshotService(out IEnumerable errors) - { - return _publishedSnapshotService.EnsureEnvironment(out errors); - } - // tries to create a sub-directory // if successful, the sub-directory is deleted // creates the directory if needed - does not delete it diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index 80570ae5de..b7699b7d0e 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Specialized; using System.Net.Http; using System.Text; @@ -24,7 +24,7 @@ namespace Umbraco.Web.Install.InstallSteps /// display a simple continue installation view. /// [InstallSetupStep(InstallationType.NewInstall, "User", 20, "")] - internal class NewInstallStep : InstallSetupStep + public class NewInstallStep : InstallSetupStep { private readonly IUserService _userService; private readonly DatabaseBuilder _databaseBuilder; diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs index 77385eb2fa..8bc5bcfdff 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs @@ -6,9 +6,9 @@ using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Security; -using Umbraco.Net; using Umbraco.Web.Install.Models; using Umbraco.Web.Security; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs index 8428b60fde..a85e52cffe 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Threading; using Microsoft.Extensions.Options; @@ -55,6 +55,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message)); } else + { try { var dumped = MiniDump.Dump(_marchal, _hostingEnvironment, withException: true); @@ -68,6 +69,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers message = "Failed to create a minidump. " + ex; logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message)); } + } } private static bool IsTimeoutThreadAbortException(Exception exception) diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs deleted file mode 100644 index fc26f922eb..0000000000 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging.Serilog.Enrichers; -using Umbraco.Infrastructure.Logging.Serilog.Enrichers; - -namespace Umbraco.Infrastructure.Logging.Serilog -{ - public class SerilogComposer : ICoreComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs index aa57383541..4c419a1648 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Serilog; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; +using Umbraco.Infrastructure.DependencyInjection; namespace Umbraco.Core.Logging.Viewer { diff --git a/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs b/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs index 94b868f145..1bbd9042b0 100644 --- a/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs +++ b/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; @@ -22,11 +21,19 @@ namespace Umbraco.Core.Manifest private readonly ILocalizationService _localizationService; private readonly ILocalizedTextService _textService; private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; /// /// Initializes a new instance of the class. /// - public DataEditorConverter(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService textService, IShortStringHelper shortStringHelper) + public DataEditorConverter( + ILoggerFactory loggerFactory, + IIOHelper ioHelper, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService textService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) { _loggerFactory = loggerFactory; _ioHelper = ioHelper; @@ -34,6 +41,7 @@ namespace Umbraco.Core.Manifest _localizationService = localizationService; _textService = textService; _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; } /// @@ -61,7 +69,7 @@ namespace Umbraco.Core.Manifest type = EditorType.MacroParameter; } - return new DataEditor(_loggerFactory, _dataTypeService, _localizationService, _textService, _shortStringHelper, type); + return new DataEditor(_loggerFactory, _dataTypeService, _localizationService, _textService, _shortStringHelper, _jsonSerializer, type); } /// @@ -88,7 +96,7 @@ namespace Umbraco.Core.Manifest // explicitly assign a value editor of type ValueEditor // (else the deserializer will try to read it before setting it) // (and besides it's an interface) - target.ExplicitValueEditor = new DataValueEditor(_dataTypeService, _localizationService, _textService, _shortStringHelper); + target.ExplicitValueEditor = new DataValueEditor(_dataTypeService, _localizationService, _textService, _shortStringHelper, _jsonSerializer); // in the manifest, validators are a simple dictionary eg // { @@ -160,7 +168,7 @@ namespace Umbraco.Core.Manifest if (jobject.Property("view") != null) { // explicitly assign a value editor of type ParameterValueEditor - target.ExplicitValueEditor = new DataValueEditor(_dataTypeService, _localizationService, _textService, _shortStringHelper); + target.ExplicitValueEditor = new DataValueEditor(_dataTypeService, _localizationService, _textService, _shortStringHelper, _jsonSerializer); // move the 'view' property jobject["editor"] = new JObject { ["view"] = jobject["view"] }; diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index eec83dffef..d134010104 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -196,7 +196,7 @@ namespace Umbraco.Core.Manifest if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(text)); var manifest = JsonConvert.DeserializeObject(text, - new DataEditorConverter(_loggerFactory, _ioHelper, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper), + new DataEditorConverter(_loggerFactory, _ioHelper, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, _jsonSerializer), new ValueValidatorConverter(_validators), new DashboardAccessRuleConverter()); diff --git a/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs b/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs new file mode 100644 index 0000000000..ad5155e6d2 --- /dev/null +++ b/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs @@ -0,0 +1,53 @@ +using System; +using System.Drawing; +using System.IO; +using Umbraco.Core; +using Umbraco.Core.Media; + +namespace Umbraco.Web.Media +{ + internal class ImageDimensionExtractor : IImageDimensionExtractor + { + /// + /// Gets the dimensions of an image. + /// + /// A stream containing the image bytes. + /// The dimension of the image. + /// First try with EXIF as it is faster and does not load the entire image + /// in memory. Fallback to GDI which means loading the image in memory and thus + /// use potentially large amounts of memory. + public ImageSize GetDimensions(Stream stream) + { + // Try to load with exif + try + { + if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height)) + { + return new ImageSize(width, height); + } + } + catch + { + // We will just swallow, just means we can't read exif data, we don't want to log an error either + } + + // we have no choice but to try to read in via GDI + try + { + // TODO: We should be using ImageSharp for this + using (var image = Image.FromStream(stream)) + { + var fileWidth = image.Width; + var fileHeight = image.Height; + return new ImageSize(fileWidth, fileHeight); + } + } + catch (Exception) + { + // We will just swallow, just means we can't read via GDI, we don't want to log an error either + } + + return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize); + } + } +} diff --git a/src/Umbraco.Infrastructure/Media/ImageHelper.cs b/src/Umbraco.Infrastructure/Media/ImageHelper.cs deleted file mode 100644 index ee01ec4a1c..0000000000 --- a/src/Umbraco.Infrastructure/Media/ImageHelper.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Drawing; -using System.IO; -using Umbraco.Core; -using Umbraco.Web.Media.Exif; - -namespace Umbraco.Web.Media -{ - public static class ImageHelper - { - /// - /// Gets the dimensions of an image. - /// - /// A stream containing the image bytes. - /// The dimension of the image. - /// First try with EXIF as it is faster and does not load the entire image - /// in memory. Fallback to GDI which means loading the image in memory and thus - /// use potentially large amounts of memory. - public static Size GetDimensions(Stream stream) - { - //Try to load with exif - try - { - var jpgInfo = ImageFile.FromStream(stream); - - if (jpgInfo != null - && jpgInfo.Format != ImageFileFormat.Unknown - && jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension) - && jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension)) - { - var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value); - var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value); - if (height > 0 && width > 0) - { - return new Size(width, height); - } - } - } - catch - { - //We will just swallow, just means we can't read exif data, we don't want to log an error either - } - - //we have no choice but to try to read in via GDI - try - { - using (var image = Image.FromStream(stream)) - { - var fileWidth = image.Width; - var fileHeight = image.Height; - return new Size(fileWidth, fileHeight); - } - } - catch (Exception) - { - //We will just swallow, just means we can't read via GDI, we don't want to log an error either - } - - return new Size(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize); - } - } -} diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs b/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs index 9fc5b1b277..22961dea5a 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs @@ -1,5 +1,6 @@ using System; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Migrations { diff --git a/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs b/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs deleted file mode 100644 index cf53f161a4..0000000000 --- a/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Umbraco.Core.Migrations.PostMigrations -{ - /// - /// Implements in Umbraco.Core (doing nothing). - /// - public class NoopPublishedSnapshotRebuilder : IPublishedSnapshotRebuilder - { - /// - public void Rebuild() - { } - } -} diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 483529036b..f4c3326769 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -8,7 +8,6 @@ using System.Xml.XPath; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core.Collections; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -17,7 +16,6 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Serialization; using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; namespace Umbraco.Core.Packaging @@ -36,14 +34,32 @@ namespace Umbraco.Core.Packaging private readonly GlobalSettings _globalSettings; private readonly ILocalizedTextService _localizedTextService; private readonly IConfigurationEditorJsonSerializer _serializer; + private readonly IMediaService _mediaService; + private readonly IMediaTypeService _mediaTypeService; + private readonly IJsonSerializer _jsonSerializer; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; private readonly IContentService _contentService; - public PackageDataInstallation(ILogger logger, ILoggerFactory loggerFactory, IFileService fileService, IMacroService macroService, ILocalizationService localizationService, - IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService, - IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IShortStringHelper shortStringHelper, IOptions globalSettings, - ILocalizedTextService localizedTextService, IConfigurationEditorJsonSerializer serializer) + public PackageDataInstallation( + ILogger logger, + ILoggerFactory loggerFactory, + IFileService fileService, + IMacroService macroService, + ILocalizationService localizationService, + IDataTypeService dataTypeService, + IEntityService entityService, + IContentTypeService contentTypeService, + IContentService contentService, + PropertyEditorCollection propertyEditors, + IScopeProvider scopeProvider, + IShortStringHelper shortStringHelper, + IOptions globalSettings, + ILocalizedTextService localizedTextService, + IConfigurationEditorJsonSerializer serializer, + IMediaService mediaService, + IMediaTypeService mediaTypeService, + IJsonSerializer jsonSerializer) { _logger = logger; _loggerFactory = loggerFactory; @@ -57,6 +73,9 @@ namespace Umbraco.Core.Packaging _globalSettings = globalSettings.Value; _localizedTextService = localizedTextService; _serializer = serializer; + _jsonSerializer = jsonSerializer; + _mediaService = mediaService; + _mediaTypeService = mediaTypeService; _entityService = entityService; _contentTypeService = contentTypeService; _contentService = contentService; @@ -197,29 +216,58 @@ namespace Umbraco.Core.Packaging DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId), MacrosInstalled = ImportMacros(compiledPackage.Macros, userId), TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId), - DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId) + DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId), + MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId), }; //we need a reference to the imported doc types to continue var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x); + var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x); installationSummary.StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId); - installationSummary.ContentInstalled = ImportContent(compiledPackage.Documents, importedDocTypes, userId); + installationSummary.ContentInstalled = ImportContentBase(compiledPackage.Documents, importedDocTypes, userId, _contentTypeService, _contentService); + installationSummary.MediaInstalled = ImportContentBase(compiledPackage.Media, importedMediaTypes, userId, _mediaTypeService, _mediaService); scope.Complete(); return installationSummary; } } + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional id of the User performing the operation. Default is zero (admin). + /// An enumerable list of generated ContentTypes + public IReadOnlyList ImportMediaTypes(IEnumerable docTypeElements, int userId) + { + return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService); + } + + #endregion + #region Content - public IReadOnlyList ImportContent(IEnumerable docs, IDictionary importedDocumentTypes, int userId) + public IReadOnlyList ImportContentBase( + IEnumerable docs, + IDictionary importedDocumentTypes, + int userId, + IContentTypeBaseService typeService, + IContentServiceBase service) + where T: class, IContentBase + where S: IContentTypeComposition { - return docs.SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)).ToList(); + return docs.SelectMany(x => ImportContentBase( + x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty), + -1, + importedDocumentTypes, + userId, + typeService, + service)).ToList(); } /// @@ -230,17 +278,20 @@ namespace Umbraco.Core.Packaging /// A dictionary of already imported document types (basically used as a cache) /// Optional Id of the user performing the import /// An enumerable list of generated content - public IEnumerable ImportContent(CompiledPackageDocument packageDocument, int parentId, IDictionary importedDocumentTypes, int userId) + public IEnumerable ImportContentBase( + IEnumerable roots, + int parentId, + IDictionary importedDocumentTypes, + int userId, + IContentTypeBaseService typeService, + IContentServiceBase service) + where T: class, IContentBase + where S: IContentTypeComposition { - var element = packageDocument.XmlData; - var roots = from doc in element.Elements() - where (string)doc.Attribute("isDoc") == "" - select doc; - - var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList(); + var contents = ParseContentBaseRootXml(roots, parentId, importedDocumentTypes, typeService, service).ToList(); if (contents.Any()) - _contentService.Save(contents, userId); + service.Save(contents, userId); return contents; @@ -249,7 +300,7 @@ namespace Umbraco.Core.Packaging //{ // //This is a single doc import // var elements = new List { element }; - // var contents = ParseDocumentRootXml(elements, parentId, importedDocumentTypes).ToList(); + // var contents = ParseContentBaseRootXml(elements, parentId, importedDocumentTypes).ToList(); // if (contents.Any()) // _contentService.Save(contents, userId); @@ -261,50 +312,64 @@ namespace Umbraco.Core.Packaging // "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); } - private IEnumerable ParseDocumentRootXml(IEnumerable roots, int parentId, IDictionary importedContentTypes) + private IEnumerable ParseContentBaseRootXml( + IEnumerable roots, + int parentId, + IDictionary importedContentTypes, + IContentTypeBaseService typeService, + IContentServiceBase service) + where T: class, IContentBase + where S: IContentTypeComposition { - var contents = new List(); + var contents = new List(); foreach (var root in roots) { var contentTypeAlias = root.Name.LocalName; if (!importedContentTypes.ContainsKey(contentTypeAlias)) { - var contentType = FindContentTypeByAlias(contentTypeAlias); + var contentType = FindContentTypeByAlias(contentTypeAlias, typeService); importedContentTypes.Add(contentTypeAlias, contentType); } - var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], null, parentId); + var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], default(T), parentId, service); if (content == null) continue; contents.Add(content); - var children = (from child in root.Elements() - where (string)child.Attribute("isDoc") == "" - select child) + var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty) .ToList(); if (children.Count > 0) - contents.AddRange(CreateContentFromXml(children, content, importedContentTypes).WhereNotNull()); + { + contents.AddRange(CreateContentFromXml(children, content, importedContentTypes, typeService, service).WhereNotNull()); + } } return contents; } - private IEnumerable CreateContentFromXml(IEnumerable children, IContent parent, IDictionary importedContentTypes) + private IEnumerable CreateContentFromXml( + IEnumerable children, + T parent, + IDictionary importedContentTypes, + IContentTypeBaseService typeService, + IContentServiceBase service) + where T: class, IContentBase + where S: IContentTypeComposition { - var list = new List(); + var list = new List(); foreach (var child in children) { string contentTypeAlias = child.Name.LocalName; if (importedContentTypes.ContainsKey(contentTypeAlias) == false) { - var contentType = FindContentTypeByAlias(contentTypeAlias); + var contentType = FindContentTypeByAlias(contentTypeAlias, typeService); importedContentTypes.Add(contentTypeAlias, contentType); } //Create and add the child to the list - var content = CreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default); + var content = CreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default, service); list.Add(content); //Recursive call @@ -314,19 +379,26 @@ namespace Umbraco.Core.Packaging select grand).ToList(); if (grandChildren.Any()) - list.AddRange(CreateContentFromXml(grandChildren, content, importedContentTypes)); + list.AddRange(CreateContentFromXml(grandChildren, content,importedContentTypes, typeService, service)); } return list; } - private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId) + private T CreateContentFromXml( + XElement element, + S contentType, + T parent, + int parentId, + IContentServiceBase service) + where T: class, IContentBase + where S: IContentTypeComposition { var key = Guid.Empty; if (element.Attribute("key") != null && Guid.TryParse(element.Attribute("key").Value, out key)) { //if a Key is supplied, then we need to check if the content already exists and if so we ignore the installation for this item - if (_contentService.GetById(key) != null) + if (service.GetById(key) != null) return null; } @@ -346,9 +418,9 @@ namespace Umbraco.Core.Packaging var template = templateId.HasValue ? _fileService.GetTemplate(templateId.Value) : null; //now double check this is correct since its an INT it could very well be pointing to an invalid template :/ - if (template != null) + if (template != null && contentType is IContentType contentTypex) { - if (!contentType.IsAllowedTemplate(template.Alias)) + if (!contentTypex.IsAllowedTemplate(template.Alias)) { //well this is awkward, we'll set the template to null and it will be wired up to the default template // when it's persisted in the document repository @@ -356,21 +428,15 @@ namespace Umbraco.Core.Packaging } } - IContent content = parent == null - ? new Content(nodeName, parentId, contentType) - { - Level = int.Parse(level), - SortOrder = int.Parse(sortOrder), - TemplateId = template?.Id, - Key = key - } - : new Content(nodeName, parent, contentType) - { - Level = int.Parse(level), - SortOrder = int.Parse(sortOrder), - TemplateId = template?.Id, - Key = key - }; + T content = CreateContent( + nodeName, + parent, + parentId, + contentType, + key, + int.Parse(level), + int.Parse(sortOrder), + template?.Id); //Here we make sure that we take composition properties in account as well //otherwise we would skip them and end up losing content @@ -396,6 +462,37 @@ namespace Umbraco.Core.Packaging return content; } + private T CreateContent(string name, T parent, int parentId, S contentType, Guid key, int level, int sortOrder, int? templateId) + where T : class, IContentBase + where S : IContentTypeComposition + { + switch (contentType) + { + case IContentType c: + if (parent is null) + { + return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + } + else + { + return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + } + + case IMediaType m: + if (parent is null) + { + return new Umbraco.Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + } + else + { + return new Umbraco.Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + } + + default: + throw new NotSupportedException($"Type {typeof(S)} is not supported"); + } + } + #endregion #region DocumentTypes @@ -413,7 +510,7 @@ namespace Umbraco.Core.Packaging /// An enumerable list of generated ContentTypes public IReadOnlyList ImportDocumentTypes(IEnumerable docTypeElements, int userId) { - return ImportDocumentTypes(docTypeElements.ToList(), true, userId); + return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService); } /// @@ -423,9 +520,10 @@ namespace Umbraco.Core.Packaging /// Boolean indicating whether or not to import the /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes - public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId) + public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService service) + where T: class, IContentTypeComposition { - var importedContentTypes = new Dictionary(); + var importedContentTypes = new Dictionary(); //When you are importing a single doc type we have to assume that the dependencies are already there. //Otherwise something like uSync won't work. @@ -479,10 +577,10 @@ namespace Umbraco.Core.Packaging var alias = documentType.Element("Info").Element("Alias").Value; if (importedContentTypes.ContainsKey(alias) == false) { - var contentType = _contentTypeService.Get(alias); + var contentType = service.Get(alias); importedContentTypes.Add(alias, contentType == null - ? CreateContentTypeFromXml(documentType, importedContentTypes) - : UpdateContentTypeFromXml(documentType, contentType, importedContentTypes)); + ? CreateContentTypeFromXml(documentType, importedContentTypes, service) + : UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service)); } } @@ -497,27 +595,27 @@ namespace Umbraco.Core.Packaging //Save the newly created/updated IContentType objects var list = importedContentTypes.Select(x => x.Value).ToList(); - _contentTypeService.Save(list, userId); + service.Save(list, userId); //Now we can finish the import by updating the 'structure', //which requires the doc types to be saved/available in the db if (importStructure) { - var updatedContentTypes = new List(); + var updatedContentTypes = new List(); //Update the structure here - we can't do it until all DocTypes have been created foreach (var documentType in documentTypes) { var alias = documentType.Element("Info").Element("Alias").Value; var structureElement = documentType.Element("Structure"); //Ensure that we only update ContentTypes which has actual structure-elements - if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue; + if (structureElement == null || structureElement.Elements().Any() == false) continue; - var updated = UpdateContentTypesStructure(importedContentTypes[alias], structureElement, importedContentTypes); + var updated = UpdateContentTypesStructure(importedContentTypes[alias], structureElement, importedContentTypes, service); updatedContentTypes.Add(updated); } //Update ContentTypes with a newly added structure/list of allowed children if (updatedContentTypes.Any()) - _contentTypeService.Save(updatedContentTypes, userId); + service.Save(updatedContentTypes, userId); } return list; @@ -586,33 +684,65 @@ namespace Umbraco.Core.Packaging return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); } - private IContentType CreateContentTypeFromXml(XElement documentType, IReadOnlyDictionary importedContentTypes) + private T CreateContentTypeFromXml(XElement documentType, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) + where T : class, IContentTypeComposition { var infoElement = documentType.Element("Info"); //Name of the master corresponds to the parent var masterElement = infoElement.Element("Master"); - IContentType parent = null; + T parent = default; if (masterElement != null) { var masterAlias = masterElement.Value; parent = importedContentTypes.ContainsKey(masterAlias) ? importedContentTypes[masterAlias] - : _contentTypeService.Get(masterAlias); + : service.Get(masterAlias); } var alias = infoElement.Element("Alias").Value; - var contentType = parent == null - ? new ContentType(_shortStringHelper, -1) { Alias = alias } - : new ContentType(_shortStringHelper, parent, alias); + T contentType = CreateContentType(parent, -1, alias); if (parent != null) contentType.AddContentType(parent); - return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes); + return UpdateContentTypeFromXml(documentType, contentType, importedContentTypes, service); } - private IContentType UpdateContentTypeFromXml(XElement documentType, IContentType contentType, IReadOnlyDictionary importedContentTypes) + private T CreateContentType(T parent, int parentId, string alias) + where T : class, IContentTypeComposition + { + if (typeof(T) == typeof(IContentType)) + { + if (parent is null) + { + return new ContentType(_shortStringHelper, parentId) { Alias = alias } as T; + } + else + { + return new ContentType(_shortStringHelper, (IContentType) parent, alias) as T; + } + + } + + if (typeof(T) == typeof(IMediaType)) + { + if (parent is null) + { + return new MediaType(_shortStringHelper, parentId) { Alias = alias } as T; + } + else + { + return new MediaType(_shortStringHelper, (IMediaType)parent, alias) as T; + } + + } + + throw new NotSupportedException($"Type {typeof(T)} is not supported"); + } + + private T UpdateContentTypeFromXml(XElement documentType, T contentType, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) + where T : IContentTypeComposition { var infoElement = documentType.Element("Info"); var defaultTemplateElement = infoElement.Element("DefaultTemplate"); @@ -646,9 +776,9 @@ namespace Umbraco.Core.Packaging if (masterElement != null) { var masterAlias = masterElement.Value; - IContentType parent = importedContentTypes.ContainsKey(masterAlias) + T parent = importedContentTypes.ContainsKey(masterAlias) ? importedContentTypes[masterAlias] - : _contentTypeService.Get(masterAlias); + : service.Get(masterAlias); contentType.SetParent(parent); } @@ -665,13 +795,17 @@ namespace Umbraco.Core.Packaging var compositionAlias = composition.Value; var compositionContentType = importedContentTypes.ContainsKey(compositionAlias) ? importedContentTypes[compositionAlias] - : _contentTypeService.Get(compositionAlias); + : service.Get(compositionAlias); contentType.AddContentType(compositionContentType); } } } - UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); + if (contentType is IContentType contentTypex) + { + UpdateContentTypesAllowedTemplates(contentTypex, infoElement.Element("AllowedTemplates"), defaultTemplateElement); + } + UpdateContentTypesTabs(contentType, documentType.Element("Tabs")); UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); @@ -716,7 +850,8 @@ namespace Umbraco.Core.Packaging } } - private void UpdateContentTypesTabs(IContentType contentType, XElement tabElement) + private void UpdateContentTypesTabs(T contentType, XElement tabElement) + where T: IContentTypeComposition { if (tabElement == null) return; @@ -742,7 +877,8 @@ namespace Umbraco.Core.Packaging } } - private void UpdateContentTypesProperties(IContentType contentType, XElement genericPropertiesElement) + private void UpdateContentTypesProperties(T contentType, XElement genericPropertiesElement) + where T: IContentTypeComposition { var properties = genericPropertiesElement.Elements("GenericProperty"); foreach (var property in properties) @@ -834,15 +970,16 @@ namespace Umbraco.Core.Packaging } } - private IContentType UpdateContentTypesStructure(IContentType contentType, XElement structureElement, IReadOnlyDictionary importedContentTypes) + private T UpdateContentTypesStructure(T contentType, XElement structureElement, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) + where T: IContentTypeComposition { var allowedChildren = contentType.AllowedContentTypes.ToList(); int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; - foreach (var element in structureElement.Elements("DocumentType")) + foreach (var element in structureElement.Elements()) { var alias = element.Value; - var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : _contentTypeService.Get(alias); + var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : service.Get(alias); if (allowedChild == null) { _logger.LogWarning( @@ -866,9 +1003,10 @@ namespace Umbraco.Core.Packaging /// /// /// - private IContentType FindContentTypeByAlias(string contentTypeAlias) + private S FindContentTypeByAlias(string contentTypeAlias, IContentTypeBaseService typeService) + where S: IContentTypeComposition { - var contentType = _contentTypeService.Get(contentTypeAlias); + var contentType = typeService.Get(contentTypeAlias); if (contentType == null) throw new Exception($"ContentType matching the passed in Alias: '{contentTypeAlias}' was null"); @@ -916,7 +1054,7 @@ namespace Umbraco.Core.Packaging var editorAlias = dataTypeElement.Attribute("Id")?.Value?.Trim(); if (!_propertyEditors.TryGet(editorAlias, out var editor)) - editor = new VoidEditor(_loggerFactory, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper) { Alias = editorAlias }; + editor = new VoidEditor(_loggerFactory, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, _jsonSerializer) { Alias = editorAlias }; var dataType = new DataType(editor, _serializer) { diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index 4970fc302e..df8a58fc8d 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -17,16 +17,11 @@ namespace Umbraco.Core.Packaging private readonly IPackageActionRunner _packageActionRunner; private readonly DirectoryInfo _applicationRootFolder; + /// - /// Constructor + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, - IHostingEnvironment hostingEnvironment) + public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, IHostingEnvironment hostingEnvironment) { _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs index a611186021..2aa450b7b9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs @@ -1,4 +1,4 @@ -using System.Data; +using System.Data; using NPoco; using Umbraco.Core.Persistence.DatabaseAnnotations; diff --git a/src/Umbraco.Infrastructure/Persistence/LocalDb.cs b/src/Umbraco.Infrastructure/Persistence/LocalDb.cs index 4ec233e17f..89fce803b2 100644 --- a/src/Umbraco.Infrastructure/Persistence/LocalDb.cs +++ b/src/Umbraco.Infrastructure/Persistence/LocalDb.cs @@ -937,7 +937,7 @@ namespace Umbraco.Core.Persistence /// This is a C# implementation of T-SQL QUOTEDNAME. /// is optional, it can be '[' (default), ']', '\'' or '"'. /// - private static string QuotedName(string name, char quote = '[') + internal static string QuotedName(string name, char quote = '[') { switch (quote) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs index 4031047970..59387fcb9f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents the NPoco implementation of . /// - internal class AuditEntryRepository : NPocoRepositoryBase, IAuditEntryRepository + internal class AuditEntryRepository : EntityRepositoryBase, IAuditEntryRepository { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs index a42019e59f..8ad370672e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NPoco; @@ -12,7 +12,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class AuditRepository : NPocoRepositoryBase, IAuditRepository + internal class AuditRepository : EntityRepositoryBase, IAuditRepository { public AuditRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs index 47ebddf698..cff06a2126 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; using NPoco; @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents the NPoco implementation of . /// - internal class ConsentRepository : NPocoRepositoryBase, IConsentRepository + internal class ConsentRepository : EntityRepositoryBase, IConsentRepository { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 2533eaea8e..7b90efd4ae 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public static bool ThrowOnWarning = false; } - public abstract class ContentRepositoryBase : NPocoRepositoryBase, IContentRepository + public abstract class ContentRepositoryBase : EntityRepositoryBase, IContentRepository where TEntity : class, IContentBase where TRepository : class, IRepository { @@ -51,7 +51,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected ContentRepositoryBase( IScopeAccessor scopeAccessor, AppCaches cache, - ILogger> logger, + ILogger> logger, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, @@ -767,8 +767,20 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #region UnitOfWork Events - // TODO: The reason these events are in the repository is for legacy, the events should exist at the service - // level now since we can fire these events within the transaction... so move the events to service level + /* + * TODO: The reason these events are in the repository is for legacy, the events should exist at the service + * level now since we can fire these events within the transaction... + * The reason these events 'need' to fire in the transaction is to ensure data consistency with Nucache (currently + * the only thing that uses them). For example, if the transaction succeeds and NuCache listened to ContentService.Saved + * and then NuCache failed at persisting data after the trans completed, then NuCache would be out of sync. This way + * the entire trans is rolled back if NuCache files. This is part of the discussion about removing the static events, + * possibly there's 3 levels of eventing, "ing", "scoped" (in trans) and "ed" (after trans). + * These particular events can be moved to the service level. However, see the notes below, it seems the only event we + * really need is the ScopedEntityRefresh. The only tricky part with moving that to the service level is that the + * handlers of that event will need to deal with the data a little differently because it seems that the + * "Published" flag on the content item matters and this event is raised before that flag is switched. Weird. + * We have the ability with IContent to see if something "WasPublished", etc.. so i think we could still use that. + */ public class ScopedEntityEventArgs : EventArgs { @@ -784,6 +796,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public class ScopedVersionEventArgs : EventArgs { + /// + /// Initializes a new instance of the class. + /// public ScopedVersionEventArgs(IScope scope, int entityId, int versionId) { Scope = scope; @@ -791,13 +806,43 @@ namespace Umbraco.Core.Persistence.Repositories.Implement VersionId = versionId; } + /// + /// Gets the current + /// public IScope Scope { get; } + + /// + /// Gets the entity id + /// public int EntityId { get; } + + /// + /// Gets the version id + /// public int VersionId { get; } } + /// + /// Occurs when an is created or updated from within the (transaction) + /// public static event TypedEventHandler ScopedEntityRefresh; + + /// + /// Occurs when an is being deleted from within the (transaction) + /// + /// + /// TODO: This doesn't seem to be necessary at all, the service "Deleting" events for this would work just fine + /// since they are raised before the item is actually deleted just like this event. + /// public static event TypedEventHandler ScopeEntityRemove; + + /// + /// Occurs when a version for an is being deleted from within the (transaction) + /// + /// + /// TODO: This doesn't seem to be necessary at all, the service "DeletingVersions" events for this would work just fine + /// since they are raised before the item is actually deleted just like this event. + /// public static event TypedEventHandler ScopeVersionRemove; // used by tests to clear events @@ -808,20 +853,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement ScopeVersionRemove = null; } + /// + /// Raises the event + /// protected void OnUowRefreshedEntity(ScopedEntityEventArgs args) - { - ScopedEntityRefresh.RaiseEvent(args, This); - } + => ScopedEntityRefresh.RaiseEvent(args, This); + /// + /// Raises the event + /// protected void OnUowRemovingEntity(ScopedEntityEventArgs args) - { - ScopeEntityRemove.RaiseEvent(args, This); - } + => ScopeEntityRemove.RaiseEvent(args, This); + /// + /// Raises the event + /// protected void OnUowRemovingVersion(ScopedVersionEventArgs args) - { - ScopeVersionRemove.RaiseEvent(args, This); - } + => ScopeVersionRemove.RaiseEvent(args, This); #endregion diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 26596410bf..6554782d24 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Exposes shared functionality /// - internal abstract class ContentTypeRepositoryBase : NPocoRepositoryBase, IReadRepository + internal abstract class ContentTypeRepositoryBase : EntityRepositoryBase, IReadRepository where TEntity : class, IContentTypeComposition { private readonly IShortStringHelper _shortStringHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 482a333631..1f614e7647 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents a repository for doing CRUD operations for /// - internal class DataTypeRepository : NPocoRepositoryBase, IDataTypeRepository + internal class DataTypeRepository : EntityRepositoryBase, IDataTypeRepository { private readonly Lazy _editors; private readonly IConfigurationEditorJsonSerializer _serializer; @@ -81,7 +81,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs index 0c58d26a2a..abab07a7bb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents a repository for doing CRUD operations for /// - internal class DictionaryRepository : NPocoRepositoryBase, IDictionaryRepository + internal class DictionaryRepository : EntityRepositoryBase, IDictionaryRepository { private readonly ILoggerFactory _loggerFactory; @@ -87,7 +87,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 6ed884eb0c..f3b9ca58d6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -952,7 +952,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // reading repository purely for looking up by GUID // TODO: ugly and to fix we need to decouple the IRepositoryQueryable -> IRepository -> IReadRepository which should all be separate things! - private class ContentByGuidReadRepository : NPocoRepositoryBase + private class ContentByGuidReadRepository : EntityRepositoryBase { private readonly DocumentRepository _outerRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs index f0315f747c..e9e62d76c9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { // TODO: We need to get a readonly ISO code for the domain assigned - internal class DomainRepository : NPocoRepositoryBase, IDomainRepository + internal class DomainRepository : EntityRepositoryBase, IDomainRepository { public DomainRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs index 36213b089f..26159c4fdf 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// An internal repository for managing entity containers such as doc type, media type, data type containers. /// - internal class EntityContainerRepository : NPocoRepositoryBase, IEntityContainerRepository + internal class EntityContainerRepository : EntityRepositoryBase, IEntityContainerRepository { private readonly Guid _containerObjectType; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs index 61ced57149..41f6a065d4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs @@ -1,15 +1,16 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using NPoco; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Scoping; -using static Umbraco.Core.Persistence.SqlExtensionsStatics; using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Scoping; using Umbraco.Core.Services; +using static Umbraco.Core.Persistence.SqlExtensionsStatics; namespace Umbraco.Core.Persistence.Repositories.Implement { @@ -20,21 +21,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// Limited to objects that have a corresponding node (in umbracoNode table). /// Returns objects, i.e. lightweight representation of entities. /// - internal class EntityRepository : IEntityRepository + internal class EntityRepository : RepositoryBase, IEntityRepository { - private readonly IScopeAccessor _scopeAccessor; - - public EntityRepository(IScopeAccessor scopeAccessor) + public EntityRepository(IScopeAccessor scopeAccessor, AppCaches appCaches) + : base(scopeAccessor, appCaches) { - _scopeAccessor = scopeAccessor; } - protected IUmbracoDatabase Database => _scopeAccessor.AmbientScope.Database; - protected Sql Sql() => _scopeAccessor.AmbientScope.SqlContext.Sql(); - protected ISqlSyntaxProvider SqlSyntax => _scopeAccessor.AmbientScope.SqlContext.SqlSyntax; - #region Repository - + public IEnumerable GetPagedResultsByQuery(IQuery query, Guid objectType, long pageIndex, int pageSize, out long totalRecords, IQuery filter, Ordering ordering) { @@ -49,17 +44,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var isMedia = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Media); var isMember = objectTypes.Any(objectType => objectType == Constants.ObjectTypes.Member); - var sql = GetBaseWhere(isContent, isMedia, isMember, false, s => + Sql sql = GetBaseWhere(isContent, isMedia, isMember, false, s => { sqlCustomization?.Invoke(s); if (filter != null) { - foreach (var filterClause in filter.GetWhereClauses()) + foreach (Tuple filterClause in filter.GetWhereClauses()) + { s.Where(filterClause.Item1, filterClause.Item2); + } } - - }, objectTypes); ordering = ordering ?? Ordering.ByDefault(); @@ -75,7 +70,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } // TODO: we should be able to do sql = sql.OrderBy(x => Alias(x.NodeId, "NodeId")); but we can't because the OrderBy extension don't support Alias currently - //no matter what we always must have node id ordered at the end + // no matter what we always must have node id ordered at the end sql = ordering.Direction == Direction.Ascending ? sql.OrderBy("NodeId") : sql.OrderByDescending("NodeId"); // for content we must query for ContentEntityDto entities to produce the correct culture variant entity names @@ -102,7 +97,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private IEntitySlim GetEntity(Sql sql, bool isContent, bool isMedia, bool isMember) { - //isContent is going to return a 1:M result now with the variants so we need to do different things + // isContent is going to return a 1:M result now with the variants so we need to do different things if (isContent) { var cdtos = Database.Fetch(sql); @@ -164,7 +159,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private IEnumerable GetEntities(Sql sql, bool isContent, bool isMedia, bool isMember) { - //isContent is going to return a 1:M result now with the variants so we need to do different things + // isContent is going to return a 1:M result now with the variants so we need to do different things if (isContent) { var cdtos = Database.Fetch(sql); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs similarity index 63% rename from src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs rename to src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs index a9e8f4bb16..8f9c5102ab 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; +using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Querying; @@ -9,53 +10,38 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { + /// - /// Provides a base class to all repositories. + /// Provides a base class to all based repositories. /// - /// The type of the entity managed by this repository. /// The type of the entity's unique identifier. - public abstract class RepositoryBase : IReadWriteQueryRepository + /// The type of the entity managed by this repository. + public abstract class EntityRepositoryBase : RepositoryBase, IReadWriteQueryRepository where TEntity : class, IEntity { private IRepositoryCachePolicy _cachePolicy; - - protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger> logger) - { - ScopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); - } - - protected ILogger> Logger { get; } - - protected AppCaches AppCaches { get; } - - protected IAppPolicyCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate(); - - protected IScopeAccessor ScopeAccessor { get; } - - protected IScope AmbientScope - { - get - { - var scope = ScopeAccessor.AmbientScope; - if (scope == null) - throw new InvalidOperationException("Cannot run a repository without an ambient scope."); - return scope; - } - } - - #region Static Queries - private IQuery _hasIdQuery; + private static RepositoryCachePolicyOptions s_defaultOptions; - #endregion - - protected virtual TId GetEntityId(TEntity entity) + /// + /// Initializes a new instance of the class. + /// + protected EntityRepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger> logger) + : base(scopeAccessor, appCaches) { - return (TId) (object) entity.Id; + Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } + /// + /// Gets the logger + /// + protected ILogger> Logger { get; } + + /// + /// Gets the isolated cache for the + /// + protected IAppPolicyCache GlobalIsolatedCache => AppCaches.IsolatedCaches.GetOrCreate(); + /// /// Gets the isolated cache. /// @@ -78,30 +64,34 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } - // ReSharper disable once StaticMemberInGenericType - private static RepositoryCachePolicyOptions _defaultOptions; - // ReSharper disable once InconsistentNaming - protected virtual RepositoryCachePolicyOptions DefaultOptions - { - get - { - return _defaultOptions ?? (_defaultOptions + /// + /// Gets the default + /// + protected virtual RepositoryCachePolicyOptions DefaultOptions => s_defaultOptions ?? (s_defaultOptions = new RepositoryCachePolicyOptions(() => { // get count of all entities of current type (TEntity) to ensure cached result is correct // create query once if it is needed (no need for locking here) - query is static! - var query = _hasIdQuery ?? (_hasIdQuery = AmbientScope.SqlContext.Query().Where(x => x.Id != 0)); + IQuery query = _hasIdQuery ?? (_hasIdQuery = AmbientScope.SqlContext.Query().Where(x => x.Id != 0)); return PerformCount(query); })); - } - } + /// + /// Gets the node object type for the repository's entity + /// + protected abstract Guid NodeObjectTypeId { get; } + + /// + /// Gets the repository cache policy + /// protected IRepositoryCachePolicy CachePolicy { get { if (AppCaches == AppCaches.NoCache) + { return NoCacheRepositoryCachePolicy.Instance; + } // create the cache policy using IsolatedCache which is either global // or scoped depending on the repository cache mode for the current scope @@ -122,66 +112,102 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } + /// + /// Get the entity id for the + /// + protected virtual TId GetEntityId(TEntity entity) + => (TId)(object)entity.Id; + + /// + /// Create the repository cache policy + /// protected virtual IRepositoryCachePolicy CreateCachePolicy() - { - return new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); - } + => new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); /// /// Adds or Updates an entity of type TEntity /// /// This method is backed by an cache - /// public virtual void Save(TEntity entity) { if (entity.HasIdentity == false) + { CachePolicy.Create(entity, PersistNewItem); + } else + { CachePolicy.Update(entity, PersistUpdatedItem); + } } /// /// Deletes the passed in entity /// - /// public virtual void Delete(TEntity entity) - { - CachePolicy.Delete(entity, PersistDeletedItem); - } + => CachePolicy.Delete(entity, PersistDeletedItem); protected abstract TEntity PerformGet(TId id); + protected abstract IEnumerable PerformGetAll(params TId[] ids); + protected abstract IEnumerable PerformGetByQuery(IQuery query); - protected abstract bool PerformExists(TId id); - protected abstract int PerformCount(IQuery query); protected abstract void PersistNewItem(TEntity item); - protected abstract void PersistUpdatedItem(TEntity item); - protected abstract void PersistDeletedItem(TEntity item); + protected abstract void PersistUpdatedItem(TEntity item); + + // TODO: obsolete, use QueryType instead everywhere like GetBaseQuery(QueryType queryType); + protected abstract Sql GetBaseQuery(bool isCount); + + protected abstract string GetBaseWhereClause(); + + protected abstract IEnumerable GetDeleteClauses(); + + protected virtual bool PerformExists(TId id) + { + var sql = GetBaseQuery(true); + sql.Where(GetBaseWhereClause(), new { id = id }); + var count = Database.ExecuteScalar(sql); + return count == 1; + } + + protected virtual int PerformCount(IQuery query) + { + var sqlClause = GetBaseQuery(true); + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate(); + + return Database.ExecuteScalar(sql); + } + + protected virtual void PersistDeletedItem(TEntity entity) + { + var deletes = GetDeleteClauses(); + foreach (var delete in deletes) + { + Database.Execute(delete, new { id = GetEntityId(entity) }); + } + + entity.DeleteDate = DateTime.Now; + } /// /// Gets an entity by the passed in Id utilizing the repository's cache policy /// - /// - /// public TEntity Get(TId id) - { - return CachePolicy.Get(id, PerformGet, PerformGetAll); - } + => CachePolicy.Get(id, PerformGet, PerformGetAll); /// /// Gets all entities of type TEntity or a list according to the passed in Ids /// - /// - /// public IEnumerable GetMany(params TId[] ids) { - //ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries + // ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries ids = ids.Distinct() - //don't query by anything that is a default of T (like a zero) + + // don't query by anything that is a default of T (like a zero) // TODO: I think we should enabled this in case accidental calls are made to get all with invalid ids - //.Where(x => Equals(x, default(TId)) == false) + // .Where(x => Equals(x, default(TId)) == false) .ToArray(); // can't query more than 2000 ids at a time... but if someone is really querying 2000+ entities, @@ -197,39 +223,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { entities.AddRange(CachePolicy.GetAll(groupOfIds.ToArray(), PerformGetAll)); } + return entities; } /// /// Gets a list of entities by the passed in query /// - /// - /// public IEnumerable Get(IQuery query) - { - return PerformGetByQuery(query) - //ensure we don't include any null refs in the returned collection! - .WhereNotNull(); - } + => PerformGetByQuery(query) + .WhereNotNull(); // ensure we don't include any null refs in the returned collection! /// /// Returns a boolean indicating whether an entity with the passed Id exists /// - /// - /// public bool Exists(TId id) - { - return CachePolicy.Exists(id, PerformExists, PerformGetAll); - } + => CachePolicy.Exists(id, PerformExists, PerformGetAll); /// /// Returns an integer with the count of entities found with the passed in query /// - /// - /// public int Count(IQuery query) - { - return PerformCount(query); - } + => PerformCount(query); } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs index c3ed111ffb..29cbdf04e5 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { // TODO: We should update this to support both users and members. It means we would remove referential integrity from users // and the user/member key would be a GUID (we also need to add a GUID to users) - internal class ExternalLoginRepository : NPocoRepositoryBase, IExternalLoginRepository + internal class ExternalLoginRepository : EntityRepositoryBase, IExternalLoginRepository { public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs index eb55b476c7..ba3754486c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class KeyValueRepository : NPocoRepositoryBase, IKeyValueRepository + internal class KeyValueRepository : EntityRepositoryBase, IKeyValueRepository { public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Guid NodeObjectTypeId => throw new NotSupportedException(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs index fd791fe01f..bd72a3faf5 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents a repository for doing CRUD operations for /// - internal class LanguageRepository : NPocoRepositoryBase, ILanguageRepository + internal class LanguageRepository : EntityRepositoryBase, ILanguageRepository { private readonly GlobalSettings _globalSettings; private readonly Dictionary _codeIdMap = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -86,7 +86,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs index 61dad47378..678f826fb4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs @@ -14,7 +14,7 @@ using Umbraco.Core.Strings; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class MacroRepository : NPocoRepositoryBase, IMacroRepository + internal class MacroRepository : EntityRepositoryBase, IMacroRepository { private readonly IShortStringHelper _shortStringHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index 0ebea656b1..7e3425707a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -412,7 +412,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// TODO: This is ugly and to fix we need to decouple the IRepositoryQueryable -> IRepository -> IReadRepository which should all be separate things! /// Then we can do the same thing with repository instances and we wouldn't need to leave all these methods as not implemented because we wouldn't need to implement them /// - private class MediaByGuidReadRepository : NPocoRepositoryBase + private class MediaByGuidReadRepository : EntityRepositoryBase { private readonly MediaRepository _outerRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs index 482a0e627f..6916203e93 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -14,7 +14,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class MemberGroupRepository : NPocoRepositoryBase, IMemberGroupRepository + internal class MemberGroupRepository : EntityRepositoryBase, IMemberGroupRepository { public MemberGroupRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs deleted file mode 100644 index 392e7bdf1f..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using NPoco; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Cache; -using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.Scoping; - -namespace Umbraco.Core.Persistence.Repositories.Implement -{ - /// - /// Represent an abstract Repository for NPoco based repositories - /// - /// - /// - public abstract class NPocoRepositoryBase : RepositoryBase - where TEntity : class, IEntity - { - /// - /// Initializes a new instance of the class. - /// - protected NPocoRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) - : base(scopeAccessor, cache, logger) - { } - - /// - /// Gets the repository's database. - /// - protected IUmbracoDatabase Database => AmbientScope.Database; - - /// - /// Gets the Sql context. - /// - protected ISqlContext SqlContext=> AmbientScope.SqlContext; - - protected Sql Sql() => SqlContext.Sql(); - protected Sql Sql(string sql, params object[] args) => SqlContext.Sql(sql, args); - protected ISqlSyntaxProvider SqlSyntax => SqlContext.SqlSyntax; - protected IQuery Query() => SqlContext.Query(); - - #region Abstract Methods - - protected abstract Sql GetBaseQuery(bool isCount); // TODO: obsolete, use QueryType instead everywhere - protected abstract string GetBaseWhereClause(); - protected abstract IEnumerable GetDeleteClauses(); - protected abstract Guid NodeObjectTypeId { get; } - protected abstract override void PersistNewItem(TEntity entity); - protected abstract override void PersistUpdatedItem(TEntity entity); - - #endregion - - protected override bool PerformExists(TId id) - { - var sql = GetBaseQuery(true); - sql.Where(GetBaseWhereClause(), new { id = id}); - var count = Database.ExecuteScalar(sql); - return count == 1; - } - - protected override int PerformCount(IQuery query) - { - var sqlClause = GetBaseQuery(true); - var translator = new SqlTranslator(sqlClause, query); - var sql = translator.Translate(); - - return Database.ExecuteScalar(sql); - } - - protected override void PersistDeletedItem(TEntity entity) - { - var deletes = GetDeleteClauses(); - foreach (var delete in deletes) - { - Database.Execute(delete, new { id = GetEntityId(entity) }); - } - entity.DeleteDate = DateTime.Now; - } - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs index 279a7075ea..161de8c58e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// This repo implements the base class so that permissions can be queued to be persisted /// like the normal repository pattern but the standard repository Get commands don't apply and will throw /// - internal class PermissionRepository : NPocoRepositoryBase + internal class PermissionRepository : EntityRepositoryBase where TEntity : class, IEntity { public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs index 6d2f95bb4d..5730272dd9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -13,7 +13,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class PublicAccessRepository : NPocoRepositoryBase, IPublicAccessRepository + internal class PublicAccessRepository : EntityRepositoryBase, IPublicAccessRepository { public PublicAccessRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs index 9e72846b58..246adf7415 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class RedirectUrlRepository : NPocoRepositoryBase, IRedirectUrlRepository + internal class RedirectUrlRepository : EntityRepositoryBase, IRedirectUrlRepository { public RedirectUrlRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 21b4ce5911..4299d50f15 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents a repository for doing CRUD operations for /// - internal class RelationRepository : NPocoRepositoryBase, IRelationRepository + internal class RelationRepository : EntityRepositoryBase, IRelationRepository { private readonly IRelationTypeRepository _relationTypeRepository; private readonly IEntityRepository _entityRepository; @@ -88,7 +88,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs index 398dd225ba..953999eaf2 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents a repository for doing CRUD operations for /// - internal class RelationTypeRepository : NPocoRepositoryBase, IRelationTypeRepository + internal class RelationTypeRepository : EntityRepositoryBase, IRelationTypeRepository { public RelationTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) @@ -87,7 +87,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs new file mode 100644 index 0000000000..8b9d8fe77c --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBase.cs @@ -0,0 +1,81 @@ +using System; +using NPoco; +using Umbraco.Core.Cache; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Scoping; + +namespace Umbraco.Core.Persistence.Repositories.Implement +{ + /// + /// Base repository class for all instances + /// + public abstract class RepositoryBase : IRepository + { + /// + /// Initializes a new instance of the class. + /// + protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches) + { + ScopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); + AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); + } + + /// + /// Gets the + /// + protected AppCaches AppCaches { get; } + + /// + /// Gets the + /// + protected IScopeAccessor ScopeAccessor { get; } + + /// + /// Gets the AmbientScope + /// + protected IScope AmbientScope + { + get + { + IScope scope = ScopeAccessor.AmbientScope; + if (scope == null) + { + throw new InvalidOperationException("Cannot run a repository without an ambient scope."); + } + + return scope; + } + } + + /// + /// Gets the repository's database. + /// + protected IUmbracoDatabase Database => AmbientScope.Database; + + /// + /// Gets the Sql context. + /// + protected ISqlContext SqlContext => AmbientScope.SqlContext; + + /// + /// Gets the + /// + protected ISqlSyntaxProvider SqlSyntax => SqlContext.SqlSyntax; + + /// + /// Creates an expression + /// + protected Sql Sql() => SqlContext.Sql(); + + /// + /// Creates a expression + /// + protected Sql Sql(string sql, params object[] args) => SqlContext.Sql(sql, args); + + /// + /// Creates a new query expression + /// + protected IQuery Query() => SqlContext.Query(); + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index f215a8997b..556f837245 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -13,7 +13,7 @@ using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class ServerRegistrationRepository : NPocoRepositoryBase, IServerRegistrationRepository + internal class ServerRegistrationRepository : EntityRepositoryBase, IServerRegistrationRepository { public ServerRegistrationRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs index bbe751d2c6..9ddb5c5b60 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Simple abstract ReadOnly repository used to simply have PerformGet and PeformGetAll with an underlying cache /// - internal abstract class SimpleGetRepository : NPocoRepositoryBase + internal abstract class SimpleGetRepository : EntityRepositoryBase where TEntity : class, IEntity where TDto: class { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs index dcd9464ae0..94c2f4289a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs @@ -15,7 +15,7 @@ using static Umbraco.Core.Persistence.SqlExtensionsStatics; namespace Umbraco.Core.Persistence.Repositories.Implement { - internal class TagRepository : NPocoRepositoryBase, ITagRepository + internal class TagRepository : EntityRepositoryBase, ITagRepository { public TagRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index b36474d688..d391bb9e4d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents the Template Repository /// - internal class TemplateRepository : NPocoRepositoryBase, ITemplateRepository + internal class TemplateRepository : EntityRepositoryBase, ITemplateRepository { private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; @@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs index 30b9b29416..4786548e57 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents the UserGroupRepository for doing CRUD operations for /// - public class UserGroupRepository : NPocoRepositoryBase, IUserGroupRepository + public class UserGroupRepository : EntityRepositoryBase, IUserGroupRepository { private readonly IShortStringHelper _shortStringHelper; private readonly UserGroupWithUsersRepository _userGroupWithUsersRepository; @@ -216,7 +216,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected Sql GetBaseQuery(QueryType type) { @@ -358,7 +358,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// used to persist a user group with associated users at once /// - private class UserGroupWithUsersRepository : NPocoRepositoryBase + private class UserGroupWithUsersRepository : EntityRepositoryBase { private readonly UserGroupRepository _userGroupRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index 51000dbe70..1557dcc1d1 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Represents the UserRepository for doing CRUD operations for /// - internal class UserRepository : NPocoRepositoryBase, IUserRepository + internal class UserRepository : EntityRepositoryBase, IUserRepository { private readonly IMapperCollection _mapperCollection; private readonly GlobalSettings _globalSettings; @@ -376,7 +376,7 @@ ORDER BY colName"; #endregion - #region Overrides of NPocoRepositoryBase + #region Overrides of EntityRepositoryBase protected override Sql GetBaseQuery(bool isCount) { diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 7b98bd150e..5c3c984677 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -327,16 +327,5 @@ namespace Umbraco.Core.Persistence //db?.Dispose(); Volatile.Write(ref _initialized, false); } - - // during tests, the thread static var can leak between tests - // this method provides a way to force-reset the variable - internal void ResetForTests() - { - // TODO: remove all this eventually - //var db = _umbracoDatabaseAccessor.UmbracoDatabase; - //_umbracoDatabaseAccessor.UmbracoDatabase = null; - //db?.Dispose(); - //_databaseScopeAccessor.Scope = null; - } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs index b1e5fb0199..81281a3302 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs @@ -1,14 +1,15 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Blocks; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using static Umbraco.Core.Models.Blocks.BlockItemData; @@ -35,8 +36,9 @@ namespace Umbraco.Web.PropertyEditors IContentTypeService contentTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _localizedTextService = localizedTextService; _propertyEditors = propertyEditors; @@ -49,7 +51,7 @@ namespace Umbraco.Web.PropertyEditors #region Value Editor - protected override IDataValueEditor CreateValueEditor() => new BlockEditorPropertyValueEditor(Attribute, PropertyEditors, _dataTypeService, _contentTypeService, _localizedTextService, LoggerFactory.CreateLogger(), LocalizationService,ShortStringHelper); + protected override IDataValueEditor CreateValueEditor() => new BlockEditorPropertyValueEditor(Attribute, PropertyEditors, _dataTypeService, _contentTypeService, _localizedTextService, LoggerFactory.CreateLogger(), LocalizationService,ShortStringHelper, JsonSerializer); internal class BlockEditorPropertyValueEditor : DataValueEditor, IDataValueReference { @@ -58,8 +60,8 @@ namespace Umbraco.Web.PropertyEditors private readonly ILogger _logger; private readonly BlockEditorValues _blockEditorValues; - public BlockEditorPropertyValueEditor(DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizedTextService textService, ILogger logger, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(dataTypeService, localizationService, textService, shortStringHelper, attribute) + public BlockEditorPropertyValueEditor(DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizedTextService textService, ILogger logger, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, textService, shortStringHelper, jsonSerializer, attribute) { _propertyEditors = propertyEditors; _dataTypeService = dataTypeService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs index 6a23d0da00..1657b4098d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs @@ -1,12 +1,9 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; +using System; using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Models.Blocks; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -34,8 +31,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizedTextService localizedTextService, IIOHelper ioHelper, ILocalizationService localizationService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, propertyEditors, dataTypeService, contentTypeService, localizedTextService, localizationService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, propertyEditors, dataTypeService, contentTypeService, localizedTextService, localizationService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs index 09600d86ae..27d729e319 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -28,8 +29,8 @@ namespace Umbraco.Web.PropertyEditors /// /// The constructor will setup the property editor based on the attribute if one is found /// - public CheckBoxListPropertyEditor(ILoggerFactory loggerFactory, ILocalizedTextService textService, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper, ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public CheckBoxListPropertyEditor(ILoggerFactory loggerFactory, ILocalizedTextService textService, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper, ILocalizedTextService localizedTextService, IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _textService = textService; _dataTypeService = dataTypeService; @@ -43,6 +44,6 @@ namespace Umbraco.Web.PropertyEditors protected override IConfigurationEditor CreateConfigurationEditor() => new ValueListConfigurationEditor(_textService, _ioHelper); /// - protected override IDataValueEditor CreateValueEditor() => new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, JsonSerializer, Attribute); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs index e2cc93bd7c..f5776b7c28 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs @@ -1,19 +1,23 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Runtime.Serialization; using System.Text.RegularExpressions; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Web.PropertyEditors { internal class ColorPickerConfigurationEditor : ConfigurationEditor { - public ColorPickerConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) + private readonly IJsonSerializer _jsonSerializer; + + public ColorPickerConfigurationEditor(IIOHelper ioHelper, IJsonSerializer jsonSerializer) : base(ioHelper) { + _jsonSerializer = jsonSerializer; var items = Fields.First(x => x.Key == "items"); // customize the items field @@ -67,7 +71,7 @@ namespace Umbraco.Web.PropertyEditors { try { - var o = JsonConvert.DeserializeObject(item.Value); + var o = _jsonSerializer.Deserialize(item.Value); o.SortOrder = sortOrder; return o; } @@ -82,15 +86,16 @@ namespace Umbraco.Web.PropertyEditors } // represents an item we are exchanging with the editor + [DataContract] private class ItemValue { - [JsonProperty("value")] + [DataMember(Name ="value")] public string Color { get; set; } - [JsonProperty("label")] + [DataMember(Name ="label")] public string Label { get; set; } - [JsonProperty("sortOrder")] + [DataMember(Name ="sortOrder")] public int SortOrder { get; set; } } @@ -131,7 +136,7 @@ namespace Umbraco.Web.PropertyEditors if (id >= nextId) nextId = id + 1; var label = item.Property("label")?.Value?.Value(); - value = JsonConvert.SerializeObject(new { value, label }); + value = _jsonSerializer.Serialize(new { value, label }); output.Items.Add(new ValueListConfiguration.ValueListItem { Id = id, Value = value }); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs index 575609a934..aec8e4b137 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,13 +18,13 @@ namespace Umbraco.Web.PropertyEditors { private readonly IIOHelper _ioHelper; - public ColorPickerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public ColorPickerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService, IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } /// - protected override IConfigurationEditor CreateConfigurationEditor() => new ColorPickerConfigurationEditor(_ioHelper); + protected override IConfigurationEditor CreateConfigurationEditor() => new ColorPickerConfigurationEditor(_ioHelper, JsonSerializer); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs index 4c172ccb2e..c95f14e8e0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs @@ -4,6 +4,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -32,8 +33,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizedTextService localizedTextService, ILoggerFactory loggerFactory, IIOHelper ioHelper, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -46,11 +48,12 @@ namespace Umbraco.Web.PropertyEditors return new ContentPickerConfigurationEditor(_ioHelper); } - protected override IDataValueEditor CreateValueEditor() => new ContentPickerPropertyValueEditor(_dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new ContentPickerPropertyValueEditor(_dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, JsonSerializer, Attribute); internal class ContentPickerPropertyValueEditor : DataValueEditor, IDataValueReference { - public ContentPickerPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public ContentPickerPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer, DataEditorAttribute attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs index db4c6734a8..40ece10a1e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -24,8 +25,8 @@ namespace Umbraco.Web.PropertyEditors /// Initializes a new instance of the class. /// /// - public DateTimePropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public DateTimePropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs index 66f605bc36..186730775e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -21,8 +22,15 @@ namespace Umbraco.Web.PropertyEditors private readonly IShortStringHelper _shortStringHelper; private readonly IIOHelper _ioHelper; - public DropDownFlexiblePropertyEditor(ILocalizedTextService textService, ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper) - : base(loggerFactory, dataTypeService, localizationService, textService, shortStringHelper) + public DropDownFlexiblePropertyEditor( + ILocalizedTextService textService, + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IShortStringHelper shortStringHelper, + IIOHelper ioHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, textService, shortStringHelper, jsonSerializer) { _textService = textService; _dataTypeService = dataTypeService; @@ -33,7 +41,7 @@ namespace Umbraco.Web.PropertyEditors protected override IDataValueEditor CreateValueEditor() { - return new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _textService, _shortStringHelper, Attribute); + return new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _textService, _shortStringHelper, JsonSerializer, Attribute); } protected override IConfigurationEditor CreateConfigurationEditor() => new DropDownFlexibleConfigurationEditor(_textService, _ioHelper); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs index 2cdfd4f7eb..120a522cd7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs @@ -3,6 +3,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -27,8 +28,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 448e2043c0..b425432b01 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -7,9 +7,9 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Media; @@ -39,8 +39,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, - UploadAutoFillProperties uploadAutoFillProperties) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + UploadAutoFillProperties uploadAutoFillProperties, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _contentSettings = contentSettings.Value; @@ -56,7 +57,7 @@ namespace Umbraco.Web.PropertyEditors /// The corresponding property value editor. protected override IDataValueEditor CreateValueEditor() { - var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Options.Create(_contentSettings)); + var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Options.Create(_contentSettings), JsonSerializer); editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, Options.Create(_contentSettings))); return editor; } @@ -162,7 +163,7 @@ namespace Umbraco.Web.PropertyEditors /// /// The event sender. /// The event arguments. - internal void MediaServiceSaving(IMediaService sender, Core.Events.SaveEventArgs args) + public void MediaServiceSaving(IMediaService sender, Core.Events.SaveEventArgs args) { foreach (var entity in args.SavedEntities) AutoFillProperties(entity); @@ -173,7 +174,7 @@ namespace Umbraco.Web.PropertyEditors /// /// The event sender. /// The event arguments. - internal void ContentServiceSaving(IContentService sender, Core.Events.SaveEventArgs args) + public void ContentServiceSaving(IContentService sender, Core.Events.SaveEventArgs args) { foreach (var entity in args.SavedEntities) AutoFillProperties(entity); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index db675e2e42..8ccb59988d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -26,8 +27,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, - IOptions contentSettings) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + IOptions contentSettings, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs index e6db6a4328..2bac76e6f9 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Templates; @@ -47,8 +48,9 @@ namespace Umbraco.Web.PropertyEditors HtmlLocalLinkParser localLinkParser, IIOHelper ioHelper, IShortStringHelper shortStringHelper, - IImageUrlGenerator imageUrlGenerator) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IImageUrlGenerator imageUrlGenerator, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _ioHelper = ioHelper; @@ -64,7 +66,7 @@ namespace Umbraco.Web.PropertyEditors /// Overridden to ensure that the value is validated /// /// - protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator); + protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator, JsonSerializer); protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor(_ioHelper); @@ -87,14 +89,15 @@ namespace Umbraco.Web.PropertyEditors RichTextEditorPastedImages pastedImages, HtmlLocalLinkParser localLinkParser, IShortStringHelper shortStringHelper, - IImageUrlGenerator imageUrlGenerator) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + IImageUrlGenerator imageUrlGenerator, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; _pastedImages = pastedImages; - _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, backOfficeSecurityAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages, imageUrlGenerator); - _mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute); + _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, backOfficeSecurityAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages, imageUrlGenerator, jsonSerializer); + _mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute); _imageUrlGenerator = imageUrlGenerator; } diff --git a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfiguration.cs similarity index 100% rename from src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs rename to src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfiguration.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 3434ee5bcb..1f35b9d88a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -1,17 +1,17 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Media; @@ -50,8 +50,9 @@ namespace Umbraco.Web.PropertyEditors IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService, - UploadAutoFillProperties uploadAutoFillProperties) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + UploadAutoFillProperties uploadAutoFillProperties, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); @@ -76,7 +77,7 @@ namespace Umbraco.Web.PropertyEditors /// Creates the corresponding property value editor. /// /// The corresponding property value editor. - protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, LoggerFactory.CreateLogger(), _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings); + protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, LoggerFactory.CreateLogger(), _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings, JsonSerializer); /// /// Creates the corresponding preValue editor. diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 6a1f3072d4..c058856ebd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using File = System.IO.File; @@ -32,8 +33,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, - ContentSettings contentSettings) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + ContentSettings contentSettings, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs index 639a9c928d..78c5087c66 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.IO; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -21,14 +22,14 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - public LabelPropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public LabelPropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } /// - protected override IDataValueEditor CreateValueEditor() => new LabelPropertyValueEditor(DataTypeService, LocalizationService,LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new LabelPropertyValueEditor(DataTypeService, LocalizationService,LocalizedTextService, ShortStringHelper, Attribute, JsonSerializer); /// protected override IConfigurationEditor CreateConfigurationEditor() => new LabelConfigurationEditor(_ioHelper); @@ -36,8 +37,8 @@ namespace Umbraco.Core.PropertyEditors // provides the property value editor internal class LabelPropertyValueEditor : DataValueEditor { - public LabelPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public LabelPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute, IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs index e01258eb80..d7fd2d9340 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -24,15 +25,21 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - /// public ListViewPropertyEditor( ILoggerFactory loggerFactory, IIOHelper iioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base( + loggerFactory, + dataTypeService, + localizationService, + localizedTextService, + shortStringHelper, + jsonSerializer) { _iioHelper = iioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs index ab4e6f3d97..97386de326 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -30,8 +31,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs index 476674b1ff..e69ff5be9d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs @@ -4,6 +4,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -33,8 +34,9 @@ namespace Umbraco.Web.PropertyEditors ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, - ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + ILocalizedTextService localizedTextService, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } @@ -42,12 +44,18 @@ namespace Umbraco.Web.PropertyEditors /// protected override IConfigurationEditor CreateConfigurationEditor() => new MediaPickerConfigurationEditor(_ioHelper); - protected override IDataValueEditor CreateValueEditor() => new MediaPickerPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new MediaPickerPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer, Attribute); public class MediaPickerPropertyValueEditor : DataValueEditor, IDataValueReference { - public MediaPickerPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService,localizationService, localizedTextService, shortStringHelper,attribute) + public MediaPickerPropertyValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute) + : base(dataTypeService,localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index fc80aabdd9..b7ec4813b2 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -4,6 +4,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,20 +21,33 @@ namespace Umbraco.Web.PropertyEditors { private readonly IIOHelper _ioHelper; - public MultiNodeTreePickerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public MultiNodeTreePickerPropertyEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } protected override IConfigurationEditor CreateConfigurationEditor() => new MultiNodePickerConfigurationEditor(_ioHelper); - protected override IDataValueEditor CreateValueEditor() => new MultiNodeTreePickerPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new MultiNodeTreePickerPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer, Attribute); public class MultiNodeTreePickerPropertyValueEditor : DataValueEditor, IDataValueReference { - public MultiNodeTreePickerPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public MultiNodeTreePickerPropertyValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs index afd749eed3..fdb908e2be 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PublishedCache; @@ -26,8 +27,19 @@ namespace Umbraco.Web.PropertyEditors private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; - public MultiUrlPickerPropertyEditor(ILoggerFactory loggerFactory, Lazy entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, EditorType.PropertyValue) + public MultiUrlPickerPropertyEditor( + ILoggerFactory loggerFactory, + Lazy entityService, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedUrlProvider publishedUrlProvider, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, EditorType.PropertyValue) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor)); @@ -38,6 +50,6 @@ namespace Umbraco.Web.PropertyEditors protected override IConfigurationEditor CreateConfigurationEditor() => new MultiUrlPickerConfigurationEditor(_ioHelper); - protected override IDataValueEditor CreateValueEditor() => new MultiUrlPickerValueEditor(_entityService.Value, _publishedSnapshotAccessor, LoggerFactory.CreateLogger(), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute, _umbracoContextAccessor, _publishedUrlProvider); + protected override IDataValueEditor CreateValueEditor() => new MultiUrlPickerValueEditor(_entityService.Value, _publishedSnapshotAccessor, LoggerFactory.CreateLogger(), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute, _umbracoContextAccessor, _publishedUrlProvider, JsonSerializer); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs index 380408c2b1..a4427cd26d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -1,14 +1,15 @@ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Entities; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; @@ -25,8 +26,19 @@ namespace Umbraco.Web.PropertyEditors private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - public MultiUrlPickerValueEditor(IEntityService entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public MultiUrlPickerValueEditor( + IEntityService entityService, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + ILogger logger, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + DataEditorAttribute attribute, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedUrlProvider publishedUrlProvider, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor)); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs index b4e1287315..c9aeb0e59a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -36,8 +37,15 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public MultipleTextStringPropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public MultipleTextStringPropertyEditor( + ILoggerFactory loggerFactory, + IIOHelper ioHelper, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; _dataTypeService = dataTypeService; @@ -46,7 +54,7 @@ namespace Umbraco.Web.PropertyEditors } /// - protected override IDataValueEditor CreateValueEditor() => new MultipleTextStringPropertyValueEditor(_dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new MultipleTextStringPropertyValueEditor(_dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, JsonSerializer, Attribute); /// protected override IConfigurationEditor CreateConfigurationEditor() => new MultipleTextStringConfigurationEditor(_ioHelper); @@ -58,8 +66,14 @@ namespace Umbraco.Web.PropertyEditors { private readonly ILocalizedTextService _localizedTextService; - public MultipleTextStringPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public MultipleTextStringPropertyValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _localizedTextService = localizedTextService; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs index a960ac51ad..5f82ed940f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,8 +21,16 @@ namespace Umbraco.Web.PropertyEditors { private readonly ILogger _logger; - public MultipleValueEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + public MultipleValueEditor( + ILogger logger, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + DataEditorAttribute attribute + ) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _logger = logger; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 98f8771699..8afc08c423 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -9,6 +9,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -42,8 +43,9 @@ namespace Umbraco.Web.PropertyEditors IContentTypeService contentTypeService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, - ILocalizedTextService localizedTextService) - : base (loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + ILocalizedTextService localizedTextService, + IJsonSerializer jsonSerializer) + : base (loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _propertyEditors = propertyEditors; _contentTypeService = contentTypeService; @@ -62,7 +64,7 @@ namespace Umbraco.Web.PropertyEditors #region Value Editor - protected override IDataValueEditor CreateValueEditor() => new NestedContentPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, _contentTypeService, ShortStringHelper, Attribute, PropertyEditors, LoggerFactory.CreateLogger()); + protected override IDataValueEditor CreateValueEditor() => new NestedContentPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, _contentTypeService, ShortStringHelper, Attribute, PropertyEditors, LoggerFactory.CreateLogger(), JsonSerializer); internal class NestedContentPropertyValueEditor : DataValueEditor, IDataValueReference { @@ -82,8 +84,9 @@ namespace Umbraco.Web.PropertyEditors IShortStringHelper shortStringHelper, DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, - ILogger logger) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + ILogger logger, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _propertyEditors = propertyEditors; _contentTypeService = contentTypeService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs index 6a863b1dd1..444e99bd23 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -30,8 +31,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 049f020db4..e97b8c0520 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Examine; @@ -50,8 +51,9 @@ namespace Umbraco.Web.PropertyEditors IShortStringHelper shortStringHelper, IIOHelper ioHelper, ILocalizedTextService localizedTextService, - IImageUrlGenerator imageUrlGenerator) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IImageUrlGenerator imageUrlGenerator, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; @@ -65,7 +67,7 @@ namespace Umbraco.Web.PropertyEditors /// Create a custom value editor /// /// - protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator); + protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator, JsonSerializer); protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor(_ioHelper); @@ -92,8 +94,9 @@ namespace Umbraco.Web.PropertyEditors HtmlImageSourceParser imageSourceParser, HtmlLocalLinkParser localLinkParser, RichTextEditorPastedImages pastedImages, - IImageUrlGenerator imageUrlGenerator) - : base(dataTypeService, localizationService,localizedTextService, shortStringHelper, attribute) + IImageUrlGenerator imageUrlGenerator, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer, attribute) { _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs index bb62c3461d..48197691a2 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -28,8 +29,9 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs index 708f4d8c9f..a2fb340d14 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs @@ -8,6 +8,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -34,21 +35,22 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _validators = validators; _ioHelper = ioHelper; } - protected override IDataValueEditor CreateValueEditor() => new TagPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new TagPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer, Attribute); protected override IConfigurationEditor CreateConfigurationEditor() => new TagConfigurationEditor(_validators, _ioHelper, LocalizedTextService); internal class TagPropertyValueEditor : DataValueEditor { - public TagPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) - : base(dataTypeService, localizationService,localizedTextService, shortStringHelper, attribute) + public TagPropertyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer, DataEditorAttribute attribute) + : base(dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer, attribute) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs index 8d173e58bc..d65f6f3a1d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -28,8 +29,15 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TextAreaPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService,shortStringHelper) + public TextAreaPropertyEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IIOHelper ioHelper, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -39,7 +47,7 @@ namespace Umbraco.Web.PropertyEditors } /// - protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor(_dataTypeService, _localizationService, Attribute, _localizedTextService, _shortStringHelper); + protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor(_dataTypeService, _localizationService, Attribute, _localizedTextService, _shortStringHelper, JsonSerializer); /// protected override IConfigurationEditor CreateConfigurationEditor() => new TextAreaConfigurationEditor(_ioHelper); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs index 1ec87abe9b..350dd4a1ff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -27,8 +28,15 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TextboxPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public TextboxPropertyEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + ILocalizedTextService localizedTextService, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper, jsonSerializer) { _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -38,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors } /// - protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor(_dataTypeService, _localizationService, Attribute, _localizedTextService, _shortStringHelper); + protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor(DataTypeService, LocalizationService, Attribute, LocalizedTextService, ShortStringHelper, JsonSerializer); /// protected override IConfigurationEditor CreateConfigurationEditor() => new TextboxConfigurationEditor(_ioHelper); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs index db72887fff..3c9599c643 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs @@ -2,6 +2,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,8 +26,15 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TrueFalsePropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public TrueFalsePropertyEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + ILocalizedTextService localizedTextService, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs index f46c118174..f35f9b9469 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -103,8 +103,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters if (settingGuidUdi != null) settingsPublishedElements.TryGetValue(settingGuidUdi.Guid, out settingsData); - if (!contentData.ContentType.TryGetKey(out var contentTypeKey)) - throw new InvalidOperationException("The content type was not of type " + typeof(IPublishedContentType2)); + var contentTypeKey = contentData.ContentType.Key; if (!blockConfigMap.TryGetValue(contentTypeKey, out var blockConfig)) continue; @@ -113,8 +112,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters // we also ensure that the content type's match since maybe the settings type has been changed after this has been persisted. if (settingsData != null) { - if (!settingsData.ContentType.TryGetKey(out var settingsElementTypeKey)) - throw new InvalidOperationException("The settings element type was not of type " + typeof(IPublishedContentType2)); + var settingsElementTypeKey = settingsData.ContentType.Key; if (!blockConfig.SettingsElementTypeKey.HasValue || settingsElementTypeKey != blockConfig.SettingsElementTypeKey) settingsData = null; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 7fe202ed4c..d0713b46ff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Text; using HtmlAgilityPack; using Umbraco.Core; @@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters /// used dynamically. /// [DefaultPropertyValueConverter] - public class RteMacroRenderingValueConverter : TinyMceValueConverter + public class RteMacroRenderingValueConverter : SimpleTinyMceValueConverter { private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IMacroRenderer _macroRenderer; diff --git a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs index 4c1482c82c..ae99243a2c 100644 --- a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs +++ b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -190,8 +190,7 @@ namespace Umbraco.Web.PublishedCache try { _lock.EnterWriteLock(); - if (type.TryGetKey(out var key)) - _keyToIdMap[key] = type.Id; + _keyToIdMap[type.Key] = type.Id; return _typesByAlias[aliasKey] = _typesById[type.Id] = type; } finally @@ -227,8 +226,7 @@ namespace Umbraco.Web.PublishedCache try { _lock.EnterWriteLock(); - if (type.TryGetKey(out var key)) - _keyToIdMap[key] = type.Id; + _keyToIdMap[type.Key] = type.Id; return _typesByAlias[GetAliasKey(type)] = _typesById[type.Id] = type; } finally diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs deleted file mode 100644 index dc71c475d1..0000000000 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ /dev/null @@ -1,387 +0,0 @@ -using System; -using Examine; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Grid; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Dashboards; -using Umbraco.Core.Dictionary; -using Umbraco.Core.Events; -using Umbraco.Core.Hosting; -using Umbraco.Core.Install; -using Umbraco.Core.Logging; -using Umbraco.Core.Manifest; -using Umbraco.Core.Media; -using Umbraco.Core.Migrations; -using Umbraco.Core.Migrations.Install; -using Umbraco.Core.Migrations.PostMigrations; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Persistence; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.PropertyEditors.Validators; -using Umbraco.Core.PropertyEditors.ValueConverters; -using Umbraco.Core.Scoping; -using Umbraco.Core.Serialization; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using Umbraco.Core.Strings; -using Umbraco.Core.Sync; -using Umbraco.Core.Templates; -using Umbraco.Examine; -using Umbraco.Infrastructure.Examine; -using Umbraco.Infrastructure.Media; -using Umbraco.Web; -using Umbraco.Web.Actions; -using Umbraco.Web.Cache; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Editors; -using Umbraco.Web.Features; -using Umbraco.Web.HealthCheck; -using Umbraco.Web.HealthCheck.NotificationMethods; -using Umbraco.Web.Install; -using Umbraco.Web.Media; -using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Migrations.PostMigrations; -using Umbraco.Web.Models.PublishedContent; -using Umbraco.Web.PropertyEditors; -using Umbraco.Web.PropertyEditors.ValueConverters; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Search; -using Umbraco.Web.Sections; -using Umbraco.Web.Services; -using Umbraco.Web.Templates; -using Umbraco.Web.Trees; -using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; -using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; -using Microsoft.Extensions.Logging; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Configuration.HealthChecks; -using Umbraco.Core.HealthCheck; -using Umbraco.Core.HealthCheck.Checks; -using Umbraco.Core.Security; - -namespace Umbraco.Core.Runtime -{ - // core's initial composer composes before all core composers - [ComposeBefore(typeof(ICoreComposer))] - public class CoreInitialComposer : ComponentComposer - { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - // composers - builder - .ComposeRepositories() - .ComposeServices() - .ComposeCoreMappingProfiles() - .ComposeFileSystems(); - - // register persistence mappers - required by database factory so needs to be done here - // means the only place the collection can be modified is in a runtime - afterwards it - // has been frozen and it is too late - builder.Mappers().AddCoreMappers(); - - // register the scope provider - builder.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor - builder.Services.AddUnique(f => f.GetRequiredService()); - builder.Services.AddUnique(f => f.GetRequiredService()); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // register database builder - // *not* a singleton, don't want to keep it around - builder.Services.AddTransient(); - - // register manifest parser, will be injected in collection builders where needed - builder.Services.AddUnique(); - - // register our predefined validators - builder.ManifestValueValidators() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add(); - - // register the manifest filter collection builder (collection is empty by default) - builder.ManifestFilters(); - - // properties and parameters derive from data editors - builder.DataEditors() - .Add(() => builder.TypeLoader.GetDataEditors()); - - builder.MediaUrlGenerators() - .Add() - .Add(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Used to determine if a datatype/editor should be storing/tracking - // references to media item/s - builder.DataValueReferenceFactories(); - - // register a server registrar, by default it's the db registrar - builder.Services.AddUnique(f => - { - var globalSettings = f.GetRequiredService>().Value; - - // TODO: we still register the full IServerMessenger because - // even on 1 single server we can have 2 concurrent app domains - var singleServer = globalSettings.DisableElectionForSingleServer; - return singleServer - ? (IServerRegistrar) new SingleServerRegistrar(f.GetRequiredService()) - : new DatabaseServerRegistrar( - new Lazy(f.GetRequiredService)); - }); - - // by default we'll use the database server messenger with default options (no callbacks), - // this will be overridden by the db thing in the corresponding components in the web - // project - builder.Services.AddUnique(factory - => new DatabaseServerMessenger( - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService>(), - factory.GetRequiredService(), - true, - new DatabaseServerMessengerCallbacks(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService>() - )); - - builder.CacheRefreshers() - .Add(() => builder.TypeLoader.GetCacheRefreshers()); - - builder.PackageActions() - .Add(() => builder.TypeLoader.GetPackageActions()); - - builder.PropertyValueConverters() - .Append(builder.TypeLoader.GetTypes()); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(factory - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); - - builder.UrlSegmentProviders() - .Append(); - - builder.Services.AddUnique(factory => new MigrationBuilder(factory)); - - // by default, register a noop factory - builder.Services.AddUnique(); - - // by default - builder.Services.AddUnique(); - - builder.SetCultureDictionaryFactory(); - builder.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); - builder.Services.AddUnique(); - - // register the published snapshot accessor - the "current" published snapshot is in the umbraco context - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards - builder.Dashboards() - .Add(builder.TypeLoader.GetTypes()); - - // will be injected in controllers when needed to invoke rest endpoints on Our - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Grid config is not a real config file as we know them - builder.Services.AddUnique(); - - // Config manipulator - builder.Services.AddUnique(); - - // register the umbraco context factory - // composition.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be - // discovered when CoreBootManager configures the converters. We HAVE to remove one of them - // here because there cannot be two converters for one property editor - and we want the full - // RteMacroRenderingValueConverter that converts macros, etc. So remove TinyMceValueConverter. - // (the limited one, defined in Core, is there for tests) - same for others - builder.PropertyValueConverters() - .Remove() - .Remove() - .Remove(); - - builder.UrlProviders() - .Append() - .Append(); - - builder.MediaUrlProviders() - .Append(); - - builder.Services.AddUnique(); - - // register properties fallback - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Actions() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.EditorValidators() - .Add(() => builder.TypeLoader.GetTypes()); - - - builder.TourFilters(); - - // replace with web implementation - builder.Services.AddUnique(); - - // register OEmbed providers - no type scanning - all explicit opt-in of adding types - // note: IEmbedProvider is not IDiscoverable - think about it if going for type scanning - builder.OEmbedProviders() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - // register back office sections in the order we want them rendered - builder.Sections() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - // register known content apps - builder.ContentApps() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - // register published router - builder.Services.AddUnique(); - - // register *all* checks, except those marked [HideFromTypeFinder] of course - builder.HealthChecks() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.WithCollectionBuilder() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.Services.AddUnique(); - - builder.ContentFinders() - // all built-in finders in the correct order, - // devs can then modify this list on application startup - .Append() - .Append() - .Append() - //.Append() // disabled, this is an odd finder - .Append() - .Append(); - - builder.Services.AddScoped(); - - builder.SearchableTrees() - .Add(() => builder.TypeLoader.GetTypes()); - - // replace some services - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - // register distributed cache - builder.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); - - - builder.Services.AddScoped(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddScoped(factory => - { - var umbCtx = factory.GetRequiredService(); - return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); - }); - - builder.Services.AddUnique(); - - // register the http context and umbraco context accessors - // we *should* use the HttpContextUmbracoContextAccessor, however there are cases when - // we have no http context, eg when booting Umbraco or in background threads, so instead - // let's use an hybrid accessor that can fall back to a ThreadStatic context. - builder.Services.AddUnique(); - - // register accessors for cultures - builder.Services.AddUnique(); - - builder.Services.AddSingleton(); - - builder.Services.AddUnique(); - - // Register noop versions for examine to be overridden by examine - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(factory => new LegacyPasswordSecurity()); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index cb02a90ebe..a05c1a7f98 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -1,7 +1,10 @@ -using System; +using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -10,71 +13,103 @@ namespace Umbraco.Infrastructure.Runtime { public class CoreRuntime : IRuntime { - public IRuntimeState State { get; } - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly ComponentCollection _components; private readonly IApplicationShutdownRegistry _applicationShutdownRegistry; private readonly IProfilingLogger _profilingLogger; private readonly IMainDom _mainDom; private readonly IUmbracoDatabaseFactory _databaseFactory; + private readonly IEventAggregator _eventAggregator; + private readonly IHostingEnvironment _hostingEnvironment; + /// + /// Initializes a new instance of the class. + /// public CoreRuntime( - ILogger logger, + ILoggerFactory loggerFactory, IRuntimeState state, ComponentCollection components, IApplicationShutdownRegistry applicationShutdownRegistry, IProfilingLogger profilingLogger, IMainDom mainDom, - IUmbracoDatabaseFactory databaseFactory) + IUmbracoDatabaseFactory databaseFactory, + IEventAggregator eventAggregator, + IHostingEnvironment hostingEnvironment) { State = state; - _logger = logger; + _loggerFactory = loggerFactory; _components = components; _applicationShutdownRegistry = applicationShutdownRegistry; _profilingLogger = profilingLogger; _mainDom = mainDom; _databaseFactory = databaseFactory; + _eventAggregator = eventAggregator; + _hostingEnvironment = hostingEnvironment; + _logger = _loggerFactory.CreateLogger(); } - - public void Start() + /// + /// Gets the state of the Umbraco runtime. + /// + public IRuntimeState State { get; } + + /// + public async Task StartAsync(CancellationToken cancellationToken) { + StaticApplicationLogging.Initialize(_loggerFactory); + AppDomain.CurrentDomain.UnhandledException += (_, args) => { var exception = (Exception)args.ExceptionObject; var isTerminating = args.IsTerminating; // always true? var msg = "Unhandled exception in AppDomain"; - if (isTerminating) msg += " (terminating)"; + + if (isTerminating) + { + msg += " (terminating)"; + } + msg += "."; + _logger.LogError(exception, msg); }; + AppDomain.CurrentDomain.SetData("DataDirectory", _hostingEnvironment?.MapPathContentRoot(Core.Constants.SystemDirectories.Data)); + DetermineRuntimeLevel(); if (State.Level <= RuntimeLevel.BootFailed) + { throw new InvalidOperationException($"Cannot start the runtime if the runtime level is less than or equal to {RuntimeLevel.BootFailed}"); + } - var hostingEnvironmentLifetime = _applicationShutdownRegistry; + IApplicationShutdownRegistry hostingEnvironmentLifetime = _applicationShutdownRegistry; if (hostingEnvironmentLifetime == null) - throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(Start)}"); + { + throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(StartAsync)}"); + } // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate AcquireMainDom(); + await _eventAggregator.PublishAsync(new UmbracoApplicationStarting(State.Level), cancellationToken); + // create & initialize the components _components.Initialize(); } - public void Terminate() + public async Task StopAsync(CancellationToken cancellationToken) { _components.Terminate(); + await _eventAggregator.PublishAsync(new UmbracoApplicationStopping(), cancellationToken); + StaticApplicationLogging.Initialize(null); } private void AcquireMainDom() { - using (var timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.")) + using (DisposableTimer timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.")) { try { @@ -90,7 +125,7 @@ namespace Umbraco.Infrastructure.Runtime private void DetermineRuntimeLevel() { - using var timer = _profilingLogger.DebugDuration("Determining runtime level.", "Determined."); + using DisposableTimer timer = _profilingLogger.DebugDuration("Determining runtime level.", "Determined."); try { diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 41bdaa9e01..c73a817327 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -7,7 +7,7 @@ using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Umbraco.Core.Configuration; +using NPoco; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Persistence; @@ -42,7 +42,7 @@ namespace Umbraco.Core.Runtime loggerFactory, globalSettings, connectionStrings, - new Lazy(() => new MapperCollection(Enumerable.Empty())), + new Lazy(() => new Persistence.Mappers.MapperCollection(Enumerable.Empty())), dbProviderFactoryCreator); MainDomKey = MainDomKeyPrefix + "-" + (NetworkHelper.MachineName + MainDom.GetMainDomId(_hostingEnvironment)).GenerateHash(); @@ -57,7 +57,9 @@ namespace Umbraco.Core.Runtime } if (!(_dbFactory.SqlContext.SqlSyntax is SqlServerSyntaxProvider sqlServerSyntaxProvider)) + { throw new NotSupportedException("SqlMainDomLock is only supported for Sql Server"); + } _sqlServerSyntax = sqlServerSyntaxProvider; @@ -65,11 +67,13 @@ namespace Umbraco.Core.Runtime var tempId = Guid.NewGuid().ToString(); - using var db = _dbFactory.CreateDatabase(); - using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); + IUmbracoDatabase db = null; try { + db = _dbFactory.CreateDatabase(); + db.BeginTransaction(IsolationLevel.ReadCommitted); + try { // wait to get a write lock @@ -110,7 +114,8 @@ namespace Umbraco.Core.Runtime } finally { - transaction.Complete(); + db?.CompleteTransaction(); + db?.Dispose(); } @@ -172,11 +177,11 @@ namespace Umbraco.Core.Runtime return; } - - using var db = _dbFactory.CreateDatabase(); - using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); + IUmbracoDatabase db = null; try { + db = _dbFactory.CreateDatabase(); + db.BeginTransaction(IsolationLevel.ReadCommitted); // get a read lock _sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom); @@ -202,7 +207,8 @@ namespace Umbraco.Core.Runtime } finally { - transaction.Complete(); + db?.CompleteTransaction(); + db?.Dispose(); } } @@ -221,34 +227,47 @@ namespace Umbraco.Core.Runtime return Task.Run(() => { - using var db = _dbFactory.CreateDatabase(); - - var watch = new Stopwatch(); - watch.Start(); - while (true) + try { - // poll very often, we need to take over as fast as we can - // local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO - Thread.Sleep(1000); + using var db = _dbFactory.CreateDatabase(); - var acquired = TryAcquire(db, tempId, updatedTempId); - if (acquired.HasValue) - return acquired.Value; - - if (watch.ElapsedMilliseconds >= millisecondsTimeout) + var watch = new Stopwatch(); + watch.Start(); + while (true) { - return AcquireWhenMaxWaitTimeElapsed(db); + // poll very often, we need to take over as fast as we can + // local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO + Thread.Sleep(1000); + + var acquired = TryAcquire(db, tempId, updatedTempId); + if (acquired.HasValue) + return acquired.Value; + + if (watch.ElapsedMilliseconds >= millisecondsTimeout) + { + return AcquireWhenMaxWaitTimeElapsed(db); + } } } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred trying to acquire and waiting for existing SqlMainDomLock to shutdown"); + return false; + } + }, _cancellationTokenSource.Token); } private bool? TryAcquire(IUmbracoDatabase db, string tempId, string updatedTempId) { - using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); + // Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction + // since this is executed in a tight loop + + ITransaction transaction = null; try { + transaction = db.GetTransaction(IsolationLevel.ReadCommitted); // get a read lock _sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom); @@ -294,7 +313,8 @@ namespace Umbraco.Core.Runtime } finally { - transaction.Complete(); + transaction?.Complete(); + transaction?.Dispose(); } return null; // continue @@ -302,6 +322,9 @@ namespace Umbraco.Core.Runtime private bool AcquireWhenMaxWaitTimeElapsed(IUmbracoDatabase db) { + // Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction + // since this is executed in a tight loop + // if the timeout has elapsed, it either means that the other main dom is taking too long to shutdown, // or it could mean that the previous appdomain was terminated and didn't clear out the main dom SQL row // and it's just been left as an orphan row. @@ -311,10 +334,12 @@ namespace Umbraco.Core.Runtime _logger.LogDebug("Timeout elapsed, assuming orphan row, acquiring MainDom."); - using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); + ITransaction transaction = null; try { + transaction = db.GetTransaction(IsolationLevel.ReadCommitted); + _sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom); // so now we update the row with our appdomain id @@ -337,7 +362,8 @@ namespace Umbraco.Core.Runtime } finally { - transaction.Complete(); + transaction?.Complete(); + transaction?.Dispose(); } } @@ -390,11 +416,12 @@ namespace Umbraco.Core.Runtime if (_dbFactory.Configured) { - using var db = _dbFactory.CreateDatabase(); - using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); - + IUmbracoDatabase db = null; try { + db = _dbFactory.CreateDatabase(); + db.BeginTransaction(IsolationLevel.ReadCommitted); + // get a write lock _sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom); @@ -421,7 +448,15 @@ namespace Umbraco.Core.Runtime } finally { - transaction.Complete(); + try + { + db?.CompleteTransaction(); + db?.Dispose(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Unexpected error during dispose when completing transaction."); + } } } } diff --git a/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs index dce6658f16..712b90affa 100644 --- a/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; using Umbraco.Core.Events; using Umbraco.Core.Persistence; @@ -13,7 +13,7 @@ namespace Umbraco.Core.Scoping /// Provides scopes. /// public interface IScopeProvider - { + { /// /// Creates an ambient scope. /// diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 65e8e343f7..84945c78d4 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; @@ -20,7 +20,6 @@ namespace Umbraco.Core.Scoping private readonly CoreDebugSettings _coreDebugSettings; private readonly IMediaFileSystem _mediaFileSystem; private readonly ILogger _logger; - private readonly ITypeFinder _typeFinder; private readonly IsolationLevel _isolationLevel; private readonly RepositoryCacheMode _repositoryCacheMode; @@ -38,10 +37,15 @@ namespace Umbraco.Core.Scoping private IEventDispatcher _eventDispatcher; // initializes a new scope - private Scope(ScopeProvider scopeProvider, + private Scope( + ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, - ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IScopeContext scopeContext, bool detachable, + ILogger logger, + FileSystems fileSystems, + Scope parent, + IScopeContext scopeContext, + bool detachable, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, @@ -53,7 +57,6 @@ namespace Umbraco.Core.Scoping _coreDebugSettings = coreDebugSettings; _mediaFileSystem = mediaFileSystem; _logger = logger; - _typeFinder = typeFinder; Context = scopeContext; @@ -117,31 +120,38 @@ namespace Umbraco.Core.Scoping } // initializes a new scope - public Scope(ScopeProvider scopeProvider, + public Scope( + ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, - ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, bool detachable, IScopeContext scopeContext, + ILogger logger, + FileSystems fileSystems, + bool detachable, + IScopeContext scopeContext, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, typeFinder, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } // initializes a new scope in a nested scopes chain, with its parent - public Scope(ScopeProvider scopeProvider, + public Scope( + ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, - ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, + ILogger logger, + FileSystems fileSystems, + Scope parent, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, typeFinder, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileSystem, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } public Guid InstanceId { get; } = Guid.NewGuid(); diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 52c096b224..151c4cfb3c 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -23,13 +23,12 @@ namespace Umbraco.Core.Scoping { private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; - private readonly ITypeFinder _typeFinder; private readonly IRequestCache _requestCache; private readonly FileSystems _fileSystems; private readonly CoreDebugSettings _coreDebugSettings; private readonly IMediaFileSystem _mediaFileSystem; - public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, IOptions coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ILoggerFactory loggerFactory, ITypeFinder typeFinder, IRequestCache requestCache) + public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, IOptions coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ILoggerFactory loggerFactory, IRequestCache requestCache) { DatabaseFactory = databaseFactory; _fileSystems = fileSystems; @@ -37,7 +36,6 @@ namespace Umbraco.Core.Scoping _mediaFileSystem = mediaFileSystem; _logger = logger; _loggerFactory = loggerFactory; - _typeFinder = typeFinder; _requestCache = requestCache; // take control of the FileSystems _fileSystems.IsScoped = () => AmbientScope != null && AmbientScope.ScopedFileSystems; @@ -256,7 +254,7 @@ namespace Umbraco.Core.Scoping IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null) { - return new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); + return new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); } /// @@ -312,13 +310,13 @@ namespace Umbraco.Core.Scoping { var ambientContext = AmbientContext; var newContext = ambientContext == null ? new ScopeContext() : null; - var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! SetAmbient(scope, newContext ?? ambientContext); return scope; } - var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); SetAmbient(nested, AmbientContext); return nested; } diff --git a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs index 683ed48ecd..c961aa6e72 100644 --- a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs +++ b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Models; diff --git a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs index ecaf7354ca..a2955dfef5 100644 --- a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs @@ -8,11 +8,11 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Examine; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; -using Umbraco.Web.Trees; namespace Umbraco.Web.Search { diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs index 120c0500e2..69dadb2b21 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; @@ -387,6 +386,16 @@ namespace Umbraco.Core.Services.Implement } } + /// + /// + /// + /// + /// + /// + /// + Attempt IContentServiceBase.Save(IEnumerable contents, int userId, + bool raiseEvents) => Attempt.Succeed(Save(contents, userId, raiseEvents)); + /// /// Gets objects by Ids /// diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs index 3241fa9d0e..be541486ff 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Scoping; @@ -16,10 +16,23 @@ namespace Umbraco.Core.Services.Implement protected abstract TService This { get; } - // that one must be dispatched + /// + /// Raised when a is changed + /// + /// + /// This event is dispatched after the trans is completed. Used by event refreshers. + /// public static event TypedEventHandler.EventArgs> Changed; - // that one is always immediate (transactional) + /// + /// Occurs when an is created or updated from within the (transaction) + /// + /// + /// The purpose of this event being raised within the transaction is so that listeners can perform database + /// operations from within the same transaction and guarantee data consistency so that if anything goes wrong + /// the entire transaction can be rolled back. This is used by Nucache. + /// TODO: See remarks in ContentRepositoryBase about these types of events. + /// public static event TypedEventHandler.EventArgs> ScopedRefreshedEntity; // used by tests to clear events @@ -45,9 +58,11 @@ namespace Umbraco.Core.Services.Implement scope.Events.Dispatch(Changed, This, args, nameof(Changed)); } + /// + /// Raises the event during the (transaction) + /// protected void OnUowRefreshedEntity(ContentTypeChange.EventArgs args) { - // that one is always immediate (not dispatched, transactional) ScopedRefreshedEntity.RaiseEvent(args, This); } diff --git a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs index eb6a94c4ee..042128558b 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs @@ -6,11 +6,11 @@ using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Strings; namespace Umbraco.Core.Services.Implement @@ -29,11 +29,14 @@ namespace Umbraco.Core.Services.Implement private readonly ILocalizedTextService _localizedTextService; private readonly ILocalizationService _localizationService; private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; public DataTypeService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDataTypeRepository dataTypeRepository, IDataTypeContainerRepository dataTypeContainerRepository, IAuditRepository auditRepository, IEntityRepository entityRepository, IContentTypeRepository contentTypeRepository, - IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) + IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) : base(provider, loggerFactory, eventMessagesFactory) { _dataTypeRepository = dataTypeRepository; @@ -45,6 +48,7 @@ namespace Umbraco.Core.Services.Implement _localizedTextService = localizedTextService; _localizationService = localizationService; _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; } #region Containers @@ -324,7 +328,7 @@ namespace Umbraco.Core.Services.Implement .Where(x => x.Editor is MissingPropertyEditor); foreach (var dataType in dataTypesWithMissingEditors) { - dataType.Editor = new LabelPropertyEditor(LoggerFactory, _ioHelper, this, _localizedTextService, _localizationService, _shortStringHelper); + dataType.Editor = new LabelPropertyEditor(LoggerFactory, _ioHelper, this, _localizedTextService, _localizationService, _shortStringHelper, _jsonSerializer); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs index 479e5cc4d8..c33265c987 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs @@ -4,8 +4,6 @@ using System.Globalization; using System.Linq; using System.Net; using System.Xml.Linq; -using Newtonsoft.Json; -using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; @@ -120,6 +118,7 @@ namespace Umbraco.Core.Services.Implement //xml.Add(new XAttribute("creatorID", media.CreatorId)); xml.Add(new XAttribute("writerName", media.GetWriterProfile(_userService)?.Name ?? string.Empty)); xml.Add(new XAttribute("writerID", media.WriterId)); + xml.Add(new XAttribute("udi", media.GetUdi())); //xml.Add(new XAttribute("template", 0)); // no template for media @@ -335,6 +334,7 @@ namespace Umbraco.Core.Services.Implement return xml; } + public XElement Serialize(IMediaType mediaType) { var info = new XElement("Info", @@ -375,7 +375,7 @@ namespace Umbraco.Core.Services.Implement new XElement("Validation", propertyType.ValidationRegExp), new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage), new XElement("LabelOnTop", propertyType.LabelOnTop), - new XElement("Description", new XCData(propertyType.Description))); + new XElement("Description", new XCData(propertyType.Description ?? string.Empty))); genericProperties.Add(genericProperty); } @@ -498,7 +498,7 @@ namespace Umbraco.Core.Services.Implement new XElement("Alias", propertyType.Alias), new XElement("Key", propertyType.Key), new XElement("Type", propertyType.PropertyEditorAlias), - new XElement("Definition", definition.Key), + new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs index 0672c3218f..5d5d4b7bd1 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; @@ -8,7 +7,6 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -360,6 +358,8 @@ namespace Umbraco.Core.Services.Implement } } + + /// /// Gets an object by Id /// @@ -643,6 +643,8 @@ namespace Umbraco.Core.Services.Implement #region Save + + /// /// Saves a single object /// diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index 3e99ca9b4b..653a878ab9 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; +using Umbraco.Core.Mail; namespace Umbraco.Core.Services.Implement { diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 145bf54aaf..14197762c6 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -1,8 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; -using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.Models; @@ -26,11 +25,12 @@ namespace Umbraco.Core.Services.Implement /// /// Initializes a new instance of the class. /// - /// A UnitOfWork provider. - /// A logger factory - /// - public ServerRegistrationService(IScopeProvider scopeProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, - IServerRegistrationRepository serverRegistrationRepository, IHostingEnvironment hostingEnvironment) + public ServerRegistrationService( + IScopeProvider scopeProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IServerRegistrationRepository serverRegistrationRepository, + IHostingEnvironment hostingEnvironment) : base(scopeProvider, loggerFactory, eventMessagesFactory) { _serverRegistrationRepository = serverRegistrationRepository; @@ -41,10 +41,10 @@ namespace Umbraco.Core.Services.Implement /// Touches a server to mark it as active; deactivate stale servers. /// /// The server URL. - /// The server unique identity. /// The time after which a server is considered stale. - public void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout) + public void TouchServer(string serverAddress, TimeSpan staleTimeout) { + var serverIdentity = GetCurrentServerIdentity(); using (var scope = ScopeProvider.CreateScope()) { scope.WriteLock(Constants.Locks.Servers); @@ -144,19 +144,16 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets the local server identity. - /// - public string CurrentServerIdentity => NetworkHelper.MachineName // eg DOMAIN\SERVER - + "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT; - /// /// Gets the role of the current server. /// /// The role of the current server. - public ServerRole GetCurrentServerRole() - { - return _currentServerRole; - } + public ServerRole GetCurrentServerRole() => _currentServerRole; + + /// + /// Gets the local server identity. + /// + private string GetCurrentServerIdentity() => NetworkHelper.MachineName // eg DOMAIN\SERVER + + "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT; } } diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs similarity index 58% rename from src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs rename to src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs index 187eced6e4..d1a9481f47 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs @@ -1,104 +1,83 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; -using Umbraco.Core.Sync; -using Umbraco.Web.Routing; +using Umbraco.Web; -namespace Umbraco.Web +namespace Umbraco.Core.Sync { /// /// An implementation that works by storing messages in the database. /// - /// - /// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls - /// - public class BatchedDatabaseServerMessenger : DatabaseServerMessenger, IBatchedDatabaseServerMessenger + public class BatchedDatabaseServerMessenger : DatabaseServerMessenger { - private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IRequestCache _requestCache; private readonly IRequestAccessor _requestAccessor; + /// + /// Initializes a new instance of the class. + /// public BatchedDatabaseServerMessenger( IMainDom mainDom, - IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, IProfilingLogger proflog, ILogger logger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IRequestCache requestCache, IRequestAccessor requestAccessor, IOptions globalSettings) - : base(mainDom, scopeProvider, databaseFactory, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings) + : base(mainDom, scopeProvider, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings) { - _databaseFactory = databaseFactory; _requestCache = requestCache; _requestAccessor = requestAccessor; } - // invoked by DatabaseServerRegistrarAndMessengerComponent - public void Startup() - { - _requestAccessor.EndRequest += UmbracoModule_EndRequest; - - if (_databaseFactory.CanConnect == false) - { - Logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server."); - } - else - { - Boot(); - } - } - - private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e) - { - // will clear the batch - will remain in HttpContext though - that's ok - FlushBatch(); - } - + /// protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { var idsA = ids?.ToArray(); - Type arrayType; - if (GetArrayType(idsA, out arrayType) == false) + if (GetArrayType(idsA, out Type arrayType) == false) + { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); + } BatchMessage(refresher, messageType, idsA, arrayType, json); } - public void FlushBatch() + /// + public override void SendMessages() { - var batch = GetBatch(false); - if (batch == null) return; + ICollection batch = GetBatch(false); + if (batch == null) + { + return; + } - var instructions = batch.SelectMany(x => x.Instructions).ToArray(); + RefreshInstruction[] instructions = batch.SelectMany(x => x.Instructions).ToArray(); batch.Clear(); - //Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount - using (var scope = ScopeProvider.CreateScope()) + // Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount + using (IScope scope = ScopeProvider.CreateScope()) { - foreach (var instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) + foreach (IEnumerable instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) { WriteInstructions(scope, instructionsBatch); } + scope.Complete(); } - } private void WriteInstructions(IScope scope, IEnumerable instructions) @@ -113,11 +92,14 @@ namespace Umbraco.Web scope.Database.Insert(dto); } - protected ICollection GetBatch(bool create) + private ICollection GetBatch(bool create) { var key = nameof(BatchedDatabaseServerMessenger); - if (!_requestCache.IsAvailable) return null; + if (!_requestCache.IsAvailable) + { + return null; + } // no thread-safety here because it'll run in only 1 thread (request) at a time var batch = (ICollection)_requestCache.Get(key); @@ -130,26 +112,27 @@ namespace Umbraco.Web return batch; } - protected void BatchMessage( + private void BatchMessage( ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, Type idType = null, string json = null) { - var batch = GetBatch(true); - var instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json); + ICollection batch = GetBatch(true); + IEnumerable instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json); // batch if we can, else write to DB immediately if (batch == null) { - //only write the json blob with a maximum count of the MaxProcessingInstructionCount - using (var scope = ScopeProvider.CreateScope()) + // only write the json blob with a maximum count of the MaxProcessingInstructionCount + using (IScope scope = ScopeProvider.CreateScope()) { - foreach (var maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) + foreach (IEnumerable maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) { WriteInstructions(scope, maxBatch); } + scope.Complete(); } } diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 856772148f..09c90461ac 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -23,19 +23,21 @@ namespace Umbraco.Core.Sync /// /// An that works by storing messages in the database. /// - // - // this messenger writes ALL instructions to the database, - // but only processes instructions coming from remote servers, - // thus ensuring that instructions run only once - // - public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger + public abstract class DatabaseServerMessenger : ServerMessengerBase { + // TODO: This class needs to be split into a service/repo for DB access + + /* + * this messenger writes ALL instructions to the database, + * but only processes instructions coming from remote servers, + * thus ensuring that instructions run only once + */ + private readonly IMainDom _mainDom; - private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; private readonly ManualResetEvent _syncIdle; private readonly object _locko = new object(); private readonly IProfilingLogger _profilingLogger; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IHostingEnvironment _hostingEnvironment; private readonly CacheRefresherCollection _cacheRefreshers; @@ -43,22 +45,28 @@ namespace Umbraco.Core.Sync private int _lastId = -1; private DateTime _lastSync; private DateTime _lastPruned; - private bool _initialized; + private readonly Lazy _initialized; private bool _syncing; private bool _released; - public DatabaseServerMessengerCallbacks Callbacks { get; } - - public GlobalSettings GlobalSettings { get; } - - public DatabaseServerMessenger( - IMainDom mainDom, IScopeProvider scopeProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, IProfilingLogger proflog, ILogger logger, IServerRegistrar serverRegistrar, - bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IOptions globalSettings) + /// + /// Initializes a new instance of the class. + /// + protected DatabaseServerMessenger( + IMainDom mainDom, + IScopeProvider scopeProvider, + IProfilingLogger proflog, + ILogger logger, + IServerRoleAccessor serverRegistrar, + bool distributedEnabled, + DatabaseServerMessengerCallbacks callbacks, + IHostingEnvironment hostingEnvironment, + CacheRefresherCollection cacheRefreshers, + IOptions globalSettings) : base(distributedEnabled) { ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); _mainDom = mainDom; - _umbracoDatabaseFactory = umbracoDatabaseFactory; _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); _serverRegistrar = serverRegistrar; _hostingEnvironment = hostingEnvironment; @@ -76,24 +84,28 @@ namespace Umbraco.Core.Sync + " [P" + Process.GetCurrentProcess().Id // eg 1234 + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique + + _initialized = new Lazy(EnsureInitialized); } + public DatabaseServerMessengerCallbacks Callbacks { get; } + + public GlobalSettings GlobalSettings { get; } + protected ILogger Logger { get; } protected IScopeProvider ScopeProvider { get; } - protected Sql Sql() => _umbracoDatabaseFactory.SqlContext.Sql(); + protected Sql Sql() => ScopeProvider.SqlContext.Sql(); private string DistCacheFilePath => _distCacheFilePath.Value; #region Messenger + // we don't care if there's servers listed or not, + // if distributed call is enabled we will make the call protected override bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType) - { - // we don't care if there's servers listed or not, - // if distributed call is enabled we will make the call - return _initialized && DistributedEnabled; - } + => _initialized.Value && DistributedEnabled; protected override void DeliverRemote( ICacheRefresher refresher, @@ -104,7 +116,9 @@ namespace Umbraco.Core.Sync var idsA = ids?.ToArray(); if (GetArrayType(idsA, out var idType) == false) + { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); + } var instructions = RefreshInstruction.GetInstructions(refresher, messageType, idsA, idType, json); @@ -130,17 +144,12 @@ namespace Umbraco.Core.Sync /// /// Boots the messenger. /// - /// - /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. - /// Callers MUST ensure thread-safety. - /// - protected void Boot() + private bool EnsureInitialized() { // weight:10, must release *before* the published snapshot service, because once released // the service will *not* be able to properly handle our notifications anymore const int weight = 10; - var registered = _mainDom.Register( () => { @@ -154,7 +163,7 @@ namespace Umbraco.Core.Sync // properly releasing MainDom - a timeout here means that one refresher // is taking too much time processing, however when it's done we will // not update lastId and stop everything - var idle =_syncIdle.WaitOne(5000); + var idle = _syncIdle.WaitOne(5000); if (idle == false) { Logger.LogWarning("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed."); @@ -163,15 +172,16 @@ namespace Umbraco.Core.Sync weight); if (registered == false) - return; + { + return false; + } ReadLastSynced(); // get _lastId - using (var scope = ScopeProvider.CreateScope()) + + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { EnsureInstructions(scope.Database); // reset _lastId if instructions are missing - Initialize(scope.Database); // boot - - scope.Complete(); + return Initialize(scope.Database); // boot } } @@ -182,14 +192,19 @@ namespace Umbraco.Core.Sync /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. /// Callers MUST ensure thread-safety. /// - private void Initialize(IUmbracoDatabase database) + private bool Initialize(IUmbracoDatabase database) { lock (_locko) { - if (_released) return; + if (_released) + { + return false; + } var coldboot = false; - if (_lastId < 0) // never synced before + + // never synced before + if (_lastId < 0) { // we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new // server and it will need to rebuild it's own caches, eg Lucene or the xml cache file. @@ -201,12 +216,12 @@ namespace Umbraco.Core.Sync } else { - //check for how many instructions there are to process, each row contains a count of the number of instructions contained in each - //row so we will sum these numbers to get the actual count. - var count = database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId}); + // check for how many instructions there are to process, each row contains a count of the number of instructions contained in each + // row so we will sum these numbers to get the actual count. + var count = database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId = _lastId }); if (count > GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount) { - //too many instructions, proceed to cold boot + // too many instructions, proceed to cold boot Logger.LogWarning( "The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})." + " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id" @@ -224,38 +239,55 @@ namespace Umbraco.Core.Sync // when doing it before, some instructions might run twice - not an issue var maxId = database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction"); - //if there is a max currently, or if we've never synced + // if there is a max currently, or if we've never synced if (maxId > 0 || _lastId < 0) + { SaveLastSynced(maxId); + } // execute initializing callbacks if (Callbacks.InitializingCallbacks != null) + { foreach (var callback in Callbacks.InitializingCallbacks) + { callback(); + } + } } - _initialized = true; + return true; } } /// /// Synchronize the server (throttled). /// - public void Sync() + public override void Sync() { + if (!_initialized.Value) + { + return; + } + lock (_locko) { if (_syncing) + { return; + } - //Don't continue if we are released + // Don't continue if we are released if (_released) + { return; + } if ((DateTime.UtcNow - _lastSync) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenSyncOperations) + { return; + } - //Set our flag and the lock to be in it's original state (i.e. it can be awaited) + // Set our flag and the lock to be in it's original state (i.e. it can be awaited) _syncing = true; _syncIdle.Reset(); _lastSync = DateTime.UtcNow; @@ -268,7 +300,7 @@ namespace Umbraco.Core.Sync { ProcessDatabaseInstructions(scope.Database); - //Check for pruning throttling + // Check for pruning throttling if (_released || (DateTime.UtcNow - _lastPruned) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenPruneOperations) { scope.Complete(); @@ -277,7 +309,7 @@ namespace Umbraco.Core.Sync _lastPruned = _lastSync; - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Single: case ServerRole.Master: @@ -292,7 +324,7 @@ namespace Umbraco.Core.Sync { lock (_locko) { - //We must reset our flag and signal any waiting locks + // We must reset our flag and signal any waiting locks _syncing = false; } @@ -306,9 +338,6 @@ namespace Umbraco.Core.Sync /// /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. /// - /// - /// Returns the number of processed instructions - /// private void ProcessDatabaseInstructions(IUmbracoDatabase database) { // NOTE @@ -324,7 +353,7 @@ namespace Umbraco.Core.Sync .Where(dto => dto.Id > _lastId) .OrderBy(dto => dto.Id); - //only retrieve the top 100 (just in case there's tons) + // only retrieve the top 100 (just in case there's tons) // even though MaxProcessingInstructionCount is by default 1000 we still don't want to process that many // rows in one request thread since each row can contain a ton of instructions (until 7.5.5 in which case // a row can only contain MaxProcessingInstructionCount) @@ -337,15 +366,15 @@ namespace Umbraco.Core.Sync var lastId = 0; - //tracks which ones have already been processed to avoid duplicates + // tracks which ones have already been processed to avoid duplicates var processed = new HashSet(); - //It would have been nice to do this in a Query instead of Fetch using a data reader to save + // It would have been nice to do this in a Query instead of Fetch using a data reader to save // some memory however we cannot do that because inside of this loop the cache refreshers are also // performing some lookups which cannot be done with an active reader open foreach (var dto in database.Fetch(topSql)) { - //If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot + // If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot // continue processing anything otherwise we'll hold up the app domain shutdown if (_released) { @@ -377,10 +406,10 @@ namespace Umbraco.Core.Sync var instructionBatch = GetAllInstructions(jsonA); - //process as per-normal + // process as per-normal var success = ProcessDatabaseInstructions(instructionBatch, dto, processed, ref lastId); - //if they couldn't be all processed (i.e. we're shutting down) then exit + // if they couldn't be all processed (i.e. we're shutting down) then exit if (success == false) { Logger.LogInformation("The current batch of instructions was not processed, app is shutting down"); @@ -425,11 +454,11 @@ namespace Umbraco.Core.Sync //} catch (Exception ex) { - Logger.LogError( - ex, - "DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored", - dto.Id, - dto.Instructions); + Logger.LogError( + ex, + "DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored", + dto.Id, + dto.Instructions); //we cannot throw here because this invalid instruction will just keep getting processed over and over and errors // will be thrown over and over. The only thing we can do is ignore and move on. @@ -509,7 +538,8 @@ namespace Umbraco.Core.Sync /// private void ReadLastSynced() { - if (File.Exists(DistCacheFilePath) == false) return; + if (File.Exists(DistCacheFilePath) == false) + return; var content = File.ReadAllText(DistCacheFilePath); if (int.TryParse(content, out var last)) diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs index f2918ffe96..dfba90291b 100644 --- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs +++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; @@ -55,7 +55,7 @@ namespace Umbraco.Core.Sync #region IServerMessenger - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); if (payload == null) throw new ArgumentNullException(nameof(payload)); @@ -72,7 +72,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByJson, json: jsonPayload); } - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -83,7 +83,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByInstance, getId, instances); } - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -94,7 +94,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByInstance, getId, instances); } - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -105,7 +105,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RemoveByInstance, getId, instances); } - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -114,7 +114,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RemoveById, numericIds.Cast()); } - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -123,7 +123,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshById, numericIds.Cast()); } - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -132,7 +132,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshById, guidIds.Cast()); } - public void PerformRefreshAll(ICacheRefresher refresher) + public void QueueRefreshAll(ICacheRefresher refresher) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -365,5 +365,8 @@ namespace Umbraco.Core.Sync //} #endregion + + public abstract void Sync(); + public abstract void SendMessages(); } } diff --git a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs index af59c27ef2..5db66fdf78 100644 --- a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs +++ b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs index 2031a23af5..f7fab098b0 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs @@ -1,9 +1,13 @@ -using Umbraco.Core.Composing; +using Umbraco.Core.Composing; using Umbraco.ModelsBuilder.Embedded.BackOffice; using Umbraco.Web.Features; namespace Umbraco.ModelsBuilder.Embedded.Compose { + // TODO: This needs to die, see TODO in ModelsBuilderComposer. This is also no longer used in this netcore + // codebase. Potentially this could be changed to ext methods if necessary that could be used by end users who will + // install the community MB package to disable any built in MB stuff. + /// /// Special component used for when MB is disabled with the legacy MB is detected /// diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs index fb39007bd0..7afb166069 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs @@ -6,13 +6,13 @@ using Microsoft.Extensions.Options; using Umbraco.Configuration; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.ModelsBuilder.Embedded.BackOffice; -using Umbraco.Net; using Umbraco.Web.Common.Lifetime; using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.WebAssets; diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index 81869a9261..94237ccf3d 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -1,7 +1,6 @@ -using System.Linq; +using System.Linq; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Configuration; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; @@ -11,7 +10,8 @@ using Umbraco.Core.DependencyInjection; namespace Umbraco.ModelsBuilder.Embedded.Compose { - [ComposeBefore(typeof(IPublishedCacheComposer))] + // TODO: We'll need to change this stuff to IUmbracoBuilder ext and control the order of things there + // This needs to execute before the AddNuCache call public sealed class ModelsBuilderComposer : ICoreComposer { public void Compose(IUmbracoBuilder builder) diff --git a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs index 7cdc7e72e1..f1c4f1d85b 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; diff --git a/src/Umbraco.PublishedCache.NuCache/ContentStore.cs b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs index d41ca344dc..bb03693adf 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentStore.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -1167,8 +1167,7 @@ namespace Umbraco.Web.PublishedCache.NuCache SetValueLocked(_contentTypesById, type.Id, type); SetValueLocked(_contentTypesByAlias, type.Alias, type); // ensure the key/id map is accurate - if (type.TryGetKey(out var key)) - _contentTypeKeyToIdMap[key] = type.Id; + _contentTypeKeyToIdMap[type.Key] = type.Id; } // set a node (just the node, not the tree) @@ -1353,7 +1352,9 @@ namespace Umbraco.Web.PublishedCache.NuCache // reading _floorGen is safe if _collectTask is null if (_collectTask == null && _collectAuto && _liveGen - _floorGen > CollectMinGenDelta) + { CollectAsyncLocked(); + } return snapshot; } @@ -1375,8 +1376,17 @@ namespace Umbraco.Web.PublishedCache.NuCache private Task CollectAsyncLocked() { + // NOTE: What in the heck is going on here? Why is any of this running in async contexts? + // SD: From what I can tell this was designed to be a set and forget background task to do the + // collecting which is why it's called from non-async methods within this class. This is + // slightly dangerous because it's not taking into account app shutdown. + // TODO: There should be a different method or class responsible for executing the cleanup on a + // background (set and forget) thread. + if (_collectTask != null) + { return _collectTask; + } // ReSharper disable InconsistentlySynchronizedField var task = _collectTask = Task.Run((Action)Collect); diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/ContentNestedData.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/ContentNestedData.cs index ec5424ad9a..98d423680b 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/ContentNestedData.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/ContentNestedData.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using System.Collections.Generic; using Umbraco.Core.Serialization; @@ -9,7 +9,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource /// internal class ContentNestedData { - //dont serialize empty properties + // dont serialize empty properties [JsonProperty("pd")] [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] public Dictionary PropertyData { get; set; } @@ -21,7 +21,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource [JsonProperty("us")] public string UrlSegment { get; set; } - //Legacy properties used to deserialize existing nucache db entries + // Legacy properties used to deserialize existing nucache db entries [JsonProperty("properties")] [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] private Dictionary LegacyPropertyData { set { PropertyData = value; } } diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs deleted file mode 100644 index bdcd8fe3e3..0000000000 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using NPoco; -using Umbraco.Core; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Scoping; -using Umbraco.Core.Serialization; -using static Umbraco.Core.Persistence.SqlExtensionsStatics; - -namespace Umbraco.Web.PublishedCache.NuCache.DataSource -{ - // TODO: use SqlTemplate for these queries else it's going to be horribly slow! - - // provides efficient database access for NuCache - internal class DatabaseDataSource : IDataSource - { - private const int PageSize = 500; - - private readonly ILogger _logger; - - public DatabaseDataSource(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - // we want arrays, we want them all loaded, not an enumerable - - private Sql ContentSourcesSelect(IScope scope, Func, Sql> joins = null) - { - var sql = scope.SqlContext.Sql() - - .Select(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"), - x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"), - x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId")) - .AndSelect(x => Alias(x.ContentTypeId, "ContentTypeId")) - .AndSelect(x => Alias(x.Published, "Published"), x => Alias(x.Edited, "Edited")) - - .AndSelect(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId")) - .AndSelect(x => Alias(x.TemplateId, "EditTemplateId")) - - .AndSelect("pcver", x => Alias(x.Id, "PublishedVersionId"), x => Alias(x.Text, "PubName"), x => Alias(x.VersionDate, "PubVersionDate"), x => Alias(x.UserId, "PubWriterId")) - .AndSelect("pdver", x => Alias(x.TemplateId, "PubTemplateId")) - - .AndSelect("nuEdit", x => Alias(x.Data, "EditData")) - .AndSelect("nuPub", x => Alias(x.Data, "PubData")) - - .From(); - - if (joins != null) - sql = joins(sql); - - sql = sql - .InnerJoin().On((left, right) => left.NodeId == right.NodeId) - .InnerJoin().On((left, right) => left.NodeId == right.NodeId) - - .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current) - .InnerJoin().On((left, right) => left.Id == right.Id) - - .LeftJoin(j => - j.InnerJoin("pdver").On((left, right) => left.Id == right.Id && right.Published, "pcver", "pdver"), "pcver") - .On((left, right) => left.NodeId == right.NodeId, aliasRight: "pcver") - - .LeftJoin("nuEdit").On((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit") - .LeftJoin("nuPub").On((left, right) => left.NodeId == right.NodeId && right.Published, aliasRight: "nuPub"); - - return sql; - } - - public ContentNodeKit GetContentSource(IScope scope, int id) - { - var sql = ContentSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && x.NodeId == id && !x.Trashed) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - var dto = scope.Database.Fetch(sql).FirstOrDefault(); - return dto == null ? new ContentNodeKit() : CreateContentNodeKit(dto); - } - - public IEnumerable GetAllContentSources(IScope scope) - { - var sql = ContentSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateContentNodeKit(row); - } - - public IEnumerable GetBranchContentSources(IScope scope, int id) - { - var syntax = scope.SqlContext.SqlSyntax; - var sql = ContentSourcesSelect(scope, - s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x")) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) - .Where(x => x.NodeId == id, "x") - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateContentNodeKit(row); - } - - public IEnumerable GetTypeContentSources(IScope scope, IEnumerable ids) - { - if (!ids.Any()) yield break; - - var sql = ContentSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) - .WhereIn(x => x.ContentTypeId, ids) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateContentNodeKit(row); - } - - private Sql MediaSourcesSelect(IScope scope, Func, Sql> joins = null) - { - var sql = scope.SqlContext.Sql() - - .Select(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"), - x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"), - x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId")) - .AndSelect(x => Alias(x.ContentTypeId, "ContentTypeId")) - .AndSelect(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId")) - .AndSelect("nuEdit", x => Alias(x.Data, "EditData")) - .From(); - - if (joins != null) - sql = joins(sql); - - sql = sql - .InnerJoin().On((left, right) => left.NodeId == right.NodeId) - .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current) - .LeftJoin("nuEdit").On((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit"); - - return sql; - } - - public ContentNodeKit GetMediaSource(IScope scope, int id) - { - var sql = MediaSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && x.NodeId == id && !x.Trashed) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - var dto = scope.Database.Fetch(sql).FirstOrDefault(); - return dto == null ? new ContentNodeKit() : CreateMediaNodeKit(dto); - } - - public IEnumerable GetAllMediaSources(IScope scope) - { - var sql = MediaSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateMediaNodeKit(row); - } - - public IEnumerable GetBranchMediaSources(IScope scope, int id) - { - var syntax = scope.SqlContext.SqlSyntax; - var sql = MediaSourcesSelect(scope, - s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x")) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) - .Where(x => x.NodeId == id, "x") - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateMediaNodeKit(row); - } - - public IEnumerable GetTypeMediaSources(IScope scope, IEnumerable ids) - { - if (!ids.Any()) yield break; - - var sql = MediaSourcesSelect(scope) - .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) - .WhereIn(x => x.ContentTypeId, ids) - .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); - - // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. - // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. - - foreach (var row in scope.Database.QueryPaged(PageSize, sql)) - yield return CreateMediaNodeKit(row); - } - - private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) - { - ContentData d = null; - ContentData p = null; - - if (dto.Edited) - { - if (dto.EditData == null) - { - if (Debugger.IsAttached) - throw new InvalidOperationException("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); - _logger.LogWarning("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); - } - else - { - var nested = DeserializeNestedData(dto.EditData); - - d = new ContentData - { - Name = dto.EditName, - Published = false, - TemplateId = dto.EditTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.EditWriterId, - Properties = nested.PropertyData, - CultureInfos = nested.CultureData, - UrlSegment = nested.UrlSegment - }; - } - } - - if (dto.Published) - { - if (dto.PubData == null) - { - if (Debugger.IsAttached) - throw new InvalidOperationException("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); - _logger.LogWarning("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); - } - else - { - var nested = DeserializeNestedData(dto.PubData); - - p = new ContentData - { - Name = dto.PubName, - UrlSegment = nested.UrlSegment, - Published = true, - TemplateId = dto.PubTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.PubVersionDate, - WriterId = dto.PubWriterId, - Properties = nested.PropertyData, - CultureInfos = nested.CultureData - }; - } - } - - var n = new ContentNode(dto.Id, dto.Uid, - dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); - - var s = new ContentNodeKit - { - Node = n, - ContentTypeId = dto.ContentTypeId, - DraftData = d, - PublishedData = p - }; - - return s; - } - - private static ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) - { - if (dto.EditData == null) - throw new InvalidOperationException("No data for media " + dto.Id); - - var nested = DeserializeNestedData(dto.EditData); - - var p = new ContentData - { - Name = dto.EditName, - Published = true, - TemplateId = -1, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.CreatorId, // what-else? - Properties = nested.PropertyData, - CultureInfos = nested.CultureData - }; - - var n = new ContentNode(dto.Id, dto.Uid, - dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); - - var s = new ContentNodeKit - { - Node = n, - ContentTypeId = dto.ContentTypeId, - PublishedData = p - }; - - return s; - } - - private static ContentNestedData DeserializeNestedData(string data) - { - // by default JsonConvert will deserialize our numeric values as Int64 - // which is bad, because they were Int32 in the database - take care - - var settings = new JsonSerializerSettings - { - Converters = new List { new ForceInt32Converter() } - }; - - return JsonConvert.DeserializeObject(data, settings); - } - } -} diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/IDataSource.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/IDataSource.cs deleted file mode 100644 index ec3ab38e84..0000000000 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/IDataSource.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Core.Scoping; - -namespace Umbraco.Web.PublishedCache.NuCache.DataSource -{ - /// - /// Defines a data source for NuCache. - /// - internal interface IDataSource - { - //TODO: For these required sort orders, would sorting on Path 'just work'? - - ContentNodeKit GetContentSource(IScope scope, int id); - - /// - /// Returns all content ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetAllContentSources(IScope scope); - - /// - /// Returns branch for content ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetBranchContentSources(IScope scope, int id); - - /// - /// Returns content by Ids ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetTypeContentSources(IScope scope, IEnumerable ids); - - ContentNodeKit GetMediaSource(IScope scope, int id); - - /// - /// Returns all media ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetAllMediaSources(IScope scope); - - /// - /// Returns branch for media ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetBranchMediaSources(IScope scope, int id); // must order by level, sortOrder - - /// - /// Returns media by Ids ordered by level + sortOrder - /// - /// - /// - /// - /// MUST be ordered by level + parentId + sortOrder! - /// - IEnumerable GetTypeMediaSources(IScope scope, IEnumerable ids); - } -} diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/PropertyData.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/PropertyData.cs index cf7ab95360..42e038c744 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/PropertyData.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/PropertyData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using Newtonsoft.Json; @@ -29,7 +29,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource public object Value { get; set; } - //Legacy properties used to deserialize existing nucache db entries + // Legacy properties used to deserialize existing nucache db entries [JsonProperty("culture")] private string LegacyCulture { diff --git a/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..6f6e0d0c0e --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Models; +using Umbraco.Core.Scoping; +using Umbraco.Core.Services; +using Umbraco.Infrastructure.PublishedCache.Persistence; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.NuCache; + +namespace Umbraco.Infrastructure.PublishedCache.DependencyInjection +{ + /// + /// Extension methods for for the Umbraco's NuCache + /// + public static class UmbracoBuilderExtensions + { + /// + /// Adds Umbraco NuCache dependencies + /// + public static IUmbracoBuilder AddNuCache(this IUmbracoBuilder builder) + { + // register the NuCache database data source + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); + + // register the NuCache published snapshot service + // must register default options, required in the service ctor + builder.Services.TryAddTransient(factory => new PublishedSnapshotServiceOptions()); + builder.SetPublishedSnapshotService(); + + // Add as itself + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); + + // replace this service since we want to improve the content/media + // mapping lookups if we are using nucache. + // TODO: Gotta wonder how much this does actually improve perf? It's a lot of weird code to make this happen so hope it's worth it + builder.Services.AddUnique(factory => + { + var idkSvc = new IdKeyMap(factory.GetRequiredService()); + if (factory.GetRequiredService() is PublishedSnapshotService publishedSnapshotService) + { + idkSvc.SetMapper(UmbracoObjectTypes.Document, id => publishedSnapshotService.GetDocumentUid(id), uid => publishedSnapshotService.GetDocumentId(uid)); + idkSvc.SetMapper(UmbracoObjectTypes.Media, id => publishedSnapshotService.GetMediaUid(id), uid => publishedSnapshotService.GetMediaId(uid)); + } + + return idkSvc; + }); + + // add the NuCache health check (hidden from type finder) + // TODO: no NuCache health check yet + // composition.HealthChecks().Add(); + return builder; + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/NuCacheComponent.cs b/src/Umbraco.PublishedCache.NuCache/NuCacheComponent.cs deleted file mode 100644 index fba133a2aa..0000000000 --- a/src/Umbraco.PublishedCache.NuCache/NuCacheComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web.PublishedCache.NuCache -{ - public sealed class NuCacheComponent : IComponent - { - public NuCacheComponent(IPublishedSnapshotService service) - { - // nothing - this just ensures that the service is created at boot time - } - - public void Initialize() - { } - - public void Terminate() - { } - } -} diff --git a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs b/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs deleted file mode 100644 index 17e707effd..0000000000 --- a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Models; -using Umbraco.Core.Scoping; -using Umbraco.Core.Services; -using Umbraco.Infrastructure.PublishedCache; -using Umbraco.Web.PublishedCache.NuCache.DataSource; - -namespace Umbraco.Web.PublishedCache.NuCache -{ - public class NuCacheComposer : ComponentComposer, IPublishedCacheComposer - { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - // register the NuCache database data source - builder.Services.AddTransient(); - - // register the NuCache published snapshot service - // must register default options, required in the service ctor - builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions()); - builder.SetPublishedSnapshotService(); - - // replace this service since we want to improve the content/media - // mapping lookups if we are using nucache. - builder.Services.AddUnique(factory => - { - var idkSvc = new IdKeyMap(factory.GetRequiredService()); - var publishedSnapshotService = factory.GetRequiredService() as PublishedSnapshotService; - if (publishedSnapshotService != null) - { - idkSvc.SetMapper(UmbracoObjectTypes.Document, id => publishedSnapshotService.GetDocumentUid(id), uid => publishedSnapshotService.GetDocumentId(uid)); - idkSvc.SetMapper(UmbracoObjectTypes.Media, id => publishedSnapshotService.GetMediaUid(id), uid => publishedSnapshotService.GetMediaId(uid)); - } - return idkSvc; - }); - - // add the NuCache health check (hidden from type finder) - // TODO: no NuCache health check yet - //composition.HealthChecks().Add(); - } - } -} diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentRepository.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentRepository.cs new file mode 100644 index 0000000000..7bce5e138c --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentRepository.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Web.PublishedCache.NuCache; + +namespace Umbraco.Infrastructure.PublishedCache.Persistence +{ + public interface INuCacheContentRepository + { + void DeleteContentItem(IContentBase item); + IEnumerable GetAllContentSources(); + IEnumerable GetAllMediaSources(); + IEnumerable GetBranchContentSources(int id); + IEnumerable GetBranchMediaSources(int id); + ContentNodeKit GetContentSource(int id); + ContentNodeKit GetMediaSource(int id); + IEnumerable GetTypeContentSources(IEnumerable ids); + IEnumerable GetTypeMediaSources(IEnumerable ids); + + /// + /// Refreshes the nucache database row for the + /// + void RefreshContent(IContent content); + + /// + /// Refreshes the nucache database row for the (used for media/members) + /// + void RefreshEntity(IContentBase content); + + /// + /// Rebuilds the caches for content, media and/or members based on the content type ids specified + /// + /// The operation batch size to process the items + /// If not null will process content for the matching content types, if empty will process all content + /// If not null will process content for the matching media types, if empty will process all media + /// If not null will process content for the matching members types, if empty will process all members + void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null); + + bool VerifyContentDbCache(); + bool VerifyMediaDbCache(); + bool VerifyMemberDbCache(); + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentService.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentService.cs new file mode 100644 index 0000000000..4a3f5b2b5d --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/INuCacheContentService.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Web.PublishedCache.NuCache; + +namespace Umbraco.Infrastructure.PublishedCache.Persistence +{ + /// + /// Defines a data source for NuCache. + /// + public interface INuCacheContentService + { + // TODO: For these required sort orders, would sorting on Path 'just work'? + ContentNodeKit GetContentSource(int id); + + /// + /// Returns all content ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetAllContentSources(); + + /// + /// Returns branch for content ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetBranchContentSources(int id); + + /// + /// Returns content by Ids ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetTypeContentSources(IEnumerable ids); + + ContentNodeKit GetMediaSource(int id); + + /// + /// Returns all media ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetAllMediaSources(); + + /// + /// Returns branch for media ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetBranchMediaSources(int id); // must order by level, sortOrder + + /// + /// Returns media by Ids ordered by level + sortOrder + /// + /// + /// MUST be ordered by level + parentId + sortOrder! + /// + IEnumerable GetTypeMediaSources(IEnumerable ids); + + void DeleteContentItem(IContentBase item); + + /// + /// Refreshes the nucache database row for the + /// + void RefreshContent(IContent content); + + /// + /// Refreshes the nucache database row for the (used for media/members) + /// + void RefreshEntity(IContentBase content); + + /// + /// Rebuilds the database caches for content, media and/or members based on the content type ids specified + /// + /// The operation batch size to process the items + /// If not null will process content for the matching content types, if empty will process all content + /// If not null will process content for the matching media types, if empty will process all media + /// If not null will process content for the matching members types, if empty will process all members + void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null); + + bool VerifyContentDbCache(); + + bool VerifyMediaDbCache(); + + bool VerifyMemberDbCache(); + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs new file mode 100644 index 0000000000..60370e9be8 --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs @@ -0,0 +1,735 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using NPoco; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Web.PublishedCache.NuCache; +using Umbraco.Web.PublishedCache.NuCache.DataSource; +using static Umbraco.Core.Persistence.SqlExtensionsStatics; + +namespace Umbraco.Infrastructure.PublishedCache.Persistence +{ + public class NuCacheContentRepository : RepositoryBase, INuCacheContentRepository + { + private const int PageSize = 500; + private readonly ILogger _logger; + private readonly IMemberRepository _memberRepository; + private readonly IDocumentRepository _documentRepository; + private readonly IMediaRepository _mediaRepository; + private readonly IShortStringHelper _shortStringHelper; + private readonly UrlSegmentProviderCollection _urlSegmentProviders; + + /// + /// Initializes a new instance of the class. + /// + public NuCacheContentRepository( + IScopeAccessor scopeAccessor, + AppCaches appCaches, + ILogger logger, + IMemberRepository memberRepository, + IDocumentRepository documentRepository, + IMediaRepository mediaRepository, + IShortStringHelper shortStringHelper, + UrlSegmentProviderCollection urlSegmentProviders) + : base(scopeAccessor, appCaches) + { + _logger = logger; + _memberRepository = memberRepository; + _documentRepository = documentRepository; + _mediaRepository = mediaRepository; + _shortStringHelper = shortStringHelper; + _urlSegmentProviders = urlSegmentProviders; + } + + public void DeleteContentItem(IContentBase item) + => Database.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id", new { id = item.Id }); + + public void RefreshContent(IContent content) + { + // always refresh the edited data + OnRepositoryRefreshed(content, false); + + if (content.PublishedState == PublishedState.Unpublishing) + { + // if unpublishing, remove published data from table + Database.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id AND published=1", new { id = content.Id }); + } + else if (content.PublishedState == PublishedState.Publishing) + { + // if publishing, refresh the published data + OnRepositoryRefreshed(content, true); + } + } + + public void RefreshEntity(IContentBase content) + => OnRepositoryRefreshed(content, false); + + private void OnRepositoryRefreshed(IContentBase content, bool published) + { + // use a custom SQL to update row version on each update + // db.InsertOrUpdate(dto); + ContentNuDto dto = GetDto(content, published); + + Database.InsertOrUpdate( + dto, + "SET data=@data, rv=rv+1 WHERE nodeId=@id AND published=@published", + new + { + data = dto.Data, + id = dto.NodeId, + published = dto.Published + }); + } + + public void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null) + { + if (contentTypeIds != null) + { + RebuildContentDbCache(groupSize, contentTypeIds); + } + + if (mediaTypeIds != null) + { + RebuildContentDbCache(groupSize, mediaTypeIds); + } + + if (memberTypeIds != null) + { + RebuildContentDbCache(groupSize, memberTypeIds); + } + } + + // assumes content tree lock + private void RebuildContentDbCache(int groupSize, IReadOnlyCollection contentTypeIds) + { + Guid contentObjectType = Constants.ObjectTypes.Document; + + // remove all - if anything fails the transaction will rollback + if (contentTypeIds == null || contentTypeIds.Count == 0) + { + // must support SQL-CE + Database.Execute( + @"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType +)", + new { objType = contentObjectType }); + } + else + { + // assume number of ctypes won't blow IN(...) + // must support SQL-CE + Database.Execute( + $@"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id + WHERE umbracoNode.nodeObjectType=@objType + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) +)", + new { objType = contentObjectType, ctypes = contentTypeIds }); + } + + // insert back - if anything fails the transaction will rollback + IQuery query = SqlContext.Query(); + if (contentTypeIds != null && contentTypeIds.Count > 0) + { + query = query.WhereIn(x => x.ContentTypeId, contentTypeIds); // assume number of ctypes won't blow IN(...) + } + + long pageIndex = 0; + long processed = 0; + long total; + do + { + // the tree is locked, counting and comparing to total is safe + IEnumerable descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); + var items = new List(); + var count = 0; + foreach (IContent c in descendants) + { + // always the edited version + items.Add(GetDto(c, false)); + + // and also the published version if it makes any sense + if (c.Published) + { + items.Add(GetDto(c, true)); + } + + count++; + } + + Database.BulkInsertRecords(items); + processed += count; + } while (processed < total); + } + + // assumes media tree lock + private void RebuildMediaDbCache(int groupSize, IReadOnlyCollection contentTypeIds) + { + var mediaObjectType = Constants.ObjectTypes.Media; + + // remove all - if anything fails the transaction will rollback + if (contentTypeIds == null || contentTypeIds.Count == 0) + { + // must support SQL-CE + Database.Execute( + @"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType +)", + new { objType = mediaObjectType }); + } + else + { + // assume number of ctypes won't blow IN(...) + // must support SQL-CE + Database.Execute( + $@"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id + WHERE umbracoNode.nodeObjectType=@objType + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) +)", + new { objType = mediaObjectType, ctypes = contentTypeIds }); + } + + // insert back - if anything fails the transaction will rollback + var query = SqlContext.Query(); + if (contentTypeIds != null && contentTypeIds.Count > 0) + { + query = query.WhereIn(x => x.ContentTypeId, contentTypeIds); // assume number of ctypes won't blow IN(...) + } + + long pageIndex = 0; + long processed = 0; + long total; + do + { + // the tree is locked, counting and comparing to total is safe + var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); + var items = descendants.Select(m => GetDto(m, false)).ToList(); + Database.BulkInsertRecords(items); + processed += items.Count; + } while (processed < total); + } + + // assumes member tree lock + private void RebuildMemberDbCache(int groupSize, IReadOnlyCollection contentTypeIds) + { + Guid memberObjectType = Constants.ObjectTypes.Member; + + // remove all - if anything fails the transaction will rollback + if (contentTypeIds == null || contentTypeIds.Count == 0) + { + // must support SQL-CE + Database.Execute( + @"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType +)", + new { objType = memberObjectType }); + } + else + { + // assume number of ctypes won't blow IN(...) + // must support SQL-CE + Database.Execute( + $@"DELETE FROM cmsContentNu +WHERE cmsContentNu.nodeId IN ( + SELECT id FROM umbracoNode + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id + WHERE umbracoNode.nodeObjectType=@objType + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) +)", + new { objType = memberObjectType, ctypes = contentTypeIds }); + } + + // insert back - if anything fails the transaction will rollback + IQuery query = SqlContext.Query(); + if (contentTypeIds != null && contentTypeIds.Count > 0) + { + query = query.WhereIn(x => x.ContentTypeId, contentTypeIds); // assume number of ctypes won't blow IN(...) + } + + long pageIndex = 0; + long processed = 0; + long total; + do + { + IEnumerable descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); + ContentNuDto[] items = descendants.Select(m => GetDto(m, false)).ToArray(); + Database.BulkInsertRecords(items); + processed += items.Length; + } while (processed < total); + } + + // assumes content tree lock + public bool VerifyContentDbCache() + { + // every document should have a corresponding row for edited properties + // and if published, may have a corresponding row for published properties + Guid contentObjectType = Constants.ObjectTypes.Document; + + var count = Database.ExecuteScalar( + $@"SELECT COUNT(*) +FROM umbracoNode +JOIN {Constants.DatabaseSchema.Tables.Document} ON umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId +LEFT JOIN cmsContentNu nuEdited ON (umbracoNode.id=nuEdited.nodeId AND nuEdited.published=0) +LEFT JOIN cmsContentNu nuPublished ON (umbracoNode.id=nuPublished.nodeId AND nuPublished.published=1) +WHERE umbracoNode.nodeObjectType=@objType +AND nuEdited.nodeId IS NULL OR ({Constants.DatabaseSchema.Tables.Document}.published=1 AND nuPublished.nodeId IS NULL);", + new { objType = contentObjectType }); + + return count == 0; + } + + // assumes media tree lock + public bool VerifyMediaDbCache() + { + // every media item should have a corresponding row for edited properties + Guid mediaObjectType = Constants.ObjectTypes.Media; + + var count = Database.ExecuteScalar( + @"SELECT COUNT(*) +FROM umbracoNode +LEFT JOIN cmsContentNu ON (umbracoNode.id=cmsContentNu.nodeId AND cmsContentNu.published=0) +WHERE umbracoNode.nodeObjectType=@objType +AND cmsContentNu.nodeId IS NULL +", new { objType = mediaObjectType }); + + return count == 0; + } + + // assumes member tree lock + public bool VerifyMemberDbCache() + { + // every member item should have a corresponding row for edited properties + var memberObjectType = Constants.ObjectTypes.Member; + + var count = Database.ExecuteScalar( + @"SELECT COUNT(*) +FROM umbracoNode +LEFT JOIN cmsContentNu ON (umbracoNode.id=cmsContentNu.nodeId AND cmsContentNu.published=0) +WHERE umbracoNode.nodeObjectType=@objType +AND cmsContentNu.nodeId IS NULL +", new { objType = memberObjectType }); + + return count == 0; + } + + private ContentNuDto GetDto(IContentBase content, bool published) + { + // should inject these in ctor + // BUT for the time being we decide not to support ConvertDbToXml/String + // var propertyEditorResolver = PropertyEditorResolver.Current; + // var dataTypeService = ApplicationContext.Current.Services.DataTypeService; + var propertyData = new Dictionary(); + foreach (IProperty prop in content.Properties) + { + var pdatas = new List(); + foreach (IPropertyValue pvalue in prop.Values) + { + // sanitize - properties should be ok but ... never knows + if (!prop.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment)) + { + continue; + } + + // note: at service level, invariant is 'null', but here invariant becomes 'string.Empty' + var value = published ? pvalue.PublishedValue : pvalue.EditedValue; + if (value != null) + { + pdatas.Add(new PropertyData { Culture = pvalue.Culture ?? string.Empty, Segment = pvalue.Segment ?? string.Empty, Value = value }); + } + } + + propertyData[prop.Alias] = pdatas.ToArray(); + } + + var cultureData = new Dictionary(); + + // sanitize - names should be ok but ... never knows + if (content.ContentType.VariesByCulture()) + { + ContentCultureInfosCollection infos = content is IContent document + ? published + ? document.PublishCultureInfos + : document.CultureInfos + : content.CultureInfos; + + // ReSharper disable once UseDeconstruction + foreach (ContentCultureInfos cultureInfo in infos) + { + var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(cultureInfo.Culture); + cultureData[cultureInfo.Culture] = new CultureVariation + { + Name = cultureInfo.Name, + UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders, cultureInfo.Culture), + Date = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue, + IsDraft = cultureIsDraft + }; + } + } + + // the dictionary that will be serialized + var nestedData = new ContentNestedData + { + PropertyData = propertyData, + CultureData = cultureData, + UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders) + }; + + var dto = new ContentNuDto + { + NodeId = content.Id, + Published = published, + + // note that numeric values (which are Int32) are serialized without their + // type (eg "value":1234) and JsonConvert by default deserializes them as Int64 + Data = JsonConvert.SerializeObject(nestedData) + }; + + return dto; + } + + // we want arrays, we want them all loaded, not an enumerable + private Sql ContentSourcesSelect(Func, Sql> joins = null) + { + var sql = Sql() + + .Select(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"), + x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"), + x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId")) + .AndSelect(x => Alias(x.ContentTypeId, "ContentTypeId")) + .AndSelect(x => Alias(x.Published, "Published"), x => Alias(x.Edited, "Edited")) + + .AndSelect(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId")) + .AndSelect(x => Alias(x.TemplateId, "EditTemplateId")) + + .AndSelect("pcver", x => Alias(x.Id, "PublishedVersionId"), x => Alias(x.Text, "PubName"), x => Alias(x.VersionDate, "PubVersionDate"), x => Alias(x.UserId, "PubWriterId")) + .AndSelect("pdver", x => Alias(x.TemplateId, "PubTemplateId")) + + .AndSelect("nuEdit", x => Alias(x.Data, "EditData")) + .AndSelect("nuPub", x => Alias(x.Data, "PubData")) + + .From(); + + if (joins != null) + { + sql = joins(sql); + } + + sql = sql + .InnerJoin().On((left, right) => left.NodeId == right.NodeId) + .InnerJoin().On((left, right) => left.NodeId == right.NodeId) + + .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current) + .InnerJoin().On((left, right) => left.Id == right.Id) + + .LeftJoin(j => + j.InnerJoin("pdver").On((left, right) => left.Id == right.Id && right.Published, "pcver", "pdver"), "pcver") + .On((left, right) => left.NodeId == right.NodeId, aliasRight: "pcver") + + .LeftJoin("nuEdit").On((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit") + .LeftJoin("nuPub").On((left, right) => left.NodeId == right.NodeId && right.Published, aliasRight: "nuPub"); + + return sql; + } + + public ContentNodeKit GetContentSource(int id) + { + var sql = ContentSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && x.NodeId == id && !x.Trashed) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + var dto = Database.Fetch(sql).FirstOrDefault(); + return dto == null ? new ContentNodeKit() : CreateContentNodeKit(dto); + } + + public IEnumerable GetAllContentSources() + { + var sql = ContentSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateContentNodeKit(row); + } + } + + public IEnumerable GetBranchContentSources(int id) + { + var syntax = SqlSyntax; + var sql = ContentSourcesSelect( + s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x")) + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) + .Where(x => x.NodeId == id, "x") + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateContentNodeKit(row); + } + } + + public IEnumerable GetTypeContentSources(IEnumerable ids) + { + if (!ids.Any()) + yield break; + + var sql = ContentSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Document && !x.Trashed) + .WhereIn(x => x.ContentTypeId, ids) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateContentNodeKit(row); + } + } + + private Sql MediaSourcesSelect(Func, Sql> joins = null) + { + var sql = Sql() + + .Select(x => Alias(x.NodeId, "Id"), x => Alias(x.UniqueId, "Uid"), + x => Alias(x.Level, "Level"), x => Alias(x.Path, "Path"), x => Alias(x.SortOrder, "SortOrder"), x => Alias(x.ParentId, "ParentId"), + x => Alias(x.CreateDate, "CreateDate"), x => Alias(x.UserId, "CreatorId")) + .AndSelect(x => Alias(x.ContentTypeId, "ContentTypeId")) + .AndSelect(x => Alias(x.Id, "VersionId"), x => Alias(x.Text, "EditName"), x => Alias(x.VersionDate, "EditVersionDate"), x => Alias(x.UserId, "EditWriterId")) + .AndSelect("nuEdit", x => Alias(x.Data, "EditData")) + .From(); + + if (joins != null) + { + sql = joins(sql); + } + + sql = sql + .InnerJoin().On((left, right) => left.NodeId == right.NodeId) + .InnerJoin().On((left, right) => left.NodeId == right.NodeId && right.Current) + .LeftJoin("nuEdit").On((left, right) => left.NodeId == right.NodeId && !right.Published, aliasRight: "nuEdit"); + + return sql; + } + + public ContentNodeKit GetMediaSource(int id) + { + var sql = MediaSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && x.NodeId == id && !x.Trashed) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + var dto = Database.Fetch(sql).FirstOrDefault(); + return dto == null ? new ContentNodeKit() : CreateMediaNodeKit(dto); + } + + public IEnumerable GetAllMediaSources() + { + var sql = MediaSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateMediaNodeKit(row); + } + } + + public IEnumerable GetBranchMediaSources(int id) + { + var syntax = SqlSyntax; + var sql = MediaSourcesSelect( + s => s.InnerJoin("x").On((left, right) => left.NodeId == right.NodeId || SqlText(left.Path, right.Path, (lp, rp) => $"({lp} LIKE {syntax.GetConcat(rp, "',%'")})"), aliasRight: "x")) + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) + .Where(x => x.NodeId == id, "x") + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateMediaNodeKit(row); + } + } + + public IEnumerable GetTypeMediaSources(IEnumerable ids) + { + if (!ids.Any()) + { + yield break; + } + + var sql = MediaSourcesSelect() + .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media && !x.Trashed) + .WhereIn(x => x.ContentTypeId, ids) + .OrderBy(x => x.Level, x => x.ParentId, x => x.SortOrder); + + // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. + // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. + + foreach (var row in Database.QueryPaged(PageSize, sql)) + { + yield return CreateMediaNodeKit(row); + } + } + + private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) + { + ContentData d = null; + ContentData p = null; + + if (dto.Edited) + { + if (dto.EditData == null) + { + if (Debugger.IsAttached) + { + throw new InvalidOperationException("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); + } + + _logger.LogWarning("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); + } + else + { + var nested = DeserializeNestedData(dto.EditData); + + d = new ContentData + { + Name = dto.EditName, + Published = false, + TemplateId = dto.EditTemplateId, + VersionId = dto.VersionId, + VersionDate = dto.EditVersionDate, + WriterId = dto.EditWriterId, + Properties = nested.PropertyData, + CultureInfos = nested.CultureData, + UrlSegment = nested.UrlSegment + }; + } + } + + if (dto.Published) + { + if (dto.PubData == null) + { + if (Debugger.IsAttached) + { + throw new InvalidOperationException("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); + } + + _logger.LogWarning("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); + } + else + { + var nested = DeserializeNestedData(dto.PubData); + + p = new ContentData + { + Name = dto.PubName, + UrlSegment = nested.UrlSegment, + Published = true, + TemplateId = dto.PubTemplateId, + VersionId = dto.VersionId, + VersionDate = dto.PubVersionDate, + WriterId = dto.PubWriterId, + Properties = nested.PropertyData, + CultureInfos = nested.CultureData + }; + } + } + + var n = new ContentNode(dto.Id, dto.Uid, + dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); + + var s = new ContentNodeKit + { + Node = n, + ContentTypeId = dto.ContentTypeId, + DraftData = d, + PublishedData = p + }; + + return s; + } + + private static ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) + { + if (dto.EditData == null) + throw new InvalidOperationException("No data for media " + dto.Id); + + var nested = DeserializeNestedData(dto.EditData); + + var p = new ContentData + { + Name = dto.EditName, + Published = true, + TemplateId = -1, + VersionId = dto.VersionId, + VersionDate = dto.EditVersionDate, + WriterId = dto.CreatorId, // what-else? + Properties = nested.PropertyData, + CultureInfos = nested.CultureData + }; + + var n = new ContentNode(dto.Id, dto.Uid, + dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); + + var s = new ContentNodeKit + { + Node = n, + ContentTypeId = dto.ContentTypeId, + PublishedData = p + }; + + return s; + } + + private static ContentNestedData DeserializeNestedData(string data) + { + // by default JsonConvert will deserialize our numeric values as Int64 + // which is bad, because they were Int32 in the database - take care + + var settings = new JsonSerializerSettings + { + Converters = new List { new ForceInt32Converter() } + }; + + return JsonConvert.DeserializeObject(data, settings); + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentService.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentService.cs new file mode 100644 index 0000000000..00c3671217 --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentService.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Umbraco.Core; +using Umbraco.Core.Events; +using Umbraco.Core.Models; +using Umbraco.Core.Scoping; +using Umbraco.Core.Services.Implement; +using Umbraco.Web.PublishedCache.NuCache; + +namespace Umbraco.Infrastructure.PublishedCache.Persistence +{ + public class NuCacheContentService : RepositoryService, INuCacheContentService + { + private readonly INuCacheContentRepository _repository; + + public NuCacheContentService(INuCacheContentRepository repository, IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) + { + _repository = repository; + } + + /// + public IEnumerable GetAllContentSources() + => _repository.GetAllContentSources(); + + /// + public IEnumerable GetAllMediaSources() + => _repository.GetAllMediaSources(); + + /// + public IEnumerable GetBranchContentSources(int id) + => _repository.GetBranchContentSources(id); + + /// + public IEnumerable GetBranchMediaSources(int id) + => _repository.GetBranchMediaSources(id); + + /// + public ContentNodeKit GetContentSource(int id) + => _repository.GetContentSource(id); + + /// + public ContentNodeKit GetMediaSource(int id) + => _repository.GetMediaSource(id); + + /// + public IEnumerable GetTypeContentSources(IEnumerable ids) + => _repository.GetTypeContentSources(ids); + + /// + public IEnumerable GetTypeMediaSources(IEnumerable ids) + => _repository.GetTypeContentSources(ids); + + /// + public void DeleteContentItem(IContentBase item) + => _repository.DeleteContentItem(item); + + /// + public void RefreshContent(IContent content) + => _repository.RefreshContent(content); + + /// + public void RefreshEntity(IContentBase content) + => _repository.RefreshEntity(content); + + /// + public void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null) + { + using (IScope scope = ScopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) + { + if (contentTypeIds != null) + { + scope.ReadLock(Constants.Locks.ContentTree); + } + + if (mediaTypeIds != null) + { + scope.ReadLock(Constants.Locks.MediaTree); + } + + if (memberTypeIds != null) + { + scope.ReadLock(Constants.Locks.MemberTree); + } + + _repository.Rebuild(groupSize, contentTypeIds, mediaTypeIds, memberTypeIds); + scope.Complete(); + } + } + + /// + public bool VerifyContentDbCache() + { + using IScope scope = ScopeProvider.CreateScope(autoComplete: true); + scope.ReadLock(Constants.Locks.ContentTree); + return _repository.VerifyContentDbCache(); + } + + /// + public bool VerifyMediaDbCache() + { + using IScope scope = ScopeProvider.CreateScope(autoComplete: true); + scope.ReadLock(Constants.Locks.MediaTree); + return _repository.VerifyMediaDbCache(); + } + + /// + public bool VerifyMemberDbCache() + { + using IScope scope = ScopeProvider.CreateScope(autoComplete: true); + scope.ReadLock(Constants.Locks.MemberTree); + return _repository.VerifyMemberDbCache(); + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/Property.cs b/src/Umbraco.PublishedCache.NuCache/Property.cs index 86023bb302..1b70c6504c 100644 --- a/src/Umbraco.PublishedCache.NuCache/Property.cs +++ b/src/Umbraco.PublishedCache.NuCache/Property.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Xml.Serialization; using Umbraco.Core; @@ -158,6 +158,7 @@ namespace Umbraco.Web.PublishedCache.NuCache default: throw new InvalidOperationException("Invalid cache level."); } + return cacheValues; } diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs b/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs index 6fe65a4ff5..9cdc0db4fa 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedContent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Umbraco.Core; @@ -43,7 +43,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // add one property per property type - this is required, for the indexing to work // if contentData supplies pdatas, use them, else use null contentData.Properties.TryGetValue(propertyType.Alias, out var pdatas); // else will be null - properties[i++] =new Property(propertyType, this, pdatas, _publishedSnapshotAccessor); + properties[i++] = new Property(propertyType, this, pdatas, _publishedSnapshotAccessor); } PropertiesArray = properties; } diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 97e3df16a6..49283de276 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using CSharpTest.Net.Collections; -using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; @@ -14,18 +15,12 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories; -using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; -using Umbraco.Core.Services.Implement; -using Umbraco.Core.Strings; -using Umbraco.Net; +using Umbraco.Infrastructure.PublishedCache.Persistence; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache.NuCache.DataSource; using Umbraco.Web.Routing; @@ -33,38 +28,32 @@ using File = System.IO.File; namespace Umbraco.Web.PublishedCache.NuCache { - internal class PublishedSnapshotService : PublishedSnapshotServiceBase + + internal class PublishedSnapshotService : IPublishedSnapshotService { - private readonly PublishedSnapshotServiceOptions _options; - private readonly IMainDom _mainDom; - private readonly IUmbracoApplicationLifetime _lifeTime; - private readonly IRuntimeState _runtime; private readonly ServiceContext _serviceContext; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; + private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly IVariationContextAccessor _variationContextAccessor; private readonly IProfilingLogger _profilingLogger; private readonly IScopeProvider _scopeProvider; - private readonly IDataSource _dataSource; + private readonly INuCacheContentService _publishedContentService; private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; - private readonly IDocumentRepository _documentRepository; - private readonly IMediaRepository _mediaRepository; - private readonly IMemberRepository _memberRepository; private readonly GlobalSettings _globalSettings; private readonly IEntityXmlSerializer _entitySerializer; private readonly IPublishedModelFactory _publishedModelFactory; private readonly IDefaultCultureAccessor _defaultCultureAccessor; - private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IShortStringHelper _shortStringHelper; - private readonly IIOHelper _ioHelper; private readonly NuCacheSettings _config; - // volatile because we read it with no lock - private volatile bool _isReady; + private bool _isReady; + private bool _isReadSet; + private object _isReadyLock; - private ContentStore _contentStore; - private ContentStore _mediaStore; - private SnapDictionary _domainStore; + private readonly ContentStore _contentStore; + private readonly ContentStore _mediaStore; + private readonly SnapDictionary _domainStore; private readonly object _storesLock = new object(); private readonly object _elementsLock = new object(); @@ -73,19 +62,20 @@ namespace Umbraco.Web.PublishedCache.NuCache private bool _localContentDbExists; private bool _localMediaDbExists; + private long _contentGen; + private long _mediaGen; + private long _domainGen; + private IAppCache _elementsCache; + // define constant - determines whether to use cache when previewing // to store eg routes, property converted values, anything - caching // means faster execution, but uses memory - not sure if we want it // so making it configurable. public static readonly bool FullCacheWhenPreviewing = true; - #region Constructors - public PublishedSnapshotService( PublishedSnapshotServiceOptions options, IMainDom mainDom, - IUmbracoApplicationLifetime lifeTime, - IRuntimeState runtime, ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IPublishedSnapshotAccessor publishedSnapshotAccessor, @@ -93,41 +83,26 @@ namespace Umbraco.Web.PublishedCache.NuCache IProfilingLogger profilingLogger, ILoggerFactory loggerFactory, IScopeProvider scopeProvider, - IDocumentRepository documentRepository, - IMediaRepository mediaRepository, - IMemberRepository memberRepository, + INuCacheContentService publishedContentService, IDefaultCultureAccessor defaultCultureAccessor, - IDataSource dataSource, IOptions globalSettings, IEntityXmlSerializer entitySerializer, IPublishedModelFactory publishedModelFactory, - UrlSegmentProviderCollection urlSegmentProviders, IHostingEnvironment hostingEnvironment, - IShortStringHelper shortStringHelper, - IIOHelper ioHelper, IOptions config) - : base(publishedSnapshotAccessor, variationContextAccessor) { - _options = options; - _mainDom = mainDom; - _lifeTime = lifeTime; - _runtime = runtime; _serviceContext = serviceContext; _publishedContentTypeFactory = publishedContentTypeFactory; + _publishedSnapshotAccessor = publishedSnapshotAccessor; + _variationContextAccessor = variationContextAccessor; _profilingLogger = profilingLogger; - _dataSource = dataSource; _loggerFactory = loggerFactory; _logger = _loggerFactory.CreateLogger(); _scopeProvider = scopeProvider; - _documentRepository = documentRepository; - _mediaRepository = mediaRepository; - _memberRepository = memberRepository; + _publishedContentService = publishedContentService; _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings.Value; - _urlSegmentProviders = urlSegmentProviders; _hostingEnvironment = hostingEnvironment; - _shortStringHelper = shortStringHelper; - _ioHelper = ioHelper; _config = config.Value; // we need an Xml serializer here so that the member cache can support XPath, @@ -135,70 +110,53 @@ namespace Umbraco.Web.PublishedCache.NuCache _entitySerializer = entitySerializer; _publishedModelFactory = publishedModelFactory; - // we always want to handle repository events, configured or not - // assuming no repository event will trigger before the whole db is ready - // (ideally we'd have Upgrading.App vs Upgrading.Data application states...) - InitializeRepositoryEvents(); - - _lifeTime.ApplicationInit += OnApplicationInit; - } - - internal void OnApplicationInit(object sender, EventArgs e) - { - // however, the cache is NOT available until we are configured, because loading - // content (and content types) from database cannot be consistent (see notes in "Handle - // Notifications" region), so - // - notifications will be ignored - // - trying to obtain a published snapshot from the service will throw - if (_runtime.Level != RuntimeLevel.Run) - return; - // lock this entire call, we only want a single thread to be accessing the stores at once and within // the call below to mainDom.Register, a callback may occur on a threadpool thread to MainDomRelease // at the same time as we are trying to write to the stores. MainDomRelease also locks on _storesLock so // it will not be able to close the stores until we are done populating (if the store is empty) lock (_storesLock) { - if (!_options.IgnoreLocalDb) + if (!options.IgnoreLocalDb) { - _mainDom.Register(MainDomRegister, MainDomRelease); + mainDom.Register(MainDomRegister, MainDomRelease); // stores are created with a db so they can write to it, but they do not read from it, // stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to // figure out whether it can read the databases or it should populate them from sql _logger.LogInformation("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists); - _contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localContentDb); + _contentStore = new ContentStore(_publishedSnapshotAccessor, _variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localContentDb); _logger.LogInformation("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists); - _mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localMediaDb); + _mediaStore = new ContentStore(_publishedSnapshotAccessor, _variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localMediaDb); } else { _logger.LogInformation("Creating the content store (local db ignored)"); - _contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); + _contentStore = new ContentStore(_publishedSnapshotAccessor, _variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); _logger.LogInformation("Creating the media store (local db ignored)"); - _mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); + _mediaStore = new ContentStore(_publishedSnapshotAccessor, _variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); } _domainStore = new SnapDictionary(); - - LoadCachesOnStartup(); } } - #region Id <-> Key methods + protected PublishedSnapshot CurrentPublishedSnapshot => (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot; // NOTE: These aren't used within this object but are made available internally to improve the IdKey lookup performance // when nucache is enabled. - + // TODO: Does this need to be here? internal int GetDocumentId(Guid udi) => GetId(_contentStore, udi); - internal int GetMediaId(Guid udi) => GetId(_mediaStore, udi); - internal Guid GetDocumentUid(int id) => GetUid(_contentStore, id); - internal Guid GetMediaUid(int id) => GetUid(_mediaStore, id); - private int GetId(ContentStore store, Guid uid) => store.LiveSnapshot.Get(uid)?.Id ?? 0; - private Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? Guid.Empty; - #endregion + internal int GetMediaId(Guid udi) => GetId(_mediaStore, udi); + + internal Guid GetDocumentUid(int id) => GetUid(_contentStore, id); + + internal Guid GetMediaUid(int id) => GetUid(_mediaStore, id); + + private int GetId(ContentStore store, Guid uid) => store.LiveSnapshot.Get(uid)?.Id ?? 0; + + private Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? Guid.Empty; /// /// Install phase of @@ -239,172 +197,121 @@ namespace Umbraco.Web.PublishedCache.NuCache lock (_storesLock) { _logger.LogDebug("Releasing content store..."); - _contentStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned + _contentStore?.ReleaseLocalDb(); // null check because we could shut down before being assigned _localContentDb = null; _logger.LogDebug("Releasing media store..."); - _mediaStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned + _mediaStore?.ReleaseLocalDb(); // null check because we could shut down before being assigned _localMediaDb = null; _logger.LogInformation("Released from MainDom"); } } - /// - /// Populates the stores - /// - /// This is called inside of a lock for _storesLock - private void LoadCachesOnStartup() - { - var okContent = false; - var okMedia = false; - - try - { - if (_localContentDbExists) - { - okContent = LockAndLoadContent(scope => LoadContentFromLocalDbLocked(true)); - if (!okContent) - _logger.LogWarning("Loading content from local db raised warnings, will reload from database."); - } - - if (_localMediaDbExists) - { - okMedia = LockAndLoadMedia(scope => LoadMediaFromLocalDbLocked(true)); - if (!okMedia) - _logger.LogWarning("Loading media from local db raised warnings, will reload from database."); - } - - if (!okContent) - LockAndLoadContent(scope => LoadContentFromDatabaseLocked(scope, true)); - - if (!okMedia) - LockAndLoadMedia(scope => LoadMediaFromDatabaseLocked(scope, true)); - - LockAndLoadDomains(); - } - catch (Exception ex) - { - _logger.LogCritical(ex, "Panic, exception while loading cache data."); - throw; - } - - // finally, cache is ready! - _isReady = true; - } - - private void InitializeRepositoryEvents() - { - // TODO: The reason these events are in the repository is for legacy, the events should exist at the service - // level now since we can fire these events within the transaction... so move the events to service level - - // plug repository event handlers - // these trigger within the transaction to ensure consistency - // and are used to maintain the central, database-level XML cache - DocumentRepository.ScopeEntityRemove += OnContentRemovingEntity; - //ContentRepository.RemovedVersion += OnContentRemovedVersion; - DocumentRepository.ScopedEntityRefresh += OnContentRefreshedEntity; - MediaRepository.ScopeEntityRemove += OnMediaRemovingEntity; - //MediaRepository.RemovedVersion += OnMediaRemovedVersion; - MediaRepository.ScopedEntityRefresh += OnMediaRefreshedEntity; - MemberRepository.ScopeEntityRemove += OnMemberRemovingEntity; - //MemberRepository.RemovedVersion += OnMemberRemovedVersion; - MemberRepository.ScopedEntityRefresh += OnMemberRefreshedEntity; - - // plug - ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; - MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity; - MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity; - - LocalizationService.SavedLanguage += OnLanguageSaved; - } - - private void TearDownRepositoryEvents() - { - DocumentRepository.ScopeEntityRemove -= OnContentRemovingEntity; - //ContentRepository.RemovedVersion -= OnContentRemovedVersion; - DocumentRepository.ScopedEntityRefresh -= OnContentRefreshedEntity; - MediaRepository.ScopeEntityRemove -= OnMediaRemovingEntity; - //MediaRepository.RemovedVersion -= OnMediaRemovedVersion; - MediaRepository.ScopedEntityRefresh -= OnMediaRefreshedEntity; - MemberRepository.ScopeEntityRemove -= OnMemberRemovingEntity; - //MemberRepository.RemovedVersion -= OnMemberRemovedVersion; - MemberRepository.ScopedEntityRefresh -= OnMemberRefreshedEntity; - - ContentTypeService.ScopedRefreshedEntity -= OnContentTypeRefreshedEntity; - MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity; - MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity; - - LocalizationService.SavedLanguage -= OnLanguageSaved; - } - - public override void Dispose() - { - TearDownRepositoryEvents(); - _lifeTime.ApplicationInit -= OnApplicationInit; - base.Dispose(); - } - - #endregion - - #region Local files - private string GetLocalFilesPath() { var path = Path.Combine(_hostingEnvironment.LocalTempPath, "NuCache"); if (!Directory.Exists(path)) + { Directory.CreateDirectory(path); + } return path; } private void DeleteLocalFilesForContent() { - if (_isReady && _localContentDb != null) + if (Volatile.Read(ref _isReady) && _localContentDb != null) + { throw new InvalidOperationException("Cannot delete local files while the cache uses them."); + } var path = GetLocalFilesPath(); var localContentDbPath = Path.Combine(path, "NuCache.Content.db"); if (File.Exists(localContentDbPath)) + { File.Delete(localContentDbPath); + } } private void DeleteLocalFilesForMedia() { - if (_isReady && _localMediaDb != null) + if (Volatile.Read(ref _isReady) && _localMediaDb != null) + { throw new InvalidOperationException("Cannot delete local files while the cache uses them."); + } var path = GetLocalFilesPath(); var localMediaDbPath = Path.Combine(path, "NuCache.Media.db"); if (File.Exists(localMediaDbPath)) + { File.Delete(localMediaDbPath); + } } - #endregion + /// + /// Populates the stores + /// + internal void EnsureCaches() => LazyInitializer.EnsureInitialized( + ref _isReady, + ref _isReadSet, + ref _isReadyLock, + () => + { + // even though we are ready locked here we want to ensure that the stores lock is also locked + lock (_storesLock) + { + var okContent = false; + var okMedia = false; - #region Environment + try + { + if (_localContentDbExists) + { + okContent = LockAndLoadContent(() => LoadContentFromLocalDbLocked(true)); + if (!okContent) + { + _logger.LogWarning("Loading content from local db raised warnings, will reload from database."); + } + } - public override bool EnsureEnvironment(out IEnumerable errors) - { - // must have app_data and be able to write files into it - var ok = _ioHelper.TryCreateDirectory(GetLocalFilesPath()); - errors = ok ? Enumerable.Empty() : new[] { "NuCache local files." }; - return ok; - } + if (_localMediaDbExists) + { + okMedia = LockAndLoadMedia(() => LoadMediaFromLocalDbLocked(true)); + if (!okMedia) + { + _logger.LogWarning("Loading media from local db raised warnings, will reload from database."); + } + } - #endregion + if (!okContent) + { + LockAndLoadContent(() => LoadContentFromDatabaseLocked(true)); + } - #region Populate Stores + if (!okMedia) + { + LockAndLoadMedia(() => LoadMediaFromDatabaseLocked(true)); + } + + LockAndLoadDomains(); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "Panic, exception while loading cache data."); + throw; + } + + return true; + } + }); // sudden panic... but in RepeatableRead can a content that I haven't already read, be removed // before I read it? NO! because the WHOLE content tree is read-locked using WithReadLocked. // don't panic. - - private bool LockAndLoadContent(Func action) + private bool LockAndLoadContent(Func action) { - - // first get a writer, then a scope // if there already is a scope, the writer will attach to it // otherwise, it will only exist here - cheap @@ -412,13 +319,13 @@ namespace Umbraco.Web.PublishedCache.NuCache using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.ContentTree); - var ok = action(scope); + var ok = action(); scope.Complete(); return ok; } } - private bool LoadContentFromDatabaseLocked(IScope scope, bool onStartup) + private bool LoadContentFromDatabaseLocked(bool onStartup) { // locks: // contentStore is wlocked (1 thread) @@ -437,7 +344,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _localContentDb?.Clear(); // IMPORTANT GetAllContentSources sorts kits by level + parentId + sortOrder - var kits = _dataSource.GetAllContentSources(scope); + var kits = _publishedContentService.GetAllContentSources(); return onStartup ? _contentStore.SetAllFastSortedLocked(kits, true) : _contentStore.SetAllLocked(kits); } } @@ -457,45 +364,22 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - // keep these around - might be useful - - //private void LoadContentBranch(IContent content) - //{ - // LoadContent(content); - - // foreach (var child in content.Children()) - // LoadContentBranch(child); - //} - - //private void LoadContent(IContent content) - //{ - // var contentService = _serviceContext.ContentService as ContentService; - // var newest = content; - // var published = newest.Published - // ? newest - // : (newest.HasPublishedVersion ? contentService.GetByVersion(newest.PublishedVersionGuid) : null); - - // var contentNode = CreateContentNode(newest, published); - // _contentStore.Set(contentNode); - //} - - private bool LockAndLoadMedia(Func action) + private bool LockAndLoadMedia(Func action) { // see note in LockAndLoadContent using (_mediaStore.GetScopedWriteLock(_scopeProvider)) using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.MediaTree); - var ok = action(scope); + var ok = action(); scope.Complete(); return ok; } } - private bool LoadMediaFromDatabaseLocked(IScope scope, bool onStartup) + private bool LoadMediaFromDatabaseLocked(bool onStartup) { // locks & notes: see content - var mediaTypes = _serviceContext.MediaTypeService.GetAll() .Select(x => _publishedContentTypeFactory.CreateContentType(x)); _mediaStore.SetAllContentTypesLocked(mediaTypes); @@ -504,12 +388,11 @@ namespace Umbraco.Web.PublishedCache.NuCache { // beware! at that point the cache is inconsistent, // assuming we are going to SetAll content items! - _localMediaDb?.Clear(); _logger.LogDebug("Loading media from database..."); // IMPORTANT GetAllMediaSources sorts kits by level + parentId + sortOrder - var kits = _dataSource.GetAllMediaSources(scope); + var kits = _publishedContentService.GetAllMediaSources(); return onStartup ? _mediaStore.SetAllFastSortedLocked(kits, true) : _mediaStore.SetAllLocked(kits); } } @@ -527,7 +410,6 @@ namespace Umbraco.Web.PublishedCache.NuCache return LoadEntitiesFromLocalDbLocked(onStartup, _localMediaDb, _mediaStore, "media"); } - } private bool LoadEntitiesFromLocalDbLocked(bool onStartup, BPlusTree localDb, ContentStore store, string entityType) @@ -562,90 +444,6 @@ namespace Umbraco.Web.PublishedCache.NuCache return onStartup ? store.SetAllFastSortedLocked(kits, false) : store.SetAllLocked(kits); } - // keep these around - might be useful - - //private void LoadMediaBranch(IMedia media) - //{ - // LoadMedia(media); - - // foreach (var child in media.Children()) - // LoadMediaBranch(child); - //} - - //private void LoadMedia(IMedia media) - //{ - // var mediaType = _contentTypeCache.Get(PublishedItemType.Media, media.ContentTypeId); - - // var mediaData = new ContentData - // { - // Name = media.Name, - // Published = true, - // Version = media.Version, - // VersionDate = media.UpdateDate, - // WriterId = media.CreatorId, // what else? - // TemplateId = -1, // have none - // Properties = GetPropertyValues(media) - // }; - - // var mediaNode = new ContentNode(media.Id, mediaType, - // media.Level, media.Path, media.SortOrder, - // media.ParentId, media.CreateDate, media.CreatorId, - // null, mediaData); - - // _mediaStore.Set(mediaNode); - //} - - //private Dictionary GetPropertyValues(IContentBase content) - //{ - // var propertyEditorResolver = PropertyEditorResolver.Current; // should inject - - // return content - // .Properties - // .Select(property => - // { - // var e = propertyEditorResolver.GetByAlias(property.PropertyType.PropertyEditorAlias); - // var v = e == null - // ? property.Value - // : e.ValueEditor.ConvertDbToString(property, property.PropertyType, _serviceContext.DataTypeService); - // return new KeyValuePair(property.Alias, v); - // }) - // .ToDictionary(x => x.Key, x => x.Value); - //} - - //private ContentData CreateContentData(IContent content) - //{ - // return new ContentData - // { - // Name = content.Name, - // Published = content.Published, - // Version = content.Version, - // VersionDate = content.UpdateDate, - // WriterId = content.WriterId, - // TemplateId = content.Template == null ? -1 : content.Template.Id, - // Properties = GetPropertyValues(content) - // }; - //} - - //private ContentNode CreateContentNode(IContent newest, IContent published) - //{ - // var contentType = _contentTypeCache.Get(PublishedItemType.Content, newest.ContentTypeId); - - // var draftData = newest.Published - // ? null - // : CreateContentData(newest); - - // var publishedData = newest.Published - // ? CreateContentData(newest) - // : (published == null ? null : CreateContentData(published)); - - // var contentNode = new ContentNode(newest.Id, contentType, - // newest.Level, newest.Path, newest.SortOrder, - // newest.ParentId, newest.CreateDate, newest.CreatorId, - // draftData, publishedData); - - // return contentNode; - //} - private void LockAndLoadDomains() { // see note in LockAndLoadContent @@ -669,10 +467,6 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - #endregion - - #region Handle Notifications - // note: if the service is not ready, ie _isReady is false, then notifications are ignored // SetUmbracoVersionStep issues a DistributedCache.Instance.RefreshAll...() call which should cause @@ -696,10 +490,10 @@ namespace Umbraco.Web.PublishedCache.NuCache // pure live model factory, if any, locked and refreshed - see ContentTypeCacheRefresher and // DataTypeCacheRefresher - public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) + public void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) { // no cache, trash everything - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) { DeleteLocalFilesForContent(); draftChanged = publishedChanged = true; @@ -713,9 +507,10 @@ namespace Umbraco.Web.PublishedCache.NuCache publishedChanged = publishedChanged2; } - if (draftChanged || publishedChanged) - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); + { + CurrentPublishedSnapshot.Resync(); + } } // Calling this method means we have a lock on the contentStore (i.e. GetScopedWriteLock) @@ -739,7 +534,7 @@ namespace Umbraco.Web.PublishedCache.NuCache using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.ContentTree); - LoadContentFromDatabaseLocked(scope, false); + LoadContentFromDatabaseLocked(false); scope.Complete(); } draftChanged = publishedChanged = true; @@ -770,13 +565,13 @@ namespace Umbraco.Web.PublishedCache.NuCache { // ?? should we do some RV check here? // IMPORTANT GetbranchContentSources sorts kits by level and by sort order - var kits = _dataSource.GetBranchContentSources(scope, capture.Id); + var kits = _publishedContentService.GetBranchContentSources(capture.Id); _contentStore.SetBranchLocked(capture.Id, kits); } else { // ?? should we do some RV check here? - var kit = _dataSource.GetContentSource(scope, capture.Id); + var kit = _publishedContentService.GetContentSource(capture.Id); if (kit.IsEmpty) { _contentStore.ClearLocked(capture.Id); @@ -796,10 +591,10 @@ namespace Umbraco.Web.PublishedCache.NuCache } /// - public override void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) + public void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) { // no cache, trash everything - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) { DeleteLocalFilesForMedia(); anythingChanged = true; @@ -813,7 +608,9 @@ namespace Umbraco.Web.PublishedCache.NuCache } if (anythingChanged) - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); + { + CurrentPublishedSnapshot.Resync(); + } } private void NotifyLocked(IEnumerable payloads, out bool anythingChanged) @@ -832,9 +629,10 @@ namespace Umbraco.Web.PublishedCache.NuCache using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.MediaTree); - LoadMediaFromDatabaseLocked(scope, false); + LoadMediaFromDatabaseLocked(false); scope.Complete(); } + anythingChanged = true; continue; } @@ -842,7 +640,10 @@ namespace Umbraco.Web.PublishedCache.NuCache if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove)) { if (_mediaStore.ClearLocked(payload.Id)) + { anythingChanged = true; + } + continue; } @@ -853,7 +654,6 @@ namespace Umbraco.Web.PublishedCache.NuCache } // TODO: should we do some RV checks here? (later) - var capture = payload; using (var scope = _scopeProvider.CreateScope()) { @@ -863,13 +663,13 @@ namespace Umbraco.Web.PublishedCache.NuCache { // ?? should we do some RV check here? // IMPORTANT GetbranchContentSources sorts kits by level and by sort order - var kits = _dataSource.GetBranchMediaSources(scope, capture.Id); + var kits = _publishedContentService.GetBranchMediaSources(capture.Id); _mediaStore.SetBranchLocked(capture.Id, kits); } else { // ?? should we do some RV check here? - var kit = _dataSource.GetMediaSource(scope, capture.Id); + var kit = _publishedContentService.GetMediaSource(capture.Id); if (kit.IsEmpty) { _mediaStore.ClearLocked(capture.Id); @@ -889,26 +689,30 @@ namespace Umbraco.Web.PublishedCache.NuCache } /// - public override void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) + public void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) { // no cache, nothing we can do - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) + { return; + } foreach (var payload in payloads) + { _logger.LogDebug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id); + } Notify(_contentStore, payloads, RefreshContentTypesLocked); Notify(_mediaStore, payloads, RefreshMediaTypesLocked); if (_publishedModelFactory.IsLiveFactoryEnabled()) { - //In the case of Pure Live - we actually need to refresh all of the content and the media - //see https://github.com/umbraco/Umbraco-CMS/issues/5671 - //The underlying issue is that in Pure Live the ILivePublishedModelFactory will re-compile all of the classes/models - //into a new DLL for the application which includes both content types and media types. - //Since the models in the cache are based on these actual classes, all of the objects in the cache need to be updated - //to use the newest version of the class. + // In the case of Pure Live - we actually need to refresh all of the content and the media + // see https://github.com/umbraco/Umbraco-CMS/issues/5671 + // The underlying issue is that in Pure Live the ILivePublishedModelFactory will re-compile all of the classes/models + // into a new DLL for the application which includes both content types and media types. + // Since the models in the cache are based on these actual classes, all of the objects in the cache need to be updated + // to use the newest version of the class. // NOTE: Ideally this can be run on background threads here which would prevent blocking the UI // as is the case when saving a content type. Intially one would think that it won't be any different @@ -935,13 +739,16 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); + CurrentPublishedSnapshot.Resync(); } private void Notify(ContentStore store, ContentTypeCacheRefresher.JsonPayload[] payloads, Action, List, List, List> action) where T : IContentTypeComposition { - if (payloads.Length == 0) return; //nothing to do + if (payloads.Length == 0) + { + return; // nothing to do + } var nameOfT = typeof(T).Name; @@ -949,40 +756,56 @@ namespace Umbraco.Web.PublishedCache.NuCache foreach (var payload in payloads) { - if (payload.ItemType != nameOfT) continue; + if (payload.ItemType != nameOfT) + { + continue; + } if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.Remove)) + { AddToList(ref removedIds, payload.Id); + } else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshMain)) + { AddToList(ref refreshedIds, payload.Id); + } else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshOther)) + { AddToList(ref otherIds, payload.Id); + } else if (payload.ChangeTypes.HasType(ContentTypeChangeTypes.Create)) + { AddToList(ref newIds, payload.Id); + } } - if (removedIds.IsCollectionEmpty() && refreshedIds.IsCollectionEmpty() && otherIds.IsCollectionEmpty() && newIds.IsCollectionEmpty()) return; + if (removedIds.IsCollectionEmpty() && refreshedIds.IsCollectionEmpty() && otherIds.IsCollectionEmpty() && newIds.IsCollectionEmpty()) + { + return; + } using (store.GetScopedWriteLock(_scopeProvider)) { - // ReSharper disable AccessToModifiedClosure action(removedIds, refreshedIds, otherIds, newIds); - // ReSharper restore AccessToModifiedClosure } } - public override void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) + public void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) { // no cache, nothing we can do - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) + { return; + } var idsA = payloads.Select(x => x.Id).ToArray(); foreach (var payload in payloads) + { _logger.LogDebug("Notified {RemovedStatus} for data type {DataTypeId}", payload.Removed ? "Removed" : "Refreshed", payload.Id); + } using (_contentStore.GetScopedWriteLock(_scopeProvider)) using (_mediaStore.GetScopedWriteLock(_scopeProvider)) @@ -1008,14 +831,16 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - ((PublishedSnapshot)CurrentPublishedSnapshot)?.Resync(); + CurrentPublishedSnapshot.Resync(); } - public override void Notify(DomainCacheRefresher.JsonPayload[] payloads) + public void Notify(DomainCacheRefresher.JsonPayload[] payloads) { // no cache, nothing we can do - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) + { return; + } // see note in LockAndLoadContent using (_domainStore.GetScopedWriteLock(_scopeProvider)) @@ -1048,19 +873,18 @@ namespace Umbraco.Web.PublishedCache.NuCache } } - //Methods used to prevent allocations of lists + // Methods used to prevent allocations of lists private void AddToList(ref List list, int val) => GetOrCreateList(ref list).Add(val); + private List GetOrCreateList(ref List list) => list ?? (list = new List()); - #endregion - - #region Content Types - private IReadOnlyCollection CreateContentTypes(PublishedItemType itemType, int[] ids) { // XxxTypeService.GetAll(empty) returns everything! if (ids.Length == 0) + { return Array.Empty(); + } IEnumerable contentTypes; switch (itemType) @@ -1079,7 +903,6 @@ namespace Umbraco.Web.PublishedCache.NuCache } // some may be missing - not checking here - return contentTypes.Select(x => _publishedContentTypeFactory.CreateContentType(x)).ToList(); } @@ -1107,13 +930,14 @@ namespace Umbraco.Web.PublishedCache.NuCache private void RefreshContentTypesLocked(List removedIds, List refreshedIds, List otherIds, List newIds) { if (removedIds.IsCollectionEmpty() && refreshedIds.IsCollectionEmpty() && otherIds.IsCollectionEmpty() && newIds.IsCollectionEmpty()) + { return; + } // locks: // content (and content types) are read-locked while reading content // contentStore is wlocked (so readable, only no new views) // and it can be wlocked by 1 thread only at a time - using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.ContentTypes); @@ -1124,13 +948,19 @@ namespace Umbraco.Web.PublishedCache.NuCache var kits = refreshedIds.IsCollectionEmpty() ? Array.Empty() - : _dataSource.GetTypeContentSources(scope, refreshedIds).ToArray(); + : _publishedContentService.GetTypeContentSources(refreshedIds).ToArray(); _contentStore.UpdateContentTypesLocked(removedIds, typesA, kits); if (!otherIds.IsCollectionEmpty()) + { _contentStore.UpdateContentTypesLocked(CreateContentTypes(PublishedItemType.Content, otherIds.ToArray())); + } + if (!newIds.IsCollectionEmpty()) + { _contentStore.NewContentTypesLocked(CreateContentTypes(PublishedItemType.Content, newIds.ToArray())); + } + scope.Complete(); } } @@ -1138,13 +968,14 @@ namespace Umbraco.Web.PublishedCache.NuCache private void RefreshMediaTypesLocked(List removedIds, List refreshedIds, List otherIds, List newIds) { if (removedIds.IsCollectionEmpty() && refreshedIds.IsCollectionEmpty() && otherIds.IsCollectionEmpty() && newIds.IsCollectionEmpty()) + { return; + } // locks: // media (and content types) are read-locked while reading media // mediaStore is wlocked (so readable, only no new views) // and it can be wlocked by 1 thread only at a time - using (var scope = _scopeProvider.CreateScope()) { scope.ReadLock(Constants.Locks.MediaTypes); @@ -1155,29 +986,32 @@ namespace Umbraco.Web.PublishedCache.NuCache var kits = refreshedIds == null ? Array.Empty() - : _dataSource.GetTypeMediaSources(scope, refreshedIds).ToArray(); + : _publishedContentService.GetTypeMediaSources(refreshedIds).ToArray(); _mediaStore.UpdateContentTypesLocked(removedIds, typesA, kits); if (!otherIds.IsCollectionEmpty()) + { _mediaStore.UpdateContentTypesLocked(CreateContentTypes(PublishedItemType.Media, otherIds.ToArray()).ToArray()); + } + if (!newIds.IsCollectionEmpty()) + { _mediaStore.NewContentTypesLocked(CreateContentTypes(PublishedItemType.Media, newIds.ToArray()).ToArray()); + } + scope.Complete(); } } - #endregion - - #region Create, Get Published Snapshot - - private long _contentGen, _mediaGen, _domainGen; - private IAppCache _elementsCache; - - public override IPublishedSnapshot CreatePublishedSnapshot(string previewToken) + public IPublishedSnapshot CreatePublishedSnapshot(string previewToken) { + EnsureCaches(); + // no cache, no joy - if (_isReady == false) + if (Volatile.Read(ref _isReady) == false) + { throw new InvalidOperationException("The published snapshot service has not properly initialized."); + } var preview = previewToken.IsNullOrWhiteSpace() == false; return new PublishedSnapshot(this, preview); @@ -1188,6 +1022,8 @@ namespace Umbraco.Web.PublishedCache.NuCache // even though the underlying elements may not change (store snapshots) public PublishedSnapshot.PublishedSnapshotElements GetElements(bool previewDefault) { + EnsureCaches(); + // note: using ObjectCacheAppCache for elements and snapshot caches // is not recommended because it creates an inner MemoryCache which is a heavy // thing - better use a dictionary-based cache which "just" creates a concurrent @@ -1197,7 +1033,6 @@ namespace Umbraco.Web.PublishedCache.NuCache // nothing like that... // for elements cache, DictionaryAppCache is a No-No, use something better. // ie FastDictionaryAppCache (thread safe and all) - ContentStore.Snapshot contentSnap, mediaSnap; SnapDictionary.Snapshot domainSnap; IAppCache elementsCache; @@ -1209,7 +1044,7 @@ namespace Umbraco.Web.PublishedCache.NuCache lock (_elementsLock) { - var scopeContext = _scopeProvider.Context; + IScopeContext scopeContext = _scopeProvider.Context; if (scopeContext == null) { @@ -1239,7 +1074,6 @@ namespace Umbraco.Web.PublishedCache.NuCache }, int.MaxValue); } - // create a new snapshot cache if snapshots are different gens if (contentSnap.Gen != _contentGen || mediaSnap.Gen != _mediaGen || domainSnap.Gen != _domainGen || _elementsCache == null) { @@ -1259,593 +1093,45 @@ namespace Umbraco.Web.PublishedCache.NuCache return new PublishedSnapshot.PublishedSnapshotElements { - ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainCache, Options.Create(_globalSettings), VariationContextAccessor), - MediaCache = new MediaCache(previewDefault, mediaSnap, VariationContextAccessor), - MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer, _publishedModelFactory), + ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainCache, Options.Create(_globalSettings), _variationContextAccessor), + MediaCache = new MediaCache(previewDefault, mediaSnap, _variationContextAccessor), + MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, _publishedSnapshotAccessor, _variationContextAccessor, _entitySerializer, _publishedModelFactory), DomainCache = domainCache, SnapshotCache = snapshotCache, ElementsCache = elementsCache }; } - #endregion + /// + public void Rebuild( + int groupSize = 5000, + IReadOnlyCollection contentTypeIds = null, + IReadOnlyCollection mediaTypeIds = null, + IReadOnlyCollection memberTypeIds = null) + => _publishedContentService.Rebuild(groupSize, contentTypeIds, mediaTypeIds, memberTypeIds); - #region Preview - - public override string EnterPreview(IUser user, int contentId) + public async Task CollectAsync() { - return "preview"; // anything + EnsureCaches(); + + await _contentStore.CollectAsync(); + await _mediaStore.CollectAsync(); } - public override void RefreshPreview(string previewToken, int contentId) + internal ContentStore GetContentStore() { - // nothing + EnsureCaches(); + return _contentStore; } - public override void ExitPreview(string previewToken) + internal ContentStore GetMediaStore() { - // nothing + EnsureCaches(); + return _mediaStore; } - #endregion - - #region Handle Repository Events For Database PreCache - - // note: if the service is not ready, ie _isReady is false, then we still handle repository events, - // because we can, we do not need a working published snapshot to do it - the only reason why it could cause an - // issue is if the database table is not ready, but that should be prevented by migrations. - - // we need them to be "repository" events ie to trigger from within the repository transaction, - // because they need to be consistent with the content that is being refreshed/removed - and that - // should be guaranteed by a DB transaction - - private void OnContentRemovingEntity(DocumentRepository sender, DocumentRepository.ScopedEntityEventArgs args) - { - OnRemovedEntity(args.Scope.Database, args.Entity); - } - - private void OnMediaRemovingEntity(MediaRepository sender, MediaRepository.ScopedEntityEventArgs args) - { - OnRemovedEntity(args.Scope.Database, args.Entity); - } - - private void OnMemberRemovingEntity(MemberRepository sender, MemberRepository.ScopedEntityEventArgs args) - { - OnRemovedEntity(args.Scope.Database, args.Entity); - } - - private void OnRemovedEntity(IUmbracoDatabase db, IContentBase item) - { - db.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id", new { id = item.Id }); - } - - private void OnContentRefreshedEntity(DocumentRepository sender, DocumentRepository.ScopedEntityEventArgs args) - { - var db = args.Scope.Database; - var content = (Content)args.Entity; - - // always refresh the edited data - OnRepositoryRefreshed(db, content, false); - - // if unpublishing, remove published data from table - if (content.PublishedState == PublishedState.Unpublishing) - db.Execute("DELETE FROM cmsContentNu WHERE nodeId=@id AND published=1", new { id = content.Id }); - - // if publishing, refresh the published data - else if (content.PublishedState == PublishedState.Publishing) - OnRepositoryRefreshed(db, content, true); - } - - private void OnMediaRefreshedEntity(MediaRepository sender, MediaRepository.ScopedEntityEventArgs args) - { - var db = args.Scope.Database; - var media = args.Entity; - - // refresh the edited data - OnRepositoryRefreshed(db, media, false); - } - - private void OnMemberRefreshedEntity(MemberRepository sender, MemberRepository.ScopedEntityEventArgs args) - { - var db = args.Scope.Database; - var member = args.Entity; - - // refresh the edited data - OnRepositoryRefreshed(db, member, false); - } - - private void OnRepositoryRefreshed(IUmbracoDatabase db, IContentBase content, bool published) - { - // use a custom SQL to update row version on each update - //db.InsertOrUpdate(dto); - - var dto = GetDto(content, published); - db.InsertOrUpdate(dto, - "SET data=@data, rv=rv+1 WHERE nodeId=@id AND published=@published", - new - { - data = dto.Data, - id = dto.NodeId, - published = dto.Published - }); - } - - private void OnContentTypeRefreshedEntity(IContentTypeService sender, ContentTypeChange.EventArgs args) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; - var contentTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (contentTypeIds.Any()) - RebuildContentDbCache(contentTypeIds: contentTypeIds); - } - - private void OnMediaTypeRefreshedEntity(IMediaTypeService sender, ContentTypeChange.EventArgs args) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; - var mediaTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (mediaTypeIds.Any()) - RebuildMediaDbCache(contentTypeIds: mediaTypeIds); - } - - private void OnMemberTypeRefreshedEntity(IMemberTypeService sender, ContentTypeChange.EventArgs args) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; - var memberTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (memberTypeIds.Any()) - RebuildMemberDbCache(contentTypeIds: memberTypeIds); - } - - /// - /// If a is ever saved with a different culture, we need to rebuild all of the content nucache table - /// - /// - /// - private void OnLanguageSaved(ILocalizationService sender, Core.Events.SaveEventArgs e) - { - //culture changed on an existing language - var cultureChanged = e.SavedEntities.Any(x => !x.WasPropertyDirty(nameof(ILanguage.Id)) && x.WasPropertyDirty(nameof(ILanguage.IsoCode))); - if (cultureChanged) - { - RebuildContentDbCache(); - } - } - - private ContentNuDto GetDto(IContentBase content, bool published) - { - // should inject these in ctor - // BUT for the time being we decide not to support ConvertDbToXml/String - //var propertyEditorResolver = PropertyEditorResolver.Current; - //var dataTypeService = ApplicationContext.Current.Services.DataTypeService; - - var propertyData = new Dictionary(); - foreach (var prop in content.Properties) - { - var pdatas = new List(); - foreach (var pvalue in prop.Values) - { - // sanitize - properties should be ok but ... never knows - if (!prop.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment)) - continue; - - // note: at service level, invariant is 'null', but here invariant becomes 'string.Empty' - var value = published ? pvalue.PublishedValue : pvalue.EditedValue; - if (value != null) - pdatas.Add(new PropertyData { Culture = pvalue.Culture ?? string.Empty, Segment = pvalue.Segment ?? string.Empty, Value = value }); - - //Core.Composing.Current.Logger.Debug($"{content.Id} {prop.Alias} [{pvalue.LanguageId},{pvalue.Segment}] {value} {(published?"pub":"edit")}"); - - //if (value != null) - //{ - // var e = propertyEditorResolver.GetByAlias(prop.PropertyType.PropertyEditorAlias); - - // // We are converting to string, even for database values which are integer or - // // DateTime, which is not optimum. Doing differently would require that we have a way to tell - // // whether the conversion to XML string changes something or not... which we don't, and we - // // don't want to implement it as PropertyValueEditor.ConvertDbToXml/String should die anyway. - - // // Don't think about improving the situation here: this is a corner case and the real - // // thing to do is to get rig of PropertyValueEditor.ConvertDbToXml/String. - - // // Use ConvertDbToString to keep it simple, although everywhere we use ConvertDbToXml and - // // nothing ensures that the two methods are consistent. - - // if (e != null) - // value = e.ValueEditor.ConvertDbToString(prop, prop.PropertyType, dataTypeService); - //} - } - propertyData[prop.Alias] = pdatas.ToArray(); - } - - var cultureData = new Dictionary(); - - // sanitize - names should be ok but ... never knows - if (content.ContentType.VariesByCulture()) - { - var infos = content is IContent document - ? (published - ? document.PublishCultureInfos - : document.CultureInfos) - : content.CultureInfos; - - // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in infos) - { - var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(cultureInfo.Culture); - cultureData[cultureInfo.Culture] = new CultureVariation - { - Name = cultureInfo.Name, - UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders, cultureInfo.Culture), - Date = content.GetUpdateDate(cultureInfo.Culture) ?? DateTime.MinValue, - IsDraft = cultureIsDraft - }; - } - } - - //the dictionary that will be serialized - var nestedData = new ContentNestedData - { - PropertyData = propertyData, - CultureData = cultureData, - UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders) - }; - - var dto = new ContentNuDto - { - NodeId = content.Id, - Published = published, - - // note that numeric values (which are Int32) are serialized without their - // type (eg "value":1234) and JsonConvert by default deserializes them as Int64 - - Data = JsonConvert.SerializeObject(nestedData) - }; - - //Core.Composing.Current.Logger.Debug(dto.Data); - - return dto; - } - - #endregion - - #region Rebuild Database PreCache - - public override void Rebuild() - { - _logger.LogDebug("Rebuilding..."); - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) - { - scope.ReadLock(Constants.Locks.ContentTree); - scope.ReadLock(Constants.Locks.MediaTree); - scope.ReadLock(Constants.Locks.MemberTree); - RebuildContentDbCacheLocked(scope, 5000, null); - RebuildMediaDbCacheLocked(scope, 5000, null); - RebuildMemberDbCacheLocked(scope, 5000, null); - scope.Complete(); - } - } - - public void RebuildContentDbCache(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) - { - scope.ReadLock(Constants.Locks.ContentTree); - RebuildContentDbCacheLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes content tree lock - private void RebuildContentDbCacheLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var contentObjectType = Constants.ObjectTypes.Document; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = contentObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - db.Execute($@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = contentObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - // the tree is locked, counting and comparing to total is safe - var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = new List(); - var count = 0; - foreach (var c in descendants) - { - // always the edited version - items.Add(GetDto(c, false)); - - // and also the published version if it makes any sense - if (c.Published) - items.Add(GetDto(c, true)); - - count++; - } - - db.BulkInsertRecords(items); - processed += count; - } while (processed < total); - } - - public void RebuildMediaDbCache(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) - { - scope.ReadLock(Constants.Locks.MediaTree); - RebuildMediaDbCacheLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes media tree lock - public void RebuildMediaDbCacheLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var mediaObjectType = Constants.ObjectTypes.Media; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = mediaObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - db.Execute($@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = mediaObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - // the tree is locked, counting and comparing to total is safe - var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => GetDto(m, false)).ToList(); - db.BulkInsertRecords(items); - processed += items.Count; - } while (processed < total); - } - - public void RebuildMemberDbCache(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) - { - scope.ReadLock(Constants.Locks.MemberTree); - RebuildMemberDbCacheLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes member tree lock - public void RebuildMemberDbCacheLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var memberObjectType = Constants.ObjectTypes.Member; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = memberObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - db.Execute($@"DELETE FROM cmsContentNu -WHERE cmsContentNu.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = memberObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => GetDto(m, false)).ToArray(); - db.BulkInsertRecords(items); - processed += items.Length; - } while (processed < total); - } - - public bool VerifyContentDbCache() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - var ok = VerifyContentDbCacheLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes content tree lock - private bool VerifyContentDbCacheLocked(IScope scope) - { - // every document should have a corresponding row for edited properties - // and if published, may have a corresponding row for published properties - - var contentObjectType = Constants.ObjectTypes.Document; - var db = scope.Database; - - var count = db.ExecuteScalar($@"SELECT COUNT(*) -FROM umbracoNode -JOIN {Constants.DatabaseSchema.Tables.Document} ON umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId -LEFT JOIN cmsContentNu nuEdited ON (umbracoNode.id=nuEdited.nodeId AND nuEdited.published=0) -LEFT JOIN cmsContentNu nuPublished ON (umbracoNode.id=nuPublished.nodeId AND nuPublished.published=1) -WHERE umbracoNode.nodeObjectType=@objType -AND nuEdited.nodeId IS NULL OR ({Constants.DatabaseSchema.Tables.Document}.published=1 AND nuPublished.nodeId IS NULL);" - , new { objType = contentObjectType }); - - return count == 0; - } - - public bool VerifyMediaDbCache() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MediaTree); - var ok = VerifyMediaDbCacheLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes media tree lock - public bool VerifyMediaDbCacheLocked(IScope scope) - { - // every media item should have a corresponding row for edited properties - - var mediaObjectType = Constants.ObjectTypes.Media; - var db = scope.Database; - - var count = db.ExecuteScalar(@"SELECT COUNT(*) -FROM umbracoNode -LEFT JOIN cmsContentNu ON (umbracoNode.id=cmsContentNu.nodeId AND cmsContentNu.published=0) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsContentNu.nodeId IS NULL -", new { objType = mediaObjectType }); - - return count == 0; - } - - public bool VerifyMemberDbCache() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MemberTree); - var ok = VerifyMemberDbCacheLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes member tree lock - public bool VerifyMemberDbCacheLocked(IScope scope) - { - // every member item should have a corresponding row for edited properties - - var memberObjectType = Constants.ObjectTypes.Member; - var db = scope.Database; - - var count = db.ExecuteScalar(@"SELECT COUNT(*) -FROM umbracoNode -LEFT JOIN cmsContentNu ON (umbracoNode.id=cmsContentNu.nodeId AND cmsContentNu.published=0) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsContentNu.nodeId IS NULL -", new { objType = memberObjectType }); - - return count == 0; - } - - #endregion - - #region Instrument - - public override string GetStatus() - { - var dbCacheIsOk = VerifyContentDbCache() - && VerifyMediaDbCache() - && VerifyMemberDbCache(); - - var cg = _contentStore.GenCount; - var mg = _mediaStore.GenCount; - var cs = _contentStore.SnapCount; - var ms = _mediaStore.SnapCount; - var ce = _contentStore.Count; - var me = _mediaStore.Count; - - return - " Database cache is " + (dbCacheIsOk ? "ok" : "NOT ok (rebuild?)") + "." + - " ContentStore contains " + ce + " item" + (ce > 1 ? "s" : "") + - " and has " + cg + " generation" + (cg > 1 ? "s" : "") + - " and " + cs + " snapshot" + (cs > 1 ? "s" : "") + "." + - " MediaStore contains " + me + " item" + (ce > 1 ? "s" : "") + - " and has " + mg + " generation" + (mg > 1 ? "s" : "") + - " and " + ms + " snapshot" + (ms > 1 ? "s" : "") + "."; - } - - public override void Collect() - { - var contentCollect = _contentStore.CollectAsync(); - var mediaCollect = _mediaStore.CollectAsync(); - System.Threading.Tasks.Task.WaitAll(contentCollect, mediaCollect); - } - - #endregion - - #region Internals/Testing - - internal ContentStore GetContentStore() => _contentStore; - internal ContentStore GetMediaStore() => _mediaStore; - - #endregion + /// + public void Dispose() + { } } } diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotServiceEventHandler.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotServiceEventHandler.cs new file mode 100644 index 0000000000..a8f3f9338b --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotServiceEventHandler.cs @@ -0,0 +1,191 @@ +using System; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Changes; +using Umbraco.Core.Services.Implement; +using Umbraco.Infrastructure.PublishedCache.Persistence; + +namespace Umbraco.Web.PublishedCache.NuCache +{ + /// + /// Subscribes to Umbraco events to ensure nucache remains consistent with the source data + /// + public class PublishedSnapshotServiceEventHandler : IDisposable + { + private readonly IRuntimeState _runtime; + private bool _disposedValue; + private readonly IPublishedSnapshotService _publishedSnapshotService; + private readonly INuCacheContentService _publishedContentService; + + /// + /// Initializes a new instance of the class. + /// + public PublishedSnapshotServiceEventHandler( + IRuntimeState runtime, + IPublishedSnapshotService publishedSnapshotService, + INuCacheContentService publishedContentService) + { + _runtime = runtime; + _publishedSnapshotService = publishedSnapshotService; + _publishedContentService = publishedContentService; + } + + /// + /// Binds to the Umbraco events + /// + /// Returns true if binding occurred + public bool Initialize() + { + // however, the cache is NOT available until we are configured, because loading + // content (and content types) from database cannot be consistent (see notes in "Handle + // Notifications" region), so + // - notifications will be ignored + // - trying to obtain a published snapshot from the service will throw + if (_runtime.Level != RuntimeLevel.Run) + { + return false; + } + + // we always want to handle repository events, configured or not + // assuming no repository event will trigger before the whole db is ready + // (ideally we'd have Upgrading.App vs Upgrading.Data application states...) + InitializeRepositoryEvents(); + + return true; + } + + private void InitializeRepositoryEvents() + { + // TODO: The reason these events are in the repository is for legacy, the events should exist at the service + // level now since we can fire these events within the transaction... so move the events to service level + + // plug repository event handlers + // these trigger within the transaction to ensure consistency + // and are used to maintain the central, database-level XML cache + DocumentRepository.ScopeEntityRemove += OnContentRemovingEntity; + DocumentRepository.ScopedEntityRefresh += DocumentRepository_ScopedEntityRefresh; + MediaRepository.ScopeEntityRemove += OnMediaRemovingEntity; + MediaRepository.ScopedEntityRefresh += MediaRepository_ScopedEntityRefresh; + MemberRepository.ScopeEntityRemove += OnMemberRemovingEntity; + MemberRepository.ScopedEntityRefresh += MemberRepository_ScopedEntityRefresh; + + // plug + ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity; + + // TODO: This should be a cache refresher call! + LocalizationService.SavedLanguage += OnLanguageSaved; + } + + private void TearDownRepositoryEvents() + { + DocumentRepository.ScopeEntityRemove -= OnContentRemovingEntity; + DocumentRepository.ScopedEntityRefresh -= DocumentRepository_ScopedEntityRefresh; + MediaRepository.ScopeEntityRemove -= OnMediaRemovingEntity; + MediaRepository.ScopedEntityRefresh -= MediaRepository_ScopedEntityRefresh; + MemberRepository.ScopeEntityRemove -= OnMemberRemovingEntity; + MemberRepository.ScopedEntityRefresh -= MemberRepository_ScopedEntityRefresh; + ContentTypeService.ScopedRefreshedEntity -= OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity; + LocalizationService.SavedLanguage -= OnLanguageSaved; // TODO: Shouldn't this be a cache refresher event? + } + + // note: if the service is not ready, ie _isReady is false, then we still handle repository events, + // because we can, we do not need a working published snapshot to do it - the only reason why it could cause an + // issue is if the database table is not ready, but that should be prevented by migrations. + + // we need them to be "repository" events ie to trigger from within the repository transaction, + // because they need to be consistent with the content that is being refreshed/removed - and that + // should be guaranteed by a DB transaction + private void OnContentRemovingEntity(DocumentRepository sender, DocumentRepository.ScopedEntityEventArgs args) + => _publishedContentService.DeleteContentItem(args.Entity); + + private void OnMediaRemovingEntity(MediaRepository sender, MediaRepository.ScopedEntityEventArgs args) + => _publishedContentService.DeleteContentItem(args.Entity); + + private void OnMemberRemovingEntity(MemberRepository sender, MemberRepository.ScopedEntityEventArgs args) + => _publishedContentService.DeleteContentItem(args.Entity); + + private void MemberRepository_ScopedEntityRefresh(MemberRepository sender, ContentRepositoryBase.ScopedEntityEventArgs e) + => _publishedContentService.RefreshEntity(e.Entity); + + private void MediaRepository_ScopedEntityRefresh(MediaRepository sender, ContentRepositoryBase.ScopedEntityEventArgs e) + => _publishedContentService.RefreshEntity(e.Entity); + + private void DocumentRepository_ScopedEntityRefresh(DocumentRepository sender, ContentRepositoryBase.ScopedEntityEventArgs e) + => _publishedContentService.RefreshContent(e.Entity); + + private void OnContentTypeRefreshedEntity(IContentTypeService sender, ContentTypeChange.EventArgs args) + { + const ContentTypeChangeTypes types // only for those that have been refreshed + = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; + var contentTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); + if (contentTypeIds.Any()) + { + _publishedSnapshotService.Rebuild(contentTypeIds: contentTypeIds); + } + } + + private void OnMediaTypeRefreshedEntity(IMediaTypeService sender, ContentTypeChange.EventArgs args) + { + const ContentTypeChangeTypes types // only for those that have been refreshed + = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; + var mediaTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); + if (mediaTypeIds.Any()) + { + _publishedSnapshotService.Rebuild(mediaTypeIds: mediaTypeIds); + } + } + + private void OnMemberTypeRefreshedEntity(IMemberTypeService sender, ContentTypeChange.EventArgs args) + { + const ContentTypeChangeTypes types // only for those that have been refreshed + = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther; + var memberTypeIds = args.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); + if (memberTypeIds.Any()) + { + _publishedSnapshotService.Rebuild(memberTypeIds: memberTypeIds); + } + } + + /// + /// If a is ever saved with a different culture, we need to rebuild all of the content nucache database table + /// + private void OnLanguageSaved(ILocalizationService sender, Core.Events.SaveEventArgs e) + { + // culture changed on an existing language + var cultureChanged = e.SavedEntities.Any(x => !x.WasPropertyDirty(nameof(ILanguage.Id)) && x.WasPropertyDirty(nameof(ILanguage.IsoCode))); + if (cultureChanged) + { + // Rebuild all content for all content types + _publishedSnapshotService.Rebuild(contentTypeIds: Array.Empty()); + } + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + TearDownRepositoryEvents(); + } + + _disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotStatus.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotStatus.cs new file mode 100644 index 0000000000..dff40275d8 --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotStatus.cs @@ -0,0 +1,53 @@ +using Umbraco.Infrastructure.PublishedCache.Persistence; + +namespace Umbraco.Web.PublishedCache.NuCache +{ + /// + /// Generates a status report for + /// + internal class PublishedSnapshotStatus : IPublishedSnapshotStatus + { + private readonly PublishedSnapshotService _service; + private readonly INuCacheContentService _publishedContentService; + + public PublishedSnapshotStatus(PublishedSnapshotService service, INuCacheContentService publishedContentService) + { + _service = service; + _publishedContentService = publishedContentService; + } + + /// + public virtual string StatusUrl => "views/dashboard/settings/publishedsnapshotcache.html"; + + /// + public string GetStatus() + { + _service.EnsureCaches(); + + var dbCacheIsOk = _publishedContentService.VerifyContentDbCache() + && _publishedContentService.VerifyMediaDbCache() + && _publishedContentService.VerifyMemberDbCache() + ? "ok" + : "NOT ok (rebuild?)"; + + ContentStore contentStore = _service.GetContentStore(); + ContentStore mediaStore = _service.GetMediaStore(); + + var contentStoreGen = contentStore.GenCount; + var mediaStoreGen = mediaStore.GenCount; + var contentStoreSnap = contentStore.SnapCount; + var mediaStoreSnap = mediaStore.SnapCount; + var contentStoreCount = contentStore.Count; + var mediaStoreCount = mediaStore.Count; + + string contentStoreCountPlural = contentStoreCount > 1 ? "s" : string.Empty; + string contentStoreGenPlural = contentStoreGen > 1 ? "s" : string.Empty; + string contentStoreSnapPlural = contentStoreSnap > 1 ? "s" : string.Empty; + string mediaStoreCountPlural = mediaStoreCount > 1 ? "s" : string.Empty; + string mediaStoreGenPlural = mediaStoreGen > 1 ? "s" : string.Empty; + string mediaStoreSnapPlural = mediaStoreSnap > 1 ? "s" : string.Empty; + + return $" Database cache is {dbCacheIsOk}. ContentStore contains {contentStoreCount} item{contentStoreCountPlural} and has {contentStoreGen} generation{contentStoreGenPlural} and {contentStoreSnap} snapshot{contentStoreSnapPlural}. MediaStore contains {mediaStoreCount} item{mediaStoreCountPlural} and has {mediaStoreGen} generation{mediaStoreGenPlural} and {mediaStoreSnap} snapshot{mediaStoreSnapPlural}."; + } + } +} diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts index 68f31e80bb..22f1f883d0 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts @@ -321,7 +321,7 @@ context('Content', () => { cy.get('.umb-box-content > div > .input-block-level') .find('option[label*=' + new Date().getDate() + ']') .then(elements => { - const option = elements[[elements.length - 1]].getAttribute('value'); + const option = elements[elements.length - 1].getAttribute('value'); cy.get('.umb-box-content > div > .input-block-level') .select(option); }); @@ -521,7 +521,7 @@ context('Content', () => { .done() .done() .build(); - + cy.saveDocumentType(pickedDocType).then((generatedType) => { const pickedContentNode = new ContentBuilder() .withContentTypeAlias(generatedType["alias"]) @@ -563,7 +563,7 @@ context('Content', () => { @{ Layout = null; } - + @{ IPublishedContent typedContentPicker = Model.Value("picker"); if (typedContentPicker != null) diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/dataTypes.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/dataTypes.ts index 5803810f54..53fd55a3fc 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/dataTypes.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/dataTypes.ts @@ -23,7 +23,7 @@ context('Data Types', () => { cy.umbracoEditorHeaderName(name); - cy.get('select[name="selectedEditor"]').select('Label'); + cy.get('select[name="selectedEditor"]', {timeout: 5000}).select('Label'); cy.get('.umb-property-editor select').select('Time'); diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts index da1adedaeb..c586384af7 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts @@ -41,7 +41,7 @@ context('Templates', () => { cy.umbracoSuccessNotification().should('be.visible'); // For some reason cy.umbracoErrorNotification tries to click the element which is not possible // if it doesn't actually exist, making should('not.be.visible') impossible. - cy.get('.umb-notifications__notifications > .alert-error').should('not.be.visible'); + cy.get('.umb-notifications__notifications > .alert-error').should('not.exist'); //Clean up cy.umbracoEnsureTemplateNameNotExists(name); diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 996a0cd2f8..378fe719fc 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -7,10 +7,10 @@ }, "devDependencies": { "cross-env": "^7.0.2", - "cypress": "^5.1.0", + "cypress": "^6.0.1", "ncp": "^2.0.0", - "umbraco-cypress-testhelpers": "^1.0.0-beta-51", - "prompt": "^1.0.0" + "prompt": "^1.0.0", + "umbraco-cypress-testhelpers": "^1.0.0-beta-52" }, "dependencies": { "typescript": "^3.9.2" diff --git a/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs index a781c6ccea..a600d2d962 100644 --- a/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -46,7 +47,9 @@ namespace Umbraco.Tests.Common.Builders Mock.Of(), Mock.Of(), Mock.Of(), - Mock.Of()) + Mock.Of(), + Mock.Of() + ) { DefaultConfiguration = defaultConfiguration, ExplicitConfigurationEditor = explicitConfigurationEditor, diff --git a/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs index cee0931060..61f6c3df78 100644 --- a/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/DataValueEditorBuilder.cs @@ -4,6 +4,7 @@ using System; using Moq; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -56,7 +57,9 @@ namespace Umbraco.Tests.Common.Builders Mock.Of(), Mock.Of(), Mock.Of(), - Mock.Of()) + Mock.Of(), + Mock.Of() + ) { Configuration = configuration, View = view, diff --git a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs index 78aa0c7bc6..b80a2996ca 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs @@ -1,5 +1,6 @@ using Moq; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -16,6 +17,7 @@ namespace Umbraco.Tests.TestHelpers.Entities Mock.Of(), Mock.Of(), Mock.Of(), + new JsonNetSerializer(), new DataEditorAttribute(name, name, name) { ValueType = valueType diff --git a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs index 958b7e558b..e7f6cc4442 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging; using Moq; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -412,11 +411,12 @@ namespace Umbraco.Tests.Common.PublishedContent static AutoPublishedContentType() { - var serializer = new ConfigurationEditorJsonSerializer(); + var configurationEditorJsonSerializer = new ConfigurationEditorJsonSerializer(); + var jsonSerializer = new JsonNetSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + Mock.Of(), Mock.Of(), Mock.Of(), jsonSerializer), configurationEditorJsonSerializer) { Id = 666 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs b/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs index f5983ddca6..4c1101d6f1 100644 --- a/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs +++ b/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs @@ -24,9 +24,8 @@ namespace Umbraco.Tests.Testing public bool Mapper { get => _mapper.ValueOrDefault(WithApplication); set => _mapper.Set(value); } private readonly Settable _mapper = new Settable(); - // FIXME: to be completed /// - /// Gets or sets a value indicating ... + /// Gets or sets a value indicating whether the LEGACY XML Cache used in tests should bind to repository events /// public bool PublishedRepositoryEvents { get => _publishedRepositoryEvents.ValueOrDefault(false); set => _publishedRepositoryEvents.Set(value); } private readonly Settable _publishedRepositoryEvents = new Settable(); diff --git a/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs b/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs new file mode 100644 index 0000000000..ba6c6473fa --- /dev/null +++ b/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs @@ -0,0 +1,76 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; +using Umbraco.Extensions; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Tests.Integration.Extensions; +using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; +using Umbraco.Web.Common.DependencyInjection; + +namespace Umbraco.Tests.Integration +{ + + [TestFixture] + [UmbracoTest(Boot = true)] + public class ComponentRuntimeTests : UmbracoIntegrationTest + { + // ensure composers are added + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddComposers(); + + /// + /// This will boot up umbraco with components enabled to show they initialize and shutdown + /// + [Test] + public async Task Start_And_Stop_Umbraco_With_Components_Enabled() + { + IRuntime runtime = Services.GetRequiredService(); + IRuntimeState runtimeState = Services.GetRequiredService(); + IMainDom mainDom = Services.GetRequiredService(); + ComponentCollection components = Services.GetRequiredService(); + + MyComponent myComponent = components.OfType().First(); + + Assert.IsTrue(mainDom.IsMainDom); + Assert.IsNull(runtimeState.BootFailedException); + Assert.IsTrue(myComponent.IsInit, "The component was not initialized"); + + // force stop now + await runtime.StopAsync(CancellationToken.None); + Assert.IsTrue(myComponent.IsTerminated, "The component was not terminated"); + } + + public class MyComposer : IUserComposer + { + public void Compose(IUmbracoBuilder builder) => builder.Components().Append(); + } + + public class MyComponent : IComponent + { + public bool IsInit { get; private set; } + + public bool IsTerminated { get; private set; } + + private readonly ILogger _logger; + + public MyComponent(ILogger logger) => _logger = logger; + + public void Initialize() => IsInit = true; + + public void Terminate() => IsTerminated = true; + + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs similarity index 64% rename from src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs rename to src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs index dacfd950e0..c1bdf19069 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,70 +1,70 @@ -using Moq; -using NUnit.Framework; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Runtime; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Sync; using Umbraco.Core.WebAssets; using Umbraco.Examine; +using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web.Compose; using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.Scheduling; using Umbraco.Web.Search; -namespace Umbraco.Tests.Integration.Testing +namespace Umbraco.Tests.Integration.DependencyInjection { /// /// This is used to replace certain services that are normally registered from our Core / Infrastructure that /// we do not want active within integration tests /// - /// - /// This is a IUserComposer so that it runs after all core composers - /// - public class IntegrationTestComposer : ComponentComposer + public static class UmbracoBuilderExtensions { - public override void Compose(IUmbracoBuilder builder) + /// + /// Uses/Replaces services with testing services + /// + public static IUmbracoBuilder AddTestServices(this IUmbracoBuilder builder, TestHelper testHelper, AppCaches appCaches = null) { - base.Compose(builder); + builder.Services.AddUnique(appCaches ?? AppCaches.NoCache); + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(testHelper.MainDom); - builder.Components().Remove(); builder.Services.AddUnique(); - builder.Services.AddUnique(factory => Mock.Of()); + builder.Services.AddUnique(factory => Mock.Of()); // we don't want persisted nucache files in tests builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }); +#if IS_WINDOWS // ensure all lucene indexes are using RAM directory (no file system) builder.Services.AddUnique(); +#endif // replace this service so that it can lookup the correct file locations - builder.Services.AddUnique(GetLocalizedTextService); + builder.Services.AddUnique(GetLocalizedTextService); builder.Services.AddUnique(); builder.Services.AddUnique(); + + return builder; } /// /// Used to register a replacement for where the file sources are the ones within the netcore project so /// we don't need to copy files /// - /// - private ILocalizedTextService GetLocalizedTextService(IServiceProvider factory) + private static ILocalizedTextService GetLocalizedTextService(IServiceProvider factory) { var globalSettings = factory.GetRequiredService>(); var loggerFactory = factory.GetRequiredService(); @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Integration.Testing { // get the src folder var currFolder = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); - while(!currFolder.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase)) + while (!currFolder.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase)) { currFolder = currFolder.Parent; } @@ -96,8 +96,8 @@ namespace Umbraco.Tests.Integration.Testing // replace the default so there is no background index rebuilder private class TestBackgroundIndexRebuilder : BackgroundIndexRebuilder { - public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) - : base(mainDom, profilingLogger , loggerFactory, hostingEnvironment, indexRebuilder) + public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) + : base(mainDom, profilingLogger, loggerFactory, hostingEnvironment, indexRebuilder) { } @@ -112,45 +112,49 @@ namespace Umbraco.Tests.Integration.Testing public NoopServerMessenger() { } - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { } - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) { } - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) { } - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) { } - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) { } - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) { } - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) { } - public void PerformRefreshAll(ICacheRefresher refresher) + public void QueueRefreshAll(ICacheRefresher refresher) { } + + public void Sync() { } + + public void SendMessages() { } } } diff --git a/src/Umbraco.Tests.Integration/GlobalSetupTeardown.cs b/src/Umbraco.Tests.Integration/GlobalSetupTeardown.cs index fe1d604dd9..6e86e97770 100644 --- a/src/Umbraco.Tests.Integration/GlobalSetupTeardown.cs +++ b/src/Umbraco.Tests.Integration/GlobalSetupTeardown.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; @@ -23,7 +23,8 @@ public class TestsSetup [OneTimeTearDown] public void TearDown() { - LocalDbTestDatabase.KillLocalDb(); + LocalDbTestDatabase.Instance?.Finish(); + SqlDeveloperTestDatabase.Instance?.Finish(); Console.WriteLine("TOTAL TESTS DURATION: {0}", _stopwatch.Elapsed); } } diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs index fd9ffe5d26..9c2da39076 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -105,7 +105,7 @@ namespace Umbraco.Tests.Integration.Implementations public ILoggerFactory ConsoleLoggerFactory { get; private set; } public IProfilingLogger ProfilingLogger { get; private set; } - public IProfiler Profiler { get; } = new VoidProfiler(); + public IProfiler Profiler { get; } = new NoopProfiler(); public IHttpContextAccessor GetHttpContextAccessor() => _httpContextAccessor; diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs deleted file mode 100644 index 77ee27b8c4..0000000000 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.DependencyInjection; -using Umbraco.Extensions; -using Umbraco.Tests.Integration.Extensions; -using Umbraco.Tests.Integration.Implementations; - -namespace Umbraco.Tests.Integration -{ - - [TestFixture] - public class RuntimeTests - { - [TearDown] - public void TearDown() - { - MyComponent.Reset(); - MyComposer.Reset(); - } - - [SetUp] - public void Setup() - { - MyComponent.Reset(); - MyComposer.Reset(); - } - - /// - /// Calling AddUmbracoCore to configure the container - /// - [Test] - public async Task AddUmbracoCore() - { - var testHelper = new TestHelper(); - - var hostBuilder = new HostBuilder() - .UseUmbraco() - .ConfigureServices((hostContext, services) => - { - var webHostEnvironment = testHelper.GetWebHostEnvironment(); - services.AddSingleton(testHelper.DbProviderFactoryCreator); - services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); - - // Add it! - var typeLoader = services.AddTypeLoader( - GetType().Assembly, - webHostEnvironment, - testHelper.GetHostingEnvironment(), - testHelper.ConsoleLoggerFactory, - AppCaches.NoCache, - hostContext.Configuration, - testHelper.Profiler); - - var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); - builder.Services.AddUnique(AppCaches.NoCache); - builder.AddConfiguration(); - builder.AddUmbracoCore(); - }); - - var host = await hostBuilder.StartAsync(); - var app = new ApplicationBuilder(host.Services); - - // assert results - var runtimeState = app.ApplicationServices.GetRequiredService(); - var mainDom = app.ApplicationServices.GetRequiredService(); - - Assert.IsFalse(mainDom.IsMainDom); // We haven't "Started" the runtime yet - Assert.IsNull(runtimeState.BootFailedException); - Assert.IsFalse(MyComponent.IsInit); // We haven't "Started" the runtime yet - - await host.StopAsync(); - - Assert.IsFalse(MyComponent.IsTerminated); // we didn't "Start" the runtime so nothing was registered for shutdown - } - - /// - /// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime - /// - /// - [Test] - public async Task UseUmbracoCore() - { - var testHelper = new TestHelper(); - - var hostBuilder = new HostBuilder() - .UseUmbraco() - .ConfigureServices((hostContext, services) => - { - var webHostEnvironment = testHelper.GetWebHostEnvironment(); - services.AddSingleton(testHelper.DbProviderFactoryCreator); - services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); - - // Add it! - - var typeLoader = services.AddTypeLoader( - GetType().Assembly, - webHostEnvironment, - testHelper.GetHostingEnvironment(), - testHelper.ConsoleLoggerFactory, - AppCaches.NoCache, - hostContext.Configuration, - testHelper.Profiler); - - var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); - builder.Services.AddUnique(AppCaches.NoCache); - builder.AddConfiguration() - .AddUmbracoCore() - .Build(); - - services.AddRouting(); // LinkGenerator - }); - - var host = await hostBuilder.StartAsync(); - var app = new ApplicationBuilder(host.Services); - - app.UseUmbracoCore(); - - - // assert results - var runtimeState = app.ApplicationServices.GetRequiredService(); - var mainDom = app.ApplicationServices.GetRequiredService(); - - Assert.IsTrue(mainDom.IsMainDom); - Assert.IsNull(runtimeState.BootFailedException); - Assert.IsTrue(MyComponent.IsInit); - - await host.StopAsync(); - - Assert.IsTrue(MyComponent.IsTerminated); - } - - public class MyComposer : IUserComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Components().Append(); - IsComposed = true; - } - - public static void Reset() - { - IsComposed = false; - } - - public static bool IsComposed { get; private set; } - } - - public class MyComponent : IComponent - { - public static bool IsInit { get; private set; } - public static bool IsTerminated { get; private set; } - - private readonly ILogger _logger; - - public MyComponent(ILogger logger) - { - _logger = logger; - } - - public void Initialize() - { - IsInit = true; - } - - public void Terminate() - { - IsTerminated = true; - } - - public static void Reset() - { - IsTerminated = false; - IsInit = false; - } - } - } - - -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb b/src/Umbraco.Tests.Integration/TestData/Packages/Document_Type_Picker_1.1.umb similarity index 100% rename from src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb rename to src/Umbraco.Tests.Integration/TestData/Packages/Document_Type_Picker_1.1.umb diff --git a/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.zip b/src/Umbraco.Tests.Integration/TestData/Packages/Document_Type_Picker_1.1.zip similarity index 100% rename from src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.zip rename to src/Umbraco.Tests.Integration/TestData/Packages/Document_Type_Picker_1.1.zip diff --git a/src/Umbraco.Tests/Packaging/Packages/Hello_1.0.0.zip b/src/Umbraco.Tests.Integration/TestData/Packages/Hello_1.0.0.zip similarity index 100% rename from src/Umbraco.Tests/Packaging/Packages/Hello_1.0.0.zip rename to src/Umbraco.Tests.Integration/TestData/Packages/Hello_1.0.0.zip diff --git a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/BackOfficeAssetsControllerTests.cs b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/BackOfficeAssetsControllerTests.cs index 7c9ab2daf3..9d49ec22fa 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/BackOfficeAssetsControllerTests.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/BackOfficeAssetsControllerTests.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Threading.Tasks; using NUnit.Framework; using Umbraco.Tests.Testing; @@ -7,7 +7,7 @@ using Umbraco.Web.BackOffice.Controllers; namespace Umbraco.Tests.Integration.TestServerTest.Controllers { [TestFixture] - public class BackOfficeAssetsControllerTests: UmbracoTestServerTestBase + public class BackOfficeAssetsControllerTests : UmbracoTestServerTestBase { [Test] public async Task EnsureSuccessStatusCode() diff --git a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs index 731079da7c..f9d5d9f7da 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -22,13 +22,12 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers /// /// Returns 404 if the content wasn't found based on the ID specified /// - /// [Test] public async Task PostSave_Validate_Existing_Content() { var localizationService = GetRequiredService(); - //Add another language + // Add another language localizationService.Save(new LanguageBuilder() .WithCultureInfo("da-DK") .WithIsDefault(false) @@ -76,10 +75,10 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers // Assert Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); -// Assert.AreEqual(")]}',\n{\"Message\":\"content was not found\"}", response.Item1.Content.ReadAsStringAsync().Result); -// -// //var obj = JsonConvert.DeserializeObject>(response.Item2); -// //Assert.AreEqual(0, obj.TotalItems); + // Assert.AreEqual(")]}',\n{\"Message\":\"content was not found\"}", response.Item1.Content.ReadAsStringAsync().Result); + // + // //var obj = JsonConvert.DeserializeObject>(response.Item2); + // //Assert.AreEqual(0, obj.TotalItems); } [Test] @@ -88,7 +87,7 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers var localizationService = GetRequiredService(); - //Add another language + // Add another language localizationService.Save(new LanguageBuilder() .WithCultureInfo("da-DK") .WithIsDefault(false) @@ -96,7 +95,6 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers var url = PrepareUrl(x => x.PostSave(null)); - var contentTypeService = GetRequiredService(); var contentType = new ContentTypeBuilder() @@ -128,7 +126,7 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers .Build(); // HERE we force the test to fail - model.Variants = model.Variants.Select(x=> + model.Variants = model.Variants.Select(x => { x.Save = false; return x; @@ -141,13 +139,12 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers }); // Assert - var body = await response.Content.ReadAsStringAsync(); Assert.Multiple(() => { Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); - Assert.AreEqual(")]}',\n{\"Message\":\"No variants flagged for saving\"}", body); + Assert.AreEqual(AngularJsonMediaTypeFormatter.XsrfPrefix + "{\"Message\":\"No variants flagged for saving\"}", body); }); } @@ -155,13 +152,12 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers /// /// Returns 404 if any of the posted properties dont actually exist /// - /// [Test] public async Task PostSave_Validate_Properties_Exist() { var localizationService = GetRequiredService(); - //Add another language + // Add another language localizationService.Save(new LanguageBuilder() .WithCultureInfo("da-DK") .WithIsDefault(false) @@ -215,12 +211,11 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers }); // Assert - var body = await response.Content.ReadAsStringAsync(); body = body.TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix); - Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); + Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); } [Test] diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs deleted file mode 100644 index 0fcf47978a..0000000000 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Moq; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Runtime; -using Umbraco.Tests.Integration.Implementations; - -namespace Umbraco.Tests.Integration.TestServerTest -{ - public static class UmbracoBuilderExtensions - { - /// - /// Uses a test version of Umbraco Core with a test IRuntime - /// - /// - /// - public static IUmbracoBuilder AddTestCore(this IUmbracoBuilder builder, TestHelper testHelper) - { - builder.AddUmbracoCore(); - - builder.Services.AddUnique(AppCaches.NoCache); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(testHelper.MainDom); - - return builder; - } - } -} diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 6e2e139f69..44f83b3ba7 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -1,8 +1,6 @@ - using System; using System.Linq.Expressions; using System.Net.Http; -using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -11,20 +9,23 @@ using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Tests.Integration.DependencyInjection; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; -using Umbraco.Core.DependencyInjection; -using Umbraco.Web.Common.Controllers; -using Microsoft.Extensions.Hosting; -using Umbraco.Core.Cache; -using Umbraco.Core.Persistence; -using Umbraco.Core.Runtime; using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.DependencyInjection; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Common.DependencyInjection; +using Umbraco.Web.Website.Controllers; +using Umbraco.Web.Website.DependencyInjection; namespace Umbraco.Tests.Integration.TestServerTest { @@ -39,7 +40,7 @@ namespace Umbraco.Tests.Integration.TestServerTest InMemoryConfiguration["Umbraco:CMS:Hosting:Debug"] = "true"; // create new WebApplicationFactory specifying 'this' as the IStartup instance - var factory = new UmbracoWebApplicationFactory(CreateHostBuilder); + var factory = new UmbracoWebApplicationFactory(CreateHostBuilder, BeforeHostStart); // additional host configuration for web server integration tests Factory = factory.WithWebHostBuilder(builder => @@ -75,11 +76,10 @@ namespace Umbraco.Tests.Integration.TestServerTest // call startup builder.Configure(app => { - UseTestLocalDb(app.ApplicationServices); - Services = app.ApplicationServices; Configure(app); }); - }).UseEnvironment(Environments.Development); + + }).UseEnvironment(Environments.Development); return builder; } @@ -116,53 +116,58 @@ namespace Umbraco.Tests.Integration.TestServerTest } protected HttpClient Client { get; private set; } + protected LinkGenerator LinkGenerator { get; private set; } + protected WebApplicationFactory Factory { get; private set; } - [TearDown] - public override void TearDown() - { - base.TearDown(); - base.TerminateCoreRuntime(); - - Factory.Dispose(); - } - - #region IStartup - public override void ConfigureServices(IServiceCollection services) { - var typeLoader = services.AddTypeLoader(GetType().Assembly, TestHelper.GetWebHostEnvironment(), TestHelper.GetHostingEnvironment(), - TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration, TestHelper.Profiler); + services.AddTransient(); + var typeLoader = services.AddTypeLoader( + GetType().Assembly, + TestHelper.GetWebHostEnvironment(), + TestHelper.GetHostingEnvironment(), + TestHelper.ConsoleLoggerFactory, + AppCaches.NoCache, + Configuration, + TestHelper.Profiler); var builder = new UmbracoBuilder(services, Configuration, typeLoader); - + builder .AddConfiguration() - .AddTestCore(TestHelper) // This is the important one! + .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() - .AddBackOffice() + .AddBackOfficeCore() + .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddMembersIdentity() .AddBackOfficeAuthorizationPolicies(TestAuthHandler.TestAuthenticationScheme) .AddPreviewSupport() - //.WithMiniProfiler() // we don't want this running in tests .AddMvcAndRazor(mvcBuilding: mvcBuilder => { + // Adds Umbraco.Web.BackOffice mvcBuilder.AddApplicationPart(typeof(ContentController).Assembly); + + // Adds Umbraco.Web.Common + mvcBuilder.AddApplicationPart(typeof(RenderController).Assembly); + + // Adds Umbraco.Web.Website + mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly); }) .AddWebServer() + .AddWebsite() + .AddTestServices(TestHelper) // This is the important one! .Build(); } public override void Configure(IApplicationBuilder app) { app.UseUmbraco(); + app.UseUmbracoBackOffice(); + app.UseUmbracoWebsite(); } - - #endregion - - } } diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs index 251f155d2c..256c5c59a9 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Hosting; @@ -8,16 +8,30 @@ namespace Umbraco.Tests.Integration.TestServerTest public class UmbracoWebApplicationFactory : WebApplicationFactory where TStartup : class { private readonly Func _createHostBuilder; + private readonly Action _beforeStart; /// /// Constructor to create a new WebApplicationFactory /// /// Method to create the IHostBuilder - public UmbracoWebApplicationFactory(Func createHostBuilder) + /// Method to perform an action before IHost starts + public UmbracoWebApplicationFactory(Func createHostBuilder, Action beforeStart = null) { _createHostBuilder = createHostBuilder; + _beforeStart = beforeStart; } protected override IHostBuilder CreateHostBuilder() => _createHostBuilder(); + + protected override IHost CreateHost(IHostBuilder builder) + { + IHost host = builder.Build(); + + _beforeStart?.Invoke(host); + + host.Start(); + + return host; + } } } diff --git a/src/Umbraco.Tests.Integration/Testing/BaseTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/BaseTestDatabase.cs new file mode 100644 index 0000000000..52a0778a59 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/BaseTestDatabase.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Configuration; +using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Persistence; + +namespace Umbraco.Tests.Integration.Testing +{ + public abstract class BaseTestDatabase + { + protected ILoggerFactory _loggerFactory; + protected IUmbracoDatabaseFactory _databaseFactory; + protected IList _testDatabases; + + protected const int _threadCount = 2; + + protected UmbracoDatabase.CommandInfo[] _cachedDatabaseInitCommands = new UmbracoDatabase.CommandInfo[0]; + + protected BlockingCollection _prepareQueue; + protected BlockingCollection _readySchemaQueue; + protected BlockingCollection _readyEmptyQueue; + + protected abstract void Initialize(); + + public TestDbMeta AttachEmpty() + { + if (_prepareQueue == null) + { + Initialize(); + } + + return _readyEmptyQueue.Take(); + } + + public TestDbMeta AttachSchema() + { + if (_prepareQueue == null) + { + Initialize(); + } + + return _readySchemaQueue.Take(); + } + + public void Detach(TestDbMeta meta) + { + _prepareQueue.TryAdd(meta); + } + + protected void PrepareDatabase() + { + Retry(10, () => + { + while (_prepareQueue.IsCompleted == false) + { + TestDbMeta meta; + try + { + meta = _prepareQueue.Take(); + } + catch (InvalidOperationException) + { + continue; + } + + using (var conn = new SqlConnection(meta.ConnectionString)) + using (var cmd = conn.CreateCommand()) + { + conn.Open(); + ResetTestDatabase(cmd); + + if (!meta.IsEmpty) + { + RebuildSchema(cmd, meta); + } + } + + if (!meta.IsEmpty) + { + _readySchemaQueue.TryAdd(meta); + } + else + { + _readyEmptyQueue.TryAdd(meta); + } + } + }); + } + + private void RebuildSchema(IDbCommand command, TestDbMeta meta) + { + lock (_cachedDatabaseInitCommands) + { + if (!_cachedDatabaseInitCommands.Any()) + { + RebuildSchemaFirstTime(command, meta); + return; + } + } + + foreach (var dbCommand in _cachedDatabaseInitCommands) + { + if (dbCommand.Text.StartsWith("SELECT ")) + { + continue; + } + + command.CommandText = dbCommand.Text; + command.Parameters.Clear(); + + foreach (var parameterInfo in dbCommand.Parameters) + { + AddParameter(command, parameterInfo); + } + + command.ExecuteNonQuery(); + } + } + + private void RebuildSchemaFirstTime(IDbCommand command, TestDbMeta meta) + { + _databaseFactory.Configure(meta.ConnectionString, Core.Constants.DatabaseProviders.SqlServer); + + using (var database = (UmbracoDatabase)_databaseFactory.CreateDatabase()) + { + database.LogCommands = true; + + using (var transaction = database.GetTransaction()) + { + var schemaCreator = new DatabaseSchemaCreator(database, _loggerFactory.CreateLogger(), _loggerFactory, new UmbracoVersion()); + schemaCreator.InitializeDatabaseSchema(); + + transaction.Complete(); + + _cachedDatabaseInitCommands = database.Commands.ToArray(); + } + } + } + + protected static void SetCommand(SqlCommand command, string sql, params object[] args) + { + command.CommandType = CommandType.Text; + command.CommandText = sql; + command.Parameters.Clear(); + + for (var i = 0; i < args.Length; i++) + { + command.Parameters.AddWithValue("@" + i, args[i]); + } + } + + protected static void AddParameter(IDbCommand cmd, UmbracoDatabase.ParameterInfo parameterInfo) + { + var p = cmd.CreateParameter(); + p.ParameterName = parameterInfo.Name; + p.Value = parameterInfo.Value; + p.DbType = parameterInfo.DbType; + p.Size = parameterInfo.Size; + cmd.Parameters.Add(p); + } + + protected static void ResetTestDatabase(IDbCommand cmd) + { + // https://stackoverflow.com/questions/536350 + + cmd.CommandType = CommandType.Text; + cmd.CommandText = @" + declare @n char(1); + set @n = char(10); + declare @stmt nvarchar(max); + -- check constraints + select @stmt = isnull( @stmt + @n, '' ) + + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']' + from sys.check_constraints; + -- foreign keys + select @stmt = isnull( @stmt + @n, '' ) + + 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']' + from sys.foreign_keys; + -- tables + select @stmt = isnull( @stmt + @n, '' ) + + 'drop table [' + schema_name(schema_id) + '].[' + name + ']' + from sys.tables; + exec sp_executesql @stmt; + "; + + // rudimentary retry policy since a db can still be in use when we try to drop + Retry(10, () => cmd.ExecuteNonQuery()); + } + + protected static void Retry(int maxIterations, Action action) + { + for (var i = 0; i < maxIterations; i++) + { + try + { + action(); + return; + } + catch (SqlException) + { + + //Console.Error.WriteLine($"SqlException occured, but we try again {i+1}/{maxIterations}.\n{e}"); + // This can occur when there's a transaction deadlock which means (i think) that the database is still in use and hasn't been closed properly yet + // so we need to just wait a little bit + Thread.Sleep(100 * i); + if (i == maxIterations - 1) + { + Debugger.Launch(); + throw; + } + } + catch (InvalidOperationException) + { + // Ignore + } + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/ITestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/ITestDatabase.cs new file mode 100644 index 0000000000..28d7e9c8bc --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/ITestDatabase.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Tests.Integration.Testing +{ + public interface ITestDatabase + { + TestDbMeta AttachEmpty(); + TestDbMeta AttachSchema(); + void Detach(TestDbMeta id); + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs index 39f9ca5592..59a9b00215 100644 --- a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs +++ b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs @@ -1,18 +1,8 @@ -using System; +using System; using System.Collections.Concurrent; -using System.Configuration; -using System.Data; -using System.Data.Common; -using System.Data.SqlClient; -using System.Diagnostics; using System.IO; -using System.Linq; using System.Threading; using Microsoft.Extensions.Logging; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; namespace Umbraco.Tests.Integration.Testing @@ -20,197 +10,112 @@ namespace Umbraco.Tests.Integration.Testing /// /// Manages a pool of LocalDb databases for integration testing /// - public class LocalDbTestDatabase + public class LocalDbTestDatabase : BaseTestDatabase, ITestDatabase { public const string InstanceName = "UmbracoTests"; public const string DatabaseName = "UmbracoTests"; - private readonly ILoggerFactory _loggerFactory; private readonly LocalDb _localDb; - private readonly IUmbracoVersion _umbracoVersion; - private static LocalDb.Instance _instance; + private static LocalDb.Instance _localDbInstance; private static string _filesPath; - private readonly IUmbracoDatabaseFactory _dbFactory; - private UmbracoDatabase.CommandInfo[] _dbCommands; - private string _currentCstr; - private static DatabasePool _emptyPool; - private static DatabasePool _schemaPool; - private DatabasePool _currentPool; + + public static LocalDbTestDatabase Instance { get; private set; } //It's internal because `Umbraco.Core.Persistence.LocalDb` is internal internal LocalDbTestDatabase(ILoggerFactory loggerFactory, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory) { - _umbracoVersion = new UmbracoVersion(); _loggerFactory = loggerFactory; + _databaseFactory = dbFactory; + _localDb = localDb; _filesPath = filesPath; - _dbFactory = dbFactory; - _instance = _localDb.GetInstance(InstanceName); - if (_instance != null) return; + Instance = this; // For GlobalSetupTeardown.cs + + _testDatabases = new[] + { + // With Schema + TestDbMeta.CreateWithoutConnectionString($"{DatabaseName}-1", false), + TestDbMeta.CreateWithoutConnectionString($"{DatabaseName}-2", false), + + // Empty (for migration testing etc) + TestDbMeta.CreateWithoutConnectionString($"{DatabaseName}-3", true), + TestDbMeta.CreateWithoutConnectionString($"{DatabaseName}-4", true), + }; + + _localDbInstance = _localDb.GetInstance(InstanceName); + if (_localDbInstance != null) + { + return; + } if (_localDb.CreateInstance(InstanceName) == false) + { throw new Exception("Failed to create a LocalDb instance."); - _instance = _localDb.GetInstance(InstanceName); + } + + _localDbInstance = _localDb.GetInstance(InstanceName); } - public string ConnectionString => _currentCstr ?? _instance.GetAttachedConnectionString("XXXXXX", _filesPath); - - private void Create() + protected override void Initialize() { var tempName = Guid.NewGuid().ToString("N"); - _instance.CreateDatabase(tempName, _filesPath); - _instance.DetachDatabase(tempName); + _localDbInstance.CreateDatabase(tempName, _filesPath); + _localDbInstance.DetachDatabase(tempName); - // there's probably a sweet spot to be found for size / parallel... + _prepareQueue = new BlockingCollection(); + _readySchemaQueue = new BlockingCollection(); + _readyEmptyQueue = new BlockingCollection(); - var s = ConfigurationManager.AppSettings["Umbraco.Tests.LocalDbTestDatabase.EmptyPoolSize"]; - var emptySize = s == null ? 1 : int.Parse(s); - s = ConfigurationManager.AppSettings["Umbraco.Tests.LocalDbTestDatabase.EmptyPoolThreadCount"]; - var emptyParallel = s == null ? 1 : int.Parse(s); - s = ConfigurationManager.AppSettings["Umbraco.Tests.LocalDbTestDatabase.SchemaPoolSize"]; - var schemaSize = s == null ? 1 : int.Parse(s); - s = ConfigurationManager.AppSettings["Umbraco.Tests.LocalDbTestDatabase.SchemaPoolThreadCount"]; - var schemaParallel = s == null ? 1 : int.Parse(s); - - _emptyPool = new DatabasePool(_localDb, _instance, DatabaseName + "-Empty", tempName, _filesPath, emptySize, emptyParallel); - _schemaPool = new DatabasePool(_localDb, _instance, DatabaseName + "-Schema", tempName, _filesPath, schemaSize, schemaParallel, delete: true, prepare: RebuildSchema); - } - - public int AttachEmpty() - { - if (_emptyPool == null) - Create(); - - _currentCstr = _emptyPool.AttachDatabase(out var id); - _currentPool = _emptyPool; - return id; - } - - public int AttachSchema() - { - if (_schemaPool == null) - Create(); - - _currentCstr = _schemaPool.AttachDatabase(out var id); - _currentPool = _schemaPool; - return id; - } - - public void Detach(int id) - { - _currentPool.DetachDatabase(id); - } - - private void RebuildSchema(DbConnection conn, IDbCommand cmd) - { - - if (_dbCommands != null) + for (var i = 0; i < _testDatabases.Count; i++) { - foreach (var dbCommand in _dbCommands) - { + var meta = _testDatabases[i]; + var isLast = i == _testDatabases.Count - 1; - if (dbCommand.Text.StartsWith("SELECT ")) continue; - - cmd.CommandText = dbCommand.Text; - cmd.Parameters.Clear(); - foreach (var parameterInfo in dbCommand.Parameters) - AddParameter(cmd, parameterInfo); - cmd.ExecuteNonQuery(); - } - } - else - { - _dbFactory.Configure(conn.ConnectionString, Constants.DatabaseProviders.SqlServer); - - using var database = (UmbracoDatabase)_dbFactory.CreateDatabase(); - // track each db command ran as part of creating the database so we can replay these - database.LogCommands = true; - - using var trans = database.GetTransaction(); - - var creator = new DatabaseSchemaCreator(database, _loggerFactory.CreateLogger(), _loggerFactory, _umbracoVersion); - creator.InitializeDatabaseSchema(); - - trans.Complete(); // commit it - - _dbCommands = database.Commands.ToArray(); + _localDb.CopyDatabaseFiles(tempName, _filesPath, targetDatabaseName: meta.Name, overwrite: true, delete: isLast); + meta.ConnectionString = _localDbInstance.GetAttachedConnectionString(meta.Name, _filesPath); + _prepareQueue.Add(meta); } - } - - private static void AddParameter(IDbCommand cmd, UmbracoDatabase.ParameterInfo parameterInfo) - { - var p = cmd.CreateParameter(); - p.ParameterName = parameterInfo.Name; - p.Value = parameterInfo.Value; - p.DbType = parameterInfo.DbType; - p.Size = parameterInfo.Size; - cmd.Parameters.Add(p); - } - - public void Clear() - { - var filename = Path.Combine(_filesPath, DatabaseName).ToUpper(); - - foreach (var database in _instance.GetDatabases()) + for (var i = 0; i < _threadCount; i++) { - if (database.StartsWith(filename)) - _instance.DropDatabase(database); - } - - foreach (var file in Directory.EnumerateFiles(_filesPath)) - { - if (file.EndsWith(".mdf") == false && file.EndsWith(".ldf") == false) continue; - File.Delete(file); + var thread = new Thread(PrepareDatabase); + thread.Start(); } } - private static void ResetLocalDb(IDbCommand cmd) + public void Finish() { - // https://stackoverflow.com/questions/536350 - - cmd.CommandType = CommandType.Text; - cmd.CommandText = @" - declare @n char(1); - set @n = char(10); - declare @stmt nvarchar(max); - -- check constraints - select @stmt = isnull( @stmt + @n, '' ) + - 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']' - from sys.check_constraints; - -- foreign keys - select @stmt = isnull( @stmt + @n, '' ) + - 'alter table [' + schema_name(schema_id) + '].[' + object_name( parent_object_id ) + '] drop constraint [' + name + ']' - from sys.foreign_keys; - -- tables - select @stmt = isnull( @stmt + @n, '' ) + - 'drop table [' + schema_name(schema_id) + '].[' + name + ']' - from sys.tables; - exec sp_executesql @stmt; - "; - - // rudimentary retry policy since a db can still be in use when we try to drop - Retry(10, () => + if (_prepareQueue == null) { - cmd.ExecuteNonQuery(); - }); - } + return; + } - public static void KillLocalDb() - { - _emptyPool?.Stop(); - _schemaPool?.Stop(); + _prepareQueue.CompleteAdding(); + while (_prepareQueue.TryTake(out _)) + { } + + _readyEmptyQueue.CompleteAdding(); + while (_readyEmptyQueue.TryTake(out _)) + { } + + _readySchemaQueue.CompleteAdding(); + while (_readySchemaQueue.TryTake(out _)) + { } if (_filesPath == null) + { return; + } var filename = Path.Combine(_filesPath, DatabaseName).ToUpper(); - foreach (var database in _instance.GetDatabases()) + foreach (var database in _localDbInstance.GetDatabases()) { if (database.StartsWith(filename)) - _instance.DropDatabase(database); + { + _localDbInstance.DropDatabase(database); + } } foreach (var file in Directory.EnumerateFiles(_filesPath)) @@ -226,145 +131,5 @@ namespace Umbraco.Tests.Integration.Testing } } } - - private static void Retry(int maxIterations, Action action) - { - for (var i = 0; i < maxIterations; i++) - { - try - { - action(); - return; - } - catch (SqlException) - { - - //Console.Error.WriteLine($"SqlException occured, but we try again {i+1}/{maxIterations}.\n{e}"); - // This can occur when there's a transaction deadlock which means (i think) that the database is still in use and hasn't been closed properly yet - // so we need to just wait a little bit - Thread.Sleep(100 * i); - if (i == maxIterations - 1) - { - Debugger.Launch(); - throw; - } - } - catch (InvalidOperationException) - { - - } - } - } - - private class DatabasePool - { - private readonly LocalDb _localDb; - private readonly LocalDb.Instance _instance; - private readonly string _filesPath; - private readonly string _name; - private readonly int _size; - private readonly string[] _cstrs; - private readonly BlockingCollection _prepareQueue, _readyQueue; - private readonly Action _prepare; - private int _current; - - public DatabasePool(LocalDb localDb, LocalDb.Instance instance, string name, string tempName, string filesPath, int size, int parallel = 1, Action prepare = null, bool delete = false) - { - _localDb = localDb; - _instance = instance; - _filesPath = filesPath; - _name = name; - _size = size; - _prepare = prepare; - _prepareQueue = new BlockingCollection(); - _readyQueue = new BlockingCollection(); - _cstrs = new string[_size]; - - for (var i = 0; i < size; i++) - localDb.CopyDatabaseFiles(tempName, filesPath, targetDatabaseName: name + "-" + i, overwrite: true, delete: delete && i == size - 1); - - if (prepare == null) - { - for (var i = 0; i < size; i++) - _readyQueue.Add(i); - } - else - { - for (var i = 0; i < size; i++) - _prepareQueue.Add(i); - } - - for (var i = 0; i < parallel; i++) - { - var thread = new Thread(PrepareThread); - thread.Start(); - } - } - - public string AttachDatabase(out int id) - { - _current = _readyQueue.Take(); - id = _current; - - return ConnectionString(_current); - } - - public void DetachDatabase(int id) - { - if (id != _current) - throw new InvalidOperationException("Cannot detatch the non-current db"); - - _prepareQueue.Add(_current); - } - - private string ConnectionString(int i) - { - return _cstrs[i] ?? (_cstrs[i] = _instance.GetAttachedConnectionString(_name + "-" + i, _filesPath)); - } - - private void PrepareThread() - { - Retry(10, () => - { - while (_prepareQueue.IsCompleted == false) - { - int i; - try - { - i = _prepareQueue.Take(); - } - catch (InvalidOperationException) - { - continue; - } - - using (var conn = new SqlConnection(ConnectionString(i))) - using (var cmd = conn.CreateCommand()) - { - conn.Open(); - ResetLocalDb(cmd); - - _prepare?.Invoke(conn, cmd); - - } - - if (!_readyQueue.IsAddingCompleted) - { - _readyQueue.Add(i); - } - } - }); - } - - public void Stop() - { - int i; - _prepareQueue.CompleteAdding(); - while (_prepareQueue.TryTake(out i)) { } - _readyQueue.CompleteAdding(); - while (_readyQueue.TryTake(out i)) { } - } - } - } } diff --git a/src/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs new file mode 100644 index 0000000000..2e1f75cd45 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Concurrent; +using System.Data.SqlClient; +using System.Threading; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Persistence; + +// ReSharper disable ConvertToUsingDeclaration + +namespace Umbraco.Tests.Integration.Testing +{ + /// + /// It's not meant to be pretty, rushed port of LocalDb.cs + LocalDbTestDatabase.cs + /// + public class SqlDeveloperTestDatabase : BaseTestDatabase, ITestDatabase + { + private readonly string _masterConnectionString; + public const string DatabaseName = "UmbracoTests"; + + public static SqlDeveloperTestDatabase Instance { get; private set; } + + public SqlDeveloperTestDatabase(ILoggerFactory loggerFactory, IUmbracoDatabaseFactory databaseFactory, string masterConnectionString) + { + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + _databaseFactory = databaseFactory ?? throw new ArgumentNullException(nameof(databaseFactory)); + + _masterConnectionString = masterConnectionString; + + _testDatabases = new[] + { + // With Schema + TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-1", false, masterConnectionString), + TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-2", false, masterConnectionString), + + // Empty (for migration testing etc) + TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-3", true, masterConnectionString), + TestDbMeta.CreateWithMasterConnectionString($"{DatabaseName}-4", true, masterConnectionString), + }; + + Instance = this; // For GlobalSetupTeardown.cs + } + + protected override void Initialize() + { + _prepareQueue = new BlockingCollection(); + _readySchemaQueue = new BlockingCollection(); + _readyEmptyQueue = new BlockingCollection(); + + foreach (var meta in _testDatabases) + { + CreateDatabase(meta); + _prepareQueue.Add(meta); + } + + for (var i = 0; i < _threadCount; i++) + { + var thread = new Thread(PrepareDatabase); + thread.Start(); + } + } + + private void CreateDatabase(TestDbMeta meta) + { + using (var connection = new SqlConnection(_masterConnectionString)) + { + connection.Open(); + using (var command = connection.CreateCommand()) + { + SetCommand(command, $@"CREATE DATABASE {LocalDb.QuotedName(meta.Name)}"); + command.ExecuteNonQuery(); + } + } + } + + private void Drop(TestDbMeta meta) + { + using (var connection = new SqlConnection(_masterConnectionString)) + { + connection.Open(); + using (var command = connection.CreateCommand()) + { + SetCommand(command, $@" + ALTER DATABASE{LocalDb.QuotedName(meta.Name)} + SET SINGLE_USER + WITH ROLLBACK IMMEDIATE + "); + command.ExecuteNonQuery(); + + SetCommand(command, $@"DROP DATABASE {LocalDb.QuotedName(meta.Name)}"); + command.ExecuteNonQuery(); + } + } + } + + public void Finish() + { + if (_prepareQueue == null) + return; + + _prepareQueue.CompleteAdding(); + while (_prepareQueue.TryTake(out _)) { } + + _readyEmptyQueue.CompleteAdding(); + while (_readyEmptyQueue.TryTake(out _)) { } + + _readySchemaQueue.CompleteAdding(); + while (_readySchemaQueue.TryTake(out _)) { } + + foreach (var testDatabase in _testDatabases) + { + Drop(testDatabase); + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/TestDatabaseFactory.cs b/src/Umbraco.Tests.Integration/Testing/TestDatabaseFactory.cs new file mode 100644 index 0000000000..60c767e17e --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/TestDatabaseFactory.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Persistence; + +namespace Umbraco.Tests.Integration.Testing +{ + public class TestDatabaseFactory + { + public static ITestDatabase Create(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory) + { + var connectionString = Environment.GetEnvironmentVariable("UmbracoIntegrationTestConnectionString"); + + return string.IsNullOrEmpty(connectionString) + ? CreateLocalDb(filesPath, loggerFactory, dbFactory) + : CreateSqlDeveloper(loggerFactory, dbFactory, connectionString); + } + + private static ITestDatabase CreateLocalDb(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory) + { + if (!Directory.Exists(filesPath)) + { + Directory.CreateDirectory(filesPath); + } + + var localDb = new LocalDb(); + + if (!localDb.IsAvailable) + { + throw new InvalidOperationException("LocalDB is not available."); + } + + return new LocalDbTestDatabase(loggerFactory, localDb, filesPath, dbFactory.Create()); + } + + private static ITestDatabase CreateSqlDeveloper(ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory, string connectionString) + { + // NOTE: Example setup for Linux box. + // $ export SA_PASSWORD=Foobar123! + // $ export UmbracoIntegrationTestConnectionString="Server=localhost,1433;User Id=sa;Password=$SA_PASSWORD;" + // $ docker run -e 'ACCEPT_EULA=Y' -e "SA_PASSWORD=$SA_PASSWORD" -e 'MSSQL_PID=Developer' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu + if (string.IsNullOrEmpty(connectionString)) + { + throw new InvalidOperationException("ENV: UmbracoIntegrationTestConnectionString is not set"); + } + + return new SqlDeveloperTestDatabase(loggerFactory, dbFactory.Create(), connectionString); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/TestDbMeta.cs b/src/Umbraco.Tests.Integration/Testing/TestDbMeta.cs new file mode 100644 index 0000000000..83702db8e5 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/TestDbMeta.cs @@ -0,0 +1,39 @@ +using System.Text.RegularExpressions; + +namespace Umbraco.Tests.Integration.Testing +{ + public class TestDbMeta + { + + public string Name { get; } + + public bool IsEmpty { get; } + + public string ConnectionString { get; set; } + + private TestDbMeta(string name, bool isEmpty, string connectionString) + { + IsEmpty = isEmpty; + Name = name; + ConnectionString = connectionString; + } + + private static string ConstructConnectionString(string masterConnectionString, string databaseName) + { + var prefix = Regex.Replace(masterConnectionString, "Database=.+?;", string.Empty); + var connectionString = $"{prefix};Database={databaseName};"; + return connectionString.Replace(";;", ";"); + } + + public static TestDbMeta CreateWithMasterConnectionString(string name, bool isEmpty, string masterConnectionString) + { + return new TestDbMeta(name, isEmpty, ConstructConnectionString(masterConnectionString, name)); + } + + // LocalDb mdf funtimes + public static TestDbMeta CreateWithoutConnectionString(string name, bool isEmpty) + { + return new TestDbMeta(name, isEmpty, null); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/TestUmbracoDatabaseFactoryProvider.cs b/src/Umbraco.Tests.Integration/Testing/TestUmbracoDatabaseFactoryProvider.cs new file mode 100644 index 0000000000..3eb3757207 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/TestUmbracoDatabaseFactoryProvider.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Mappers; + +namespace Umbraco.Tests.Integration.Testing +{ + /// + /// I want to be able to create a database for integration testsing without setting the connection string on the + /// singleton database factory forever. + /// + public class TestUmbracoDatabaseFactoryProvider + { + private readonly ILoggerFactory _loggerFactory; + private readonly IOptions _globalSettings; + private readonly IOptions _connectionStrings; + private readonly Lazy _mappers; + private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; + + public TestUmbracoDatabaseFactoryProvider( + ILoggerFactory loggerFactory, + IOptions globalSettings, + IOptions connectionStrings, + Lazy mappers, + IDbProviderFactoryCreator dbProviderFactoryCreator) + { + _loggerFactory = loggerFactory; + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; + _mappers = mappers; + _dbProviderFactoryCreator = dbProviderFactoryCreator; + } + + public IUmbracoDatabaseFactory Create() + { + // ReSharper disable once ArrangeMethodOrOperatorBody + return new UmbracoDatabaseFactory( + _loggerFactory.CreateLogger(), + _loggerFactory, + _globalSettings.Value, + _connectionStrings.Value, + _mappers, + _dbProviderFactoryCreator); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 60bab5805f..449d038c9f 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Data.SqlClient; using System.IO; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -15,7 +16,6 @@ using NUnit.Framework; using Serilog; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; using Umbraco.Core.IO; @@ -25,11 +25,17 @@ using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; using Umbraco.Core.Strings; using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.DependencyInjection; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.TestServerTest; using Umbraco.Tests.Testing; using Umbraco.Web; +using Umbraco.Web.BackOffice.DependencyInjection; +using Umbraco.Web.Common.DependencyInjection; namespace Umbraco.Tests.Integration.Testing { @@ -50,7 +56,10 @@ namespace Umbraco.Tests.Integration.Testing public void OnTestTearDown(Action tearDown) { if (_testTeardown == null) + { _testTeardown = new List(); + } + _testTeardown.Add(tearDown); } @@ -60,20 +69,30 @@ namespace Umbraco.Tests.Integration.Testing public void FixtureTearDown() { foreach (var a in _fixtureTeardown) + { a(); + } } [TearDown] - public virtual void TearDown() + public async Task TearDownAsync() { if (_testTeardown != null) { foreach (var a in _testTeardown) + { a(); + } } + _testTeardown = null; FirstTestInFixture = false; FirstTestInSession = false; + + // Ensure CoreRuntime stopped (now it's a HostedService) + IHost host = Services.GetRequiredService(); + await host.StopAsync(); + host.Dispose(); } [TearDown] @@ -94,14 +113,18 @@ namespace Umbraco.Tests.Integration.Testing InMemoryConfiguration[Constants.Configuration.ConfigGlobal + ":" + nameof(GlobalSettings.InstallEmptyDatabase)] = "true"; var hostBuilder = CreateHostBuilder(); - var host = hostBuilder.Start(); + IHost host = hostBuilder.Build(); + BeforeHostStart(host); + host.Start(); - Services = host.Services; var app = new ApplicationBuilder(host.Services); - Configure(app); + } - OnFixtureTearDown(() => host.Dispose()); + protected virtual void BeforeHostStart(IHost host) + { + Services = host.Services; + UseTestDatabase(Services); } #region Generic Host Builder and Runtime @@ -110,13 +133,21 @@ namespace Umbraco.Tests.Integration.Testing { try { - var testOptions = TestOptionAttributeBase.GetTestOptions(); - switch (testOptions.Logger) + switch (TestOptions.Logger) { case UmbracoTestOptions.Logger.Mock: return NullLoggerFactory.Instance; case UmbracoTestOptions.Logger.Serilog: - return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); + return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => + { + var path = Path.Combine(TestHelper.WorkingDirectory, "logs", "umbraco_integration_tests_.txt"); + + Log.Logger = new LoggerConfiguration() + .WriteTo.File(path, rollingInterval: RollingInterval.Day) + .CreateLogger(); + + builder.AddSerilog(Log.Logger); + }); case UmbracoTestOptions.Logger.Console: return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); } @@ -132,7 +163,6 @@ namespace Umbraco.Tests.Integration.Testing /// /// Create the Generic Host and execute startup ConfigureServices/Configure calls /// - /// public virtual IHostBuilder CreateHostBuilder() { var hostBuilder = Host.CreateDefaultBuilder() @@ -141,7 +171,6 @@ namespace Umbraco.Tests.Integration.Testing // create separate Host instances. So instead of UseStartup, we just call ConfigureServices/Configure ourselves, // and in the case of the UmbracoTestServerTestBase it will use the ConfigureWebHost to Configure the IApplicationBuilder directly. //.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(GetType()); }) - .UseUmbraco() .ConfigureAppConfiguration((context, configBuilder) => { context.HostingEnvironment = TestHelper.GetWebHostEnvironment(); @@ -152,19 +181,25 @@ namespace Umbraco.Tests.Integration.Testing }) .ConfigureServices((hostContext, services) => { - services.AddTransient(_ => CreateLoggerFactory()); ConfigureServices(services); + services.AddUnique(CreateLoggerFactory()); + + if (!TestOptions.Boot) + { + // If boot is false, we don't want the CoreRuntime hosted service to start + // So we replace it with a Mock + services.AddUnique(Mock.Of()); + } }); return hostBuilder; } #endregion - #region IStartup - public virtual void ConfigureServices(IServiceCollection services) { services.AddSingleton(TestHelper.DbProviderFactoryCreator); + services.AddTransient(); var webHostEnvironment = TestHelper.GetWebHostEnvironment(); services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment); @@ -180,30 +215,32 @@ namespace Umbraco.Tests.Integration.Testing TestHelper.Profiler); var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); - builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); builder.AddConfiguration() - .AddUmbracoCore(); + .AddUmbracoCore() + .AddWebComponents() + .AddRuntimeMinifier() + .AddBackOfficeAuthentication() + .AddBackOfficeIdentity() + .AddTestServices(TestHelper, GetAppCaches()); - builder.Services.AddUnique(GetAppCaches()); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(TestHelper.MainDom); + if (TestOptions.Mapper) + { + // TODO: Should these just be called from within AddUmbracoCore/AddWebComponents? + builder + .AddCoreMappingProfiles() + .AddWebMappingProfiles(); + } services.AddSignalR(); - - builder.AddWebComponents(); - builder.AddRuntimeMinifier(); - builder.AddBackOffice(); - builder.AddBackOfficeIdentity(); builder.AddMembersIdentity(); - services.AddMvc(); - builder.Build(); + CustomTestSetup(builder); - CustomTestSetup(services); + builder.Build(); } protected virtual AppCaches GetAppCaches() @@ -214,72 +251,49 @@ namespace Umbraco.Tests.Integration.Testing public virtual void Configure(IApplicationBuilder app) { - UseTestLocalDb(app.ApplicationServices); - - //get the currently set options - var testOptions = TestOptionAttributeBase.GetTestOptions(); - if (testOptions.Boot) + if (TestOptions.Boot) { Services.GetRequiredService().EnsureBackOfficeSecurity(); Services.GetRequiredService().EnsureUmbracoContext(); - app.UseUmbracoCore(); // Takes 200 ms - - OnTestTearDown(TerminateCoreRuntime); } - } - /// - /// Some IComponents hook onto static events (e.g. Published in ContentService) - /// If these fire after the components host has been shutdown, errors can occur. - /// If CoreRuntime.Start() is called We also need to de-register the events. - /// - protected void TerminateCoreRuntime() - { - Services.GetRequiredService().Terminate(); - StaticApplicationLogging.Initialize(null); + app.UseUmbracoCore(); // This no longer starts CoreRuntime, it's very fast } - #endregion - #region LocalDb private static readonly object _dbLocker = new object(); - private static LocalDbTestDatabase _dbInstance; + private static ITestDatabase _dbInstance; + private static TestDbMeta _fixtureDbMeta; - protected void UseTestLocalDb(IServiceProvider serviceProvider) + protected void UseTestDatabase(IServiceProvider serviceProvider) { var state = serviceProvider.GetRequiredService(); + var testDatabaseFactoryProvider = serviceProvider.GetRequiredService(); var databaseFactory = serviceProvider.GetRequiredService(); + var loggerFactory = serviceProvider.GetRequiredService(); // This will create a db, install the schema and ensure the app is configured to run - InstallTestLocalDb(databaseFactory, TestHelper.ConsoleLoggerFactory, state, TestHelper.WorkingDirectory); - TestDBConnectionString = databaseFactory.ConnectionString; - InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString; + SetupTestDatabase(testDatabaseFactoryProvider, databaseFactory, loggerFactory, state, TestHelper.WorkingDirectory); } /// - /// Get or create an instance of + /// Get or create an instance of /// - /// - /// - /// - /// - /// - /// /// /// There must only be ONE instance shared between all tests in a session /// - private static LocalDbTestDatabase GetOrCreateDatabase(string filesPath, ILoggerFactory loggerFactory, IUmbracoDatabaseFactory dbFactory) + private static ITestDatabase GetOrCreateDatabase(string filesPath, ILoggerFactory loggerFactory, TestUmbracoDatabaseFactoryProvider dbFactory) { lock (_dbLocker) { if (_dbInstance != null) + { return _dbInstance; + } + + _dbInstance = TestDatabaseFactory.Create(filesPath, loggerFactory, dbFactory); - var localDb = new LocalDb(); - if (localDb.IsAvailable == false) - throw new InvalidOperationException("LocalDB is not available."); - _dbInstance = new LocalDbTestDatabase(loggerFactory, localDb, filesPath, dbFactory); return _dbInstance; } } @@ -287,69 +301,47 @@ namespace Umbraco.Tests.Integration.Testing /// /// Creates a LocalDb instance to use for the test /// - /// - /// - /// - /// - /// - /// - /// - private void InstallTestLocalDb( - IUmbracoDatabaseFactory databaseFactory, ILoggerFactory loggerFactory, - IRuntimeState runtimeState, string workingDirectory) + private void SetupTestDatabase( + TestUmbracoDatabaseFactoryProvider testUmbracoDatabaseFactoryProvider, + IUmbracoDatabaseFactory databaseFactory, + ILoggerFactory loggerFactory, + IRuntimeState runtimeState, + string workingDirectory) { - var dbFilePath = Path.Combine(workingDirectory, "LocalDb"); - - // get the currently set db options - var testOptions = TestOptionAttributeBase.GetTestOptions(); - - if (testOptions.Database == UmbracoTestOptions.Database.None) + if (TestOptions.Database == UmbracoTestOptions.Database.None) + { return; + } // need to manually register this factory DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); - if (!Directory.Exists(dbFilePath)) - Directory.CreateDirectory(dbFilePath); + var dbFilePath = Path.Combine(workingDirectory, "LocalDb"); - var db = GetOrCreateDatabase(dbFilePath, loggerFactory, databaseFactory); + var db = GetOrCreateDatabase(dbFilePath, loggerFactory, testUmbracoDatabaseFactoryProvider); - switch (testOptions.Database) + switch (TestOptions.Database) { case UmbracoTestOptions.Database.NewSchemaPerTest: // New DB + Schema - var newSchemaDbId = db.AttachSchema(); + TestDbMeta newSchemaDbMeta = db.AttachSchema(); // Add teardown callback - OnTestTearDown(() => db.Detach(newSchemaDbId)); + OnTestTearDown(() => db.Detach(newSchemaDbMeta)); - // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings - if (!databaseFactory.Configured) - { - databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); - } - - // re-run the runtime level check - runtimeState.DetermineRuntimeLevel(); + ConfigureTestDatabaseFactory(newSchemaDbMeta, databaseFactory, runtimeState); Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level); break; case UmbracoTestOptions.Database.NewEmptyPerTest: - var newEmptyDbId = db.AttachEmpty(); + TestDbMeta newEmptyDbMeta = db.AttachEmpty(); // Add teardown callback - OnTestTearDown(() => db.Detach(newEmptyDbId)); + OnTestTearDown(() => db.Detach(newEmptyDbMeta)); - // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings - if (!databaseFactory.Configured) - { - databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); - } - - // re-run the runtime level check - runtimeState.DetermineRuntimeLevel(); + ConfigureTestDatabaseFactory(newEmptyDbMeta, databaseFactory, runtimeState); Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); @@ -361,20 +353,14 @@ namespace Umbraco.Tests.Integration.Testing if (FirstTestInFixture) { // New DB + Schema - var newSchemaFixtureDbId = db.AttachSchema(); + TestDbMeta newSchemaFixtureDbMeta = db.AttachSchema(); + _fixtureDbMeta = newSchemaFixtureDbMeta; // Add teardown callback - OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbId)); + OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbMeta)); } - // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings - if (!databaseFactory.Configured) - { - databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); - } - - // re-run the runtime level check - runtimeState.DetermineRuntimeLevel(); + ConfigureTestDatabaseFactory(_fixtureDbMeta, databaseFactory, runtimeState); break; case UmbracoTestOptions.Database.NewEmptyPerFixture: @@ -384,27 +370,37 @@ namespace Umbraco.Tests.Integration.Testing if (FirstTestInFixture) { // New DB + Schema - var newEmptyFixtureDbId = db.AttachEmpty(); + TestDbMeta newEmptyFixtureDbMeta = db.AttachEmpty(); + _fixtureDbMeta = newEmptyFixtureDbMeta; // Add teardown callback - OnFixtureTearDown(() => db.Detach(newEmptyFixtureDbId)); + OnFixtureTearDown(() => db.Detach(newEmptyFixtureDbMeta)); } - // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings - if (!databaseFactory.Configured) - { - databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); - } + ConfigureTestDatabaseFactory(_fixtureDbMeta, databaseFactory, runtimeState); break; default: - throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null); + throw new ArgumentOutOfRangeException(nameof(TestOptions), TestOptions, null); } } + private void ConfigureTestDatabaseFactory(TestDbMeta meta, IUmbracoDatabaseFactory factory, IRuntimeState state) + { + ILogger log = Services.GetRequiredService>(); + log.LogInformation($"ConfigureTestDatabaseFactory - Using test database: [{meta.Name}] - IsEmpty: [{meta.IsEmpty}]"); + + // It's just been pulled from container and wasn't used to create test database + Assert.IsFalse(factory.Configured); + + factory.Configure(meta.ConnectionString, Constants.DatabaseProviders.SqlServer); + state.DetermineRuntimeLevel(); + log.LogInformation($"ConfigureTestDatabaseFactory - Determined RuntimeLevel: [{state.Level}]"); + } + #endregion - #region Common services + protected UmbracoTestAttribute TestOptions => TestOptionAttributeBase.GetTestOptions(); protected virtual T GetRequiredService() => Services.GetRequiredService(); @@ -412,11 +408,9 @@ namespace Umbraco.Tests.Integration.Testing public IConfiguration Configuration { get; protected set; } - public TestHelper TestHelper = new TestHelper(); + public TestHelper TestHelper { get; } = new TestHelper(); - protected virtual string TestDBConnectionString { get; private set; } - - protected virtual Action CustomTestSetup => services => { }; + protected virtual void CustomTestSetup(IUmbracoBuilder builder) { } /// /// Returns the DI container @@ -439,12 +433,14 @@ namespace Umbraco.Tests.Integration.Testing protected ILoggerFactory LoggerFactory => Services.GetRequiredService(); protected AppCaches AppCaches => Services.GetRequiredService(); - protected IIOHelper IOHelper => Services.GetRequiredService(); - protected IShortStringHelper ShortStringHelper => Services.GetRequiredService(); - protected GlobalSettings GlobalSettings => Services.GetRequiredService>().Value; - protected IMapperCollection Mappers => Services.GetRequiredService(); - #endregion + protected IIOHelper IOHelper => Services.GetRequiredService(); + + protected IShortStringHelper ShortStringHelper => Services.GetRequiredService(); + + protected GlobalSettings GlobalSettings => Services.GetRequiredService>().Value; + + protected IMapperCollection Mappers => Services.GetRequiredService(); #region Builders diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs index ecfc829427..2feccbcccb 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -10,17 +10,17 @@ namespace Umbraco.Tests.Integration.Testing public abstract class UmbracoIntegrationTestWithContent : UmbracoIntegrationTest { protected IContentTypeService ContentTypeService => GetRequiredService(); + protected IFileService FileService => GetRequiredService(); + protected ContentService ContentService => (ContentService)GetRequiredService(); [SetUp] - public void Setup(){ - CreateTestData(); - } + public void Setup() => CreateTestData(); public virtual void CreateTestData() { - //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. + // NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs index 4474b95584..314a50ce75 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs @@ -1,27 +1,17 @@ -using System; +using System; using System.IO; using System.Text; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; -using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.IO { [TestFixture] - [UmbracoTest()] + [UmbracoTest] public class FileSystemsTests : UmbracoIntegrationTest { [Test] diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs index 4028889b01..244e8c8d1a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Linq; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs index 6f3702765e..e3ec2d872b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs @@ -45,6 +45,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging private IEntityXmlSerializer EntityXmlSerializer => GetRequiredService(); private IHostingEnvironment HostingEnvironment => GetRequiredService(); private IUmbracoVersion UmbracoVersion => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); public ICreatedPackagesRepository PackageBuilder => new PackagesRepository( ContentService, ContentTypeService, DataTypeService, @@ -53,6 +55,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging EntityXmlSerializer, LoggerFactory, UmbracoVersion, Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), + MediaService, + MediaTypeService, "createdPackages.config", //temp paths tempFolderPath: "~/" + _testBaseFolder + "/temp", @@ -158,8 +162,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging { var file1 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/package.manifest"; var file2 = $"~/{_testBaseFolder}/App_Plugins/MyPlugin/styles.css"; - var mappedFile1 = IOHelper.MapPath(file1); - var mappedFile2 = IOHelper.MapPath(file2); + var mappedFile1 = HostingEnvironment.MapPathContentRoot(file1); + var mappedFile2 = HostingEnvironment.MapPathContentRoot(file2); Directory.CreateDirectory(Path.GetDirectoryName(mappedFile1)); Directory.CreateDirectory(Path.GetDirectoryName(mappedFile2)); File.WriteAllText(mappedFile1, "hello world"); @@ -183,7 +187,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging def = PackageBuilder.GetById(def.Id); //re-get Assert.IsNotNull(def.PackagePath); - using (var archive = ZipFile.OpenRead(IOHelper.MapPath(zip))) + using (var archive = ZipFile.OpenRead(HostingEnvironment.MapPathWebRoot(zip))) { Assert.AreEqual(3, archive.Entries.Count); diff --git a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs similarity index 87% rename from src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs index b48e3230f6..f250a43b7f 100644 --- a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageDataInstallationTests.cs @@ -2,22 +2,21 @@ using System.Linq; using System.Threading; using System.Xml.Linq; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; @@ -26,15 +25,18 @@ namespace Umbraco.Tests.Packaging [TestFixture] [Category("Slow")] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PackageDataInstallationTests : TestWithSomeContentBase + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] + public class PackageDataInstallationTests : UmbracoIntegrationTestWithContent { + private ILocalizationService LocalizationService => GetRequiredService(); + private IMacroService MacroService => GetRequiredService(); + [HideFromTypeFinder] [DataEditor("7e062c13-7c41-4ad9-b389-41d88aeef87c", "Editor1", "editor1")] public class Editor1 : DataEditor { public Editor1(ILoggerFactory loggerFactory) - : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) + : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()) { } } @@ -44,36 +46,41 @@ namespace Umbraco.Tests.Packaging public class Editor2 : DataEditor { public Editor2(ILoggerFactory loggerFactory) - : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of()) + : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), new JsonNetSerializer()) { } } - protected override void Compose() - { - base.Compose(); + // protected override void Compose() + // { + // base.Compose(); + // + // // the packages that are used by these tests reference totally bogus property + // // editors that must exist - so they are defined here - and in order not to + // // pollute everything, they are ignored by the type finder and explicitely + // // added to the editors collection + // + // Builder.WithCollectionBuilder() + // .Add() + // .Add(); + // } + // + // protected override void ComposeApplication(bool withApplication) + // { + // base.ComposeApplication(withApplication); + // + // if (!withApplication) return; + // + // // re-register with actual media fs + // Builder.ComposeFileSystems(); + // } - // the packages that are used by these tests reference totally bogus property - // editors that must exist - so they are defined here - and in order not to - // pollute everything, they are ignored by the type finder and explicitely - // added to the editors collection + private PackageDataInstallation PackageDataInstallation => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); - Builder.WithCollectionBuilder() - .Add() - .Add(); - } - - protected override void ComposeApplication(bool withApplication) - { - base.ComposeApplication(withApplication); - - if (!withApplication) return; - - // re-register with actual media fs - Builder.ComposeFileSystems(); - } - - private PackageDataInstallation PackageDataInstallation => Factory.GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); [Test] public void Can_Import_uBlogsy_ContentTypes_And_Verify_Structure() @@ -194,12 +201,12 @@ namespace Umbraco.Tests.Packaging var xml = XElement.Parse(strXml); var element = xml.Descendants("Templates").First(); - var init = ServiceContext.FileService.GetTemplates().Count(); + var init = FileService.GetTemplates().Count(); // Act var templates = PackageDataInstallation.ImportTemplates(element.Elements("Template").ToList(), 0); var numberOfTemplates = (from doc in element.Elements("Template") select doc).Count(); - var allTemplates = ServiceContext.FileService.GetTemplates(); + var allTemplates = FileService.GetTemplates(); // Assert Assert.That(templates, Is.Not.Null); @@ -321,16 +328,16 @@ namespace Umbraco.Tests.Packaging var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - var packageDocument = CompiledPackageDocument.Create(element); + var packageDocument = CompiledPackageContentBase.Create(element); // Act var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0); + var contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); var numberOfDocs = (from doc in element.Descendants() - where (string) doc.Attribute("isDoc") == "" - select doc).Count(); + where (string) doc.Attribute("isDoc") == "" + select doc).Count(); // Assert Assert.That(contents, Is.Not.Null); @@ -340,6 +347,32 @@ namespace Umbraco.Tests.Packaging Assert.That(contents.Count(), Is.EqualTo(numberOfDocs)); } + [Test] + public void Can_Import_Media_Package_Xml() + { + // Arrange + Core.Services.Implement.MediaTypeService.ClearScopeEvents(); + string strXml = ImportResources.MediaTypesAndMedia_Package_xml; + var xml = XElement.Parse(strXml); + var mediaTypesElement = xml.Descendants("MediaTypes").First(); + var element = xml.Descendants("MediaSet").First(); + var packageMedia = CompiledPackageContentBase.Create(element); + + // Act + var mediaTypes = PackageDataInstallation.ImportMediaTypes(mediaTypesElement.Elements("MediaType"), 0); + var importedMediaTypes = mediaTypes.ToDictionary(x => x.Alias, x => x); + var medias = PackageDataInstallation.ImportContentBase(packageMedia.Yield(), importedMediaTypes, 0, MediaTypeService, MediaService); + var numberOfDocs = (from doc in element.Descendants() + where (string) doc.Attribute("isDoc") == "" + select doc).Count(); + + // Assert + Assert.That(medias, Is.Not.Null); + Assert.That(mediaTypes.Any(), Is.True); + Assert.That(medias.Any(), Is.True); + Assert.That(medias.Count(), Is.EqualTo(numberOfDocs)); + } + [Test] public void Can_Import_CheckboxList_Content_Package_Xml_With_Property_Editor_Aliases() { @@ -355,13 +388,13 @@ namespace Umbraco.Tests.Packaging var dataTypeElement = xml.Descendants("DataTypes").First(); var docTypesElement = xml.Descendants("DocumentTypes").First(); var element = xml.Descendants("DocumentSet").First(); - var packageDocument = CompiledPackageDocument.Create(element); + var packageDocument = CompiledPackageContentBase.Create(element); // Act var dataTypeDefinitions = PackageDataInstallation.ImportDataTypes(dataTypeElement.Elements("DataType").ToList(), 0); var contentTypes = PackageDataInstallation.ImportDocumentTypes(docTypesElement.Elements("DocumentType"), 0); var importedContentTypes = contentTypes.ToDictionary(x => x.Alias, x => x); - var contents = PackageDataInstallation.ImportContent(packageDocument, -1, importedContentTypes, 0); + var contents = PackageDataInstallation.ImportContentBase(packageDocument.Yield(), importedContentTypes, 0, ContentTypeService, ContentService); var numberOfDocs = (from doc in element.Descendants() where (string)doc.Attribute("isDoc") == "" select doc).Count(); @@ -426,7 +459,7 @@ namespace Umbraco.Tests.Packaging string strXml = ImportResources.SingleDocType; var docTypeElement = XElement.Parse(strXml); - var serializer = Factory.GetRequiredService(); + var serializer = GetRequiredService(); // Act var contentTypes = PackageDataInstallation.ImportDocumentType(docTypeElement, 0); @@ -475,7 +508,7 @@ namespace Umbraco.Tests.Packaging var templateElement = newPackageXml.Descendants("Templates").First(); var templateElementUpdated = updatedPackageXml.Descendants("Templates").First(); - var fileService = ServiceContext.FileService; + var fileService = FileService; // kill default test data fileService.DeleteTemplate("Textpage"); @@ -534,11 +567,11 @@ namespace Umbraco.Tests.Packaging var dictionaryItems = PackageDataInstallation.ImportDictionaryItems(dictionaryItemsElement.Elements("DictionaryItem"), 0); // Assert - Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist"); - Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(childKey), "DictionaryItem childKey does not exist"); + Assert.That(LocalizationService.DictionaryItemExists(parentKey), "DictionaryItem parentKey does not exist"); + Assert.That(LocalizationService.DictionaryItemExists(childKey), "DictionaryItem childKey does not exist"); - var parentDictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(parentKey); - var childDictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(childKey); + var parentDictionaryItem = LocalizationService.GetDictionaryItemByKey(parentKey); + var childDictionaryItem = LocalizationService.GetDictionaryItemByKey(childKey); Assert.That(parentDictionaryItem.ParentId, Is.Not.EqualTo(childDictionaryItem.ParentId)); Assert.That(childDictionaryItem.ParentId, Is.EqualTo(parentDictionaryItem.Key)); @@ -603,7 +636,7 @@ namespace Umbraco.Tests.Packaging // Act var languages = PackageDataInstallation.ImportLanguages(LanguageItemsElement.Elements("Language"), 0); - var allLanguages = ServiceContext.LocalizationService.GetAllLanguages(); + var allLanguages = LocalizationService.GetAllLanguages(); // Assert Assert.That(languages.Any(x => x.HasIdentity == false), Is.False); @@ -628,7 +661,7 @@ namespace Umbraco.Tests.Packaging // Assert Assert.That(macros.Any(), Is.True); - var allMacros = ServiceContext.MacroService.GetAll().ToList(); + var allMacros = MacroService.GetAll().ToList(); foreach (var macro in macros) { Assert.That(allMacros.Any(x => x.Alias == macro.Alias), Is.True); @@ -651,7 +684,7 @@ namespace Umbraco.Tests.Packaging Assert.That(macros.Any(), Is.True); Assert.That(macros.First().Properties.Values.Any(), Is.True); - var allMacros = ServiceContext.MacroService.GetAll().ToList(); + var allMacros = MacroService.GetAll().ToList(); foreach (var macro in macros) { Assert.That(allMacros.Any(x => x.Alias == macro.Alias), Is.True); @@ -717,14 +750,14 @@ namespace Umbraco.Tests.Packaging var globalSettings = new GlobalSettings(); var norwegian = new Core.Models.Language(globalSettings, "nb-NO"); var english = new Core.Models.Language(globalSettings, "en-GB"); - ServiceContext.LocalizationService.Save(norwegian, 0); - ServiceContext.LocalizationService.Save(english, 0); + LocalizationService.Save(norwegian, 0); + LocalizationService.Save(english, 0); } private void AssertDictionaryItem(string key, string expectedValue, string cultureCode) { - Assert.That(ServiceContext.LocalizationService.DictionaryItemExists(key), "DictionaryItem key does not exist"); - var dictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey(key); + Assert.That(LocalizationService.DictionaryItemExists(key), "DictionaryItem key does not exist"); + var dictionaryItem = LocalizationService.GetDictionaryItemByKey(key); var translation = dictionaryItem.Translations.SingleOrDefault(i => i.Language.IsoCode == cultureCode); Assert.IsNotNull(translation, "Translation to {0} was not added", cultureCode); var value = translation.Value; @@ -733,9 +766,9 @@ namespace Umbraco.Tests.Packaging private void AddExistingEnglishParentDictionaryItem(string expectedEnglishParentValue) { - var languages = ServiceContext.LocalizationService.GetAllLanguages().ToList(); + var languages = LocalizationService.GetAllLanguages().ToList(); var englishLanguage = languages.Single(l => l.IsoCode == "en-GB"); - ServiceContext.LocalizationService.Save( + LocalizationService.Save( new DictionaryItem("Parent") { Translations = new List @@ -748,10 +781,10 @@ namespace Umbraco.Tests.Packaging private void AddExistingEnglishAndNorwegianParentDictionaryItem(string expectedEnglishParentValue, string expectedNorwegianParentValue) { - var languages = ServiceContext.LocalizationService.GetAllLanguages().ToList(); + var languages = LocalizationService.GetAllLanguages().ToList(); var englishLanguage = languages.Single(l => l.IsoCode == "en-GB"); var norwegianLanguage = languages.Single(l => l.IsoCode == "nb-NO"); - ServiceContext.LocalizationService.Save( + LocalizationService.Save( new DictionaryItem("Parent") { Translations = new List diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs similarity index 58% rename from src/Umbraco.Tests/Packaging/PackageInstallationTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs index 51d077d89f..93a6ef010b 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/PackageInstallationTest.cs @@ -2,74 +2,21 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Scoping; -using Umbraco.Core.Serialization; -using Umbraco.Core.Services; -using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -using File = System.IO.File; namespace Umbraco.Tests.Packaging { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class PackageInstallationTest : TestWithDatabaseBase + public class PackageInstallationTest : UmbracoIntegrationTest { - private DirectoryInfo _testBaseFolder; - - public override void SetUp() - { - base.SetUp(); - var path = Path.Combine(TestHelper.WorkingDirectory, Guid.NewGuid().ToString()); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - _testBaseFolder = new DirectoryInfo(path); - } - - public override void TearDown() - { - base.TearDown(); - - //clear out files/folders - if (_testBaseFolder.Exists) - _testBaseFolder.Delete(true); - } - - private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser( - new ConflictingPackageData( - ServiceContext.MacroService, - ServiceContext.FileService), - Microsoft.Extensions.Options.Options.Create(new GlobalSettings())); - - private PackageDataInstallation PackageDataInstallation => new PackageDataInstallation( - NullLoggerFactory.Instance.CreateLogger(), NullLoggerFactory.Instance, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, - ServiceContext.DataTypeService, ServiceContext.EntityService, - ServiceContext.ContentTypeService, ServiceContext.ContentService, - Factory.GetRequiredService(), - Factory.GetRequiredService(), - Factory.GetRequiredService(), - Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), - Factory.GetRequiredService(), - Factory.GetRequiredService()); - - private IPackageInstallation PackageInstallation => new PackageInstallation( - PackageDataInstallation, - new PackageFileInstallation(Parser, IOHelper, HostingEnvironment, ProfilingLogger), - Parser, Mock.Of(), - //we don't want to extract package files to the real root, so extract to a test folder - Mock.Of(x => x.ApplicationPhysicalPath == _testBaseFolder.FullName)); + private IHostingEnvironment HostingEnvironment => GetRequiredService(); + private IPackageInstallation PackageInstallation => GetRequiredService(); private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.umb"; private const string HelloPackage = "Hello_1.0.0.zip"; @@ -79,7 +26,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); + new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage))); Assert.IsNotNull(package); Assert.AreEqual(1, package.Files.Count); Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName); @@ -102,7 +49,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), HelloPackage))); + new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), HelloPackage))); Assert.IsNotNull(package); Assert.AreEqual(0, package.Files.Count); Assert.AreEqual("Hello", package.Name); @@ -128,12 +75,12 @@ namespace Umbraco.Tests.Packaging { //copy a file to the same path that the package will install so we can detect file conflicts - var filePath = Path.Combine(_testBaseFolder.FullName, "bin", "Auros.DocumentTypePicker.dll"); + var filePath = Path.Combine(HostingEnvironment.MapPathContentRoot("~/"), "bin", "Auros.DocumentTypePicker.dll"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)); File.WriteAllText(filePath, "test"); //this is where our test zip file is - var packageFile = Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage); + var packageFile = Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage); Console.WriteLine(packageFile); var package = PackageInstallation.ReadPackage(new FileInfo(packageFile)); @@ -141,7 +88,7 @@ namespace Umbraco.Tests.Packaging Assert.IsNotNull(preInstallWarnings); Assert.AreEqual(1, preInstallWarnings.FilesReplaced.Count()); - Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", preInstallWarnings.FilesReplaced.First()); + Assert.AreEqual(Path.Combine("bin", "Auros.DocumentTypePicker.dll"), preInstallWarnings.FilesReplaced.First()); // TODO: More Asserts } @@ -151,7 +98,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); + new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; @@ -161,8 +108,8 @@ namespace Umbraco.Tests.Packaging var result = PackageInstallation.InstallPackageFiles(def, package, -1).ToList(); Assert.AreEqual(1, result.Count); - Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", result[0]); - Assert.IsTrue(File.Exists(Path.Combine(_testBaseFolder.FullName, result[0]))); + Assert.AreEqual(Path.Combine("bin", "Auros.DocumentTypePicker.dll"), result[0]); + Assert.IsTrue(File.Exists(Path.Combine(HostingEnvironment.MapPathContentRoot("~/"), result[0]))); //make sure the def is updated too Assert.AreEqual(result.Count, def.Files.Count); @@ -173,7 +120,7 @@ namespace Umbraco.Tests.Packaging { var package = PackageInstallation.ReadPackage( //this is where our test zip file is - new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerPackage))); + new FileInfo(Path.Combine(HostingEnvironment.MapPathContentRoot("~/TestData/Packages"), DocumentTypePickerPackage))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); @@ -186,7 +133,5 @@ namespace Umbraco.Tests.Packaging //make sure the def is updated too Assert.AreEqual(summary.DataTypesInstalled.Count(), def.DataTypes.Count); } - - } } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index ebfcd3e7de..c94b708ff9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -3,11 +3,11 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -using Umbraco.Tests.Testing; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories @@ -23,15 +23,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor private IDataTypeContainerRepository DataTypeContainerRepository => GetRequiredService(); private IDataTypeRepository DataTypeRepository => GetRequiredService(); private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); + private IJsonSerializer JsonSerializer => GetRequiredService(); [Test] public void Can_Find_Usages() { using (ScopeProvider.CreateScope()) { - IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "dt1" }; + IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { Name = "dt1" }; DataTypeRepository.Save(dataType1); - IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "dt2" }; + IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { Name = "dt2" }; DataTypeRepository.Save(dataType2); IContentType ct = new ContentType(ShortStringHelper, -1) @@ -94,14 +95,14 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container2 = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah2", ParentId = container1.Id }; DataTypeContainerRepository.Save(container2); - var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container2.Id) + var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer, container2.Id) { Name = "dt1" }; DataTypeRepository.Save(dataType); //create a - var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, dataType.Id) + var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer, dataType.Id) { Name = "dt2" }; @@ -160,7 +161,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; DataTypeContainerRepository.Save(container); - var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; + var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; DataTypeRepository.Save(dataTypeDefinition); Assert.AreEqual(container.Id, dataTypeDefinition.ParentId); @@ -175,7 +176,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; DataTypeContainerRepository.Save(container); - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; DataTypeRepository.Save(dataType); // Act @@ -195,7 +196,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) {Name = "test"}; + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) {Name = "test"}; DataTypeRepository.Save(dataType); @@ -295,7 +296,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -330,7 +331,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new IntegerPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService), ConfigurationEditorJsonSerializer) + var dataTypeDefinition = new DataType(new IntegerPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService, JsonSerializer), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -341,7 +342,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor // Act var definition = DataTypeRepository.Get(dataTypeDefinition.Id); definition.Name = "AgeDataType Updated"; - definition.Editor = new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper); //change + definition.Editor = new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper, JsonSerializer); //change DataTypeRepository.Save(definition); var definitionUpdated = DataTypeRepository.Get(dataTypeDefinition.Id); @@ -358,7 +359,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index b0ba97eedf..e0ef0434c9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -114,7 +114,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), globalSettings); contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); - var entityRepository = new EntityRepository(scopeAccessor); + var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs index 3fb518661c..8fbfc765d7 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs @@ -1,7 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Repositories.Implement; @@ -19,7 +20,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { private EntityRepository CreateRepository(IScopeAccessor scopeAccessor) { - var entityRepository = new EntityRepository(scopeAccessor); + var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); return entityRepository; } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs index 7d3dcc7202..f504218cec 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Microsoft.Extensions.Logging; using Moq; @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); - var entityRepository = new EntityRepository(scopeAccessor); + var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty()); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs index 1ae46faa76..ffda46ed0d 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Tests.Testing; using System; +using System.IO; using Umbraco.Core.Hosting; using Umbraco.Tests.Integration.Testing; @@ -55,28 +56,28 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor partialView = new PartialView(PartialViewType.PartialView, "path-2/test-path-2.cshtml") { Content = "// partialView" }; repository.Save(partialView); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-2.cshtml")); - Assert.AreEqual("path-2\\test-path-2.cshtml", partialView.Path); // fixed in 7.3 - 7.2.8 does not update the path + Assert.AreEqual("path-2\\test-path-2.cshtml".Replace("\\", $"{Path.DirectorySeparatorChar}"), partialView.Path); // fixed in 7.3 - 7.2.8 does not update the path Assert.AreEqual("/Views/Partials/path-2/test-path-2.cshtml", partialView.VirtualPath); partialView = (PartialView) repository.Get("path-2/test-path-2.cshtml"); Assert.IsNotNull(partialView); - Assert.AreEqual("path-2\\test-path-2.cshtml", partialView.Path); + Assert.AreEqual("path-2\\test-path-2.cshtml".Replace("\\", $"{Path.DirectorySeparatorChar}"), partialView.Path); Assert.AreEqual("/Views/Partials/path-2/test-path-2.cshtml", partialView.VirtualPath); partialView = new PartialView(PartialViewType.PartialView, "path-2\\test-path-3.cshtml") { Content = "// partialView" }; repository.Save(partialView); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-3.cshtml")); - Assert.AreEqual("path-2\\test-path-3.cshtml", partialView.Path); + Assert.AreEqual("path-2\\test-path-3.cshtml".Replace("\\", $"{Path.DirectorySeparatorChar}"), partialView.Path); Assert.AreEqual("/Views/Partials/path-2/test-path-3.cshtml", partialView.VirtualPath); partialView = (PartialView) repository.Get("path-2/test-path-3.cshtml"); Assert.IsNotNull(partialView); - Assert.AreEqual("path-2\\test-path-3.cshtml", partialView.Path); + Assert.AreEqual("path-2\\test-path-3.cshtml".Replace("\\", $"{Path.DirectorySeparatorChar}"), partialView.Path); Assert.AreEqual("/Views/Partials/path-2/test-path-3.cshtml", partialView.VirtualPath); partialView = (PartialView) repository.Get("path-2\\test-path-3.cshtml"); Assert.IsNotNull(partialView); - Assert.AreEqual("path-2\\test-path-3.cshtml", partialView.Path); + Assert.AreEqual("path-2\\test-path-3.cshtml".Replace("\\", $"{Path.DirectorySeparatorChar}"), partialView.Path); Assert.AreEqual("/Views/Partials/path-2/test-path-3.cshtml", partialView.VirtualPath); partialView = new PartialView(PartialViewType.PartialView, "\\test-path-4.cshtml") { Content = "// partialView" }; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs index 26efdf325a..b73af3fdfc 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs @@ -19,7 +19,7 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Boot = true)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class RelationRepositoryTest : UmbracoIntegrationTest { private RelationType _relateContent; @@ -432,7 +432,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { var accessor = (IScopeAccessor)ScopeProvider; var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of>()); - var entityRepository = new EntityRepository(accessor); + var entityRepository = new EntityRepository(accessor, AppCaches.Disabled); var relationRepository = new RelationRepository(accessor, Mock.Of>(), relationTypeRepository, entityRepository); relationTypeRepository.Save(_relateContent); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs index 9e4ae80ec6..f9084332b7 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs @@ -280,36 +280,36 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor repository.Save(script); Assert.IsTrue(_fileSystem.FileExists("scripts/path-2/test-path-2.js")); - Assert.AreEqual("scripts\\path-2\\test-path-2.js", script.Path); + Assert.AreEqual("scripts\\path-2\\test-path-2.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path); Assert.AreEqual("/scripts/scripts/path-2/test-path-2.js", script.VirtualPath); script = new Script("path-2/test-path-2.js") { Content = "// script" }; repository.Save(script); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-2.js")); - Assert.AreEqual("path-2\\test-path-2.js", script.Path); // fixed in 7.3 - 7.2.8 does not update the path + Assert.AreEqual("path-2\\test-path-2.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path);// fixed in 7.3 - 7.2.8 does not update the path Assert.AreEqual("/scripts/path-2/test-path-2.js", script.VirtualPath); script = repository.Get("path-2/test-path-2.js"); Assert.IsNotNull(script); - Assert.AreEqual("path-2\\test-path-2.js", script.Path); + Assert.AreEqual("path-2\\test-path-2.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path); Assert.AreEqual("/scripts/path-2/test-path-2.js", script.VirtualPath); script = new Script("path-2\\test-path-3.js") { Content = "// script" }; repository.Save(script); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-3.js")); - Assert.AreEqual("path-2\\test-path-3.js", script.Path); + Assert.AreEqual("path-2\\test-path-3.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path); Assert.AreEqual("/scripts/path-2/test-path-3.js", script.VirtualPath); script = repository.Get("path-2/test-path-3.js"); Assert.IsNotNull(script); - Assert.AreEqual("path-2\\test-path-3.js", script.Path); + Assert.AreEqual("path-2\\test-path-3.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path); Assert.AreEqual("/scripts/path-2/test-path-3.js", script.VirtualPath); script = repository.Get("path-2\\test-path-3.js"); Assert.IsNotNull(script); - Assert.AreEqual("path-2\\test-path-3.js", script.Path); + Assert.AreEqual("path-2\\test-path-3.js".Replace("\\", $"{Path.DirectorySeparatorChar}"), script.Path); Assert.AreEqual("/scripts/path-2/test-path-3.js", script.VirtualPath); script = new Script("\\test-path-4.js") { Content = "// script" }; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs index a576666e6e..b4b8316f83 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs @@ -135,7 +135,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor stylesheet = repository.Get(stylesheet.Name); //Assert - Assert.That(stylesheet.Content, Is.EqualTo("body { color:#000; } .bold {font-weight:bold;}\r\n\r\n/**umb_name:Test*/\r\np {\r\n\tfont-size:2em;\r\n}")); + Assert.That(stylesheet.Content, Is.EqualTo("body { color:#000; } .bold {font-weight:bold;}\r\n\r\n/**umb_name:Test*/\r\np {\r\n\tfont-size:2em;\r\n}".Replace("\r\n", Environment.NewLine))); Assert.AreEqual(1, stylesheet.Properties.Count()); } } @@ -281,29 +281,29 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor repository.Save(stylesheet); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-2.css")); - Assert.AreEqual("path-2\\test-path-2.css", stylesheet.Path); // fixed in 7.3 - 7.2.8 does not update the path + Assert.AreEqual("path-2\\test-path-2.css".Replace("\\", $"{Path.DirectorySeparatorChar}"), stylesheet.Path);// fixed in 7.3 - 7.2.8 does not update the path Assert.AreEqual("/css/path-2/test-path-2.css", stylesheet.VirtualPath); stylesheet = repository.Get("path-2/test-path-2.css"); Assert.IsNotNull(stylesheet); - Assert.AreEqual("path-2\\test-path-2.css", stylesheet.Path); + Assert.AreEqual("path-2\\test-path-2.css".Replace("\\", $"{Path.DirectorySeparatorChar}"), stylesheet.Path); Assert.AreEqual("/css/path-2/test-path-2.css", stylesheet.VirtualPath); stylesheet = new Stylesheet("path-2\\test-path-3.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-3.css")); - Assert.AreEqual("path-2\\test-path-3.css", stylesheet.Path); + Assert.AreEqual("path-2\\test-path-3.css".Replace("\\", $"{Path.DirectorySeparatorChar}"), stylesheet.Path); Assert.AreEqual("/css/path-2/test-path-3.css", stylesheet.VirtualPath); stylesheet = repository.Get("path-2/test-path-3.css"); Assert.IsNotNull(stylesheet); - Assert.AreEqual("path-2\\test-path-3.css", stylesheet.Path); + Assert.AreEqual("path-2\\test-path-3.css".Replace("\\", $"{Path.DirectorySeparatorChar}"), stylesheet.Path); Assert.AreEqual("/css/path-2/test-path-3.css", stylesheet.VirtualPath); stylesheet = repository.Get("path-2\\test-path-3.css"); Assert.IsNotNull(stylesheet); - Assert.AreEqual("path-2\\test-path-3.css", stylesheet.Path); + Assert.AreEqual("path-2\\test-path-3.css".Replace("\\", $"{Path.DirectorySeparatorChar}"), stylesheet.Path); Assert.AreEqual("/css/path-2/test-path-3.css", stylesheet.VirtualPath); stylesheet = new Stylesheet("\\test-path-4.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index 6deb579ad1..5cab23c4c9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -262,7 +262,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); - var entityRepository = new EntityRepository(scopeAccessor); + var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index 5542f926e1..0a1e46274b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs @@ -1,8 +1,6 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Cache; @@ -27,12 +25,12 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping private DistributedCacheBinder _distributedCacheBinder; private IUserService UserService => GetRequiredService(); - private ILocalizationService LocalizationService => GetRequiredService(); - private IServerMessenger ServerMessenger => GetRequiredService(); - private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); - protected override Action CustomTestSetup => (services) - => services.Replace(ServiceDescriptor.Singleton(typeof(IServerMessenger), typeof(LocalServerMessenger))); + private ILocalizationService LocalizationService => GetRequiredService(); + + private IServerMessenger ServerMessenger { get; } = new LocalServerMessenger(); + + private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); protected override AppCaches GetAppCaches() { @@ -330,6 +328,10 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping : base(false) { } + public override void SendMessages() { } + + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { throw new NotImplementedException(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs index 4dbc7b3efc..3c03be2a95 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs @@ -21,6 +21,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private ILocalizedTextService LocalizedTextService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); + private IJsonSerializer JsonSerializer => GetRequiredService(); /// /// This tests validates that with the new scope changes that the underlying cache policies work - in this case it tests that the cache policy @@ -29,7 +30,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services [Test] public void DataTypeService_Can_Get_All() { - IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; DataTypeService.Save(dataType); //Get all the first time (no cache) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs index d5f9f41cbb..68ec7fcf5f 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Sync; @@ -21,14 +21,13 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public class ContentEventsTests : UmbracoIntegrationTestWithContent { private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); + private IUmbracoContextFactory UmbracoContextFactory => GetRequiredService(); + private ILogger Logger => GetRequiredService>(); #region Setup - // trace ContentRepository unit-of-work events (refresh, remove), and ContentCacheRefresher CacheUpdated event - // - [SetUp] public void SetUp() { @@ -52,20 +51,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services ContentTypeService.Save(_contentType); } - // protected override void Compose() - // { - // base.Compose(); - // - // Composition.Register(_ => new TestServerRegistrar()); // localhost-only - // composition.Services.AddUnique(); - // - // Composition.WithCollectionBuilder() - // .Add() - // .Add() - // .Add(); - // } - - [TearDown] public void TearDownTest() { @@ -2181,6 +2166,10 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public LocalServerMessenger() : base(false) { } + public override void SendMessages() { } + + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs index 837536d362..10fe206290 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -22,45 +22,50 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { + /// /// Tests covering all methods in the ContentService class. /// [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, + [UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] public class ContentServiceTests : UmbracoIntegrationTestWithContent { // TODO: Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating. // TODO: Add test to delete specific version (with and without deleting prior versions) and versions by date. - - private IMediaTypeService MediaTypeService => GetRequiredService(); - private MediaService MediaService => (MediaService)GetRequiredService(); private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IAuditService AuditService => GetRequiredService(); + private IUserService UserService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); + private ILocalizedTextService TextService => GetRequiredService(); + private ITagService TagService => GetRequiredService(); + private IPublicAccessService PublicAccessService => GetRequiredService(); + private IDomainService DomainService => GetRequiredService(); + private INotificationService NotificationService => GetRequiredService(); + private PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); + private IDocumentRepository DocumentRepository => GetRequiredService(); + private IJsonSerializer Serializer => GetRequiredService(); [SetUp] - public void Setup() - { - ContentRepositoryBase.ThrowOnWarning = true; - } + public void Setup() => ContentRepositoryBase.ThrowOnWarning = true; [TearDown] - public void Teardown() - { - ContentRepositoryBase.ThrowOnWarning = false; - } + public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false; [Test] public void Create_Blueprint() @@ -444,54 +449,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services Assert.That(content.HasIdentity, Is.False); } - [Test] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, - PublishedRepositoryEvents = true, - WithApplication = true, - Boot = true)] - public void Automatically_Track_Relations() - { - var mt = MediaTypeBuilder.CreateSimpleMediaType("testMediaType", "Test Media Type"); - MediaTypeService.Save(mt); - var m1 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); - var m2 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); - MediaService.Save(m1); - MediaService.Save(m2); - - var template = TemplateBuilder.CreateTextPageTemplate(); - FileService.SaveTemplate(template); - - var ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest", defaultTemplateId: template.Id); - ct.AllowedTemplates = Enumerable.Empty(); - - ContentTypeService.Save(ct); - - var c1 = ContentBuilder.CreateTextpageContent(ct, "my content 1", -1); - ContentService.Save(c1); - - var c2 = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1); - - //'bodyText' is a property with a RTE property editor which we knows tracks relations - c2.Properties["bodyText"].SetValue(@"

- -

-

-

- hello -

"); - - ContentService.Save(c2); - - var relations = RelationService.GetByParentId(c2.Id).ToList(); - Assert.AreEqual(3, relations.Count); - Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[0].RelationType.Alias); - Assert.AreEqual(m1.Id, relations[0].ChildId); - Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[1].RelationType.Alias); - Assert.AreEqual(m2.Id, relations[1].ChildId); - Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedDocumentAlias, relations[2].RelationType.Alias); - Assert.AreEqual(c1.Id, relations[2].ChildId); - } - [Test] public void Can_Create_Content_Without_Explicitly_Set_User() { @@ -2326,7 +2283,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // This sleep ensures the save is called on later ticks then the SetValue and SetCultureName. Therefore // we showcase the currect lack of handling dirty on variants on save. When this is implemented the sleep // helps showcase the functionality is actually working - Thread.Sleep(1); + Thread.Sleep(5); ContentService.Save(page); var versionId5 = page.VersionId; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index d11210c093..b52609ce89 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -1,19 +1,25 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; using Umbraco.Core.Sync; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Net; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.NuCache; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { @@ -23,11 +29,24 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest { private ISqlContext SqlContext => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IRedirectUrlService RedirectUrlService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + protected override void BeforeHostStart(IHost host) + { + base.BeforeHostStart(host); + + // Ensure that the events are bound on each test + PublishedSnapshotServiceEventHandler eventBinder = host.Services.GetRequiredService(); + eventBinder.Initialize(); + } + private void AssertJsonStartsWith(int id, string expected) { var json = GetJson(id).Replace('"', '\''); @@ -510,7 +529,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { // one simple content type, variant, with both variant and invariant properties // can change it to invariant and back - GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var contentType = CreateContentType(ContentVariation.Culture); @@ -599,8 +617,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // one simple content type, invariant // can change it to variant and back // can then switch one property to variant - GetRequiredService(); //hack to ensure events are initialized - var globalSettings = new GlobalSettings(); var languageEn = new Language(globalSettings, "en") { IsDefault = true }; @@ -690,7 +706,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { // one simple content type, variant, with both variant and invariant properties // can change an invariant property to variant and back - GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var contentType = CreateContentType(ContentVariation.Culture); @@ -885,7 +900,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { // one simple content type, variant, with both variant and invariant properties // can change an invariant property to variant and back - CreateFrenchAndEnglishLangs(); var contentType = CreateContentType(ContentVariation.Culture | ContentVariation.Segment); @@ -966,9 +980,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // one composed content type, variant, with both variant and invariant properties // can change the composing content type to invariant and back // can change the composed content type to invariant and back - - - GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var composing = CreateContentType(ContentVariation.Culture, "composing"); @@ -1063,8 +1074,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // one composed content type, invariant // can change the composing content type to invariant and back // can change the variant composed content type to invariant and back - - GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var composing = CreateContentType(ContentVariation.Culture, "composing"); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs index 0af3ae6fb5..2de7fb6b2a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs @@ -26,12 +26,13 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private ILocalizedTextService LocalizedTextService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); + private IJsonSerializer JsonSerializer => GetRequiredService(); [Test] public void DataTypeService_Can_Persist_New_DataTypeDefinition() { // Act - IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; DataTypeService.Save(dataType); // Assert @@ -74,7 +75,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public void Cannot_Save_DataType_With_Empty_Name() { // Act - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper, JsonSerializer), ConfigurationEditorJsonSerializer) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; // Act & Assert Assert.Throws(() => DataTypeService.Save(dataTypeDefinition)); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs index b7ab3ceea1..6d5cf19b50 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -42,11 +42,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services [SetUp] public void SetupTestData() { - - //This is super nasty, but this lets us initialize the cache while it is empty. - var publishedSnapshotService = GetRequiredService() as PublishedSnapshotService; - publishedSnapshotService?.OnApplicationInit(null, EventArgs.Empty); - if (_langFr == null && _langEs == null) { var globalSettings = new GlobalSettings(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs index a0068f8c3d..8a04caeac7 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; -using Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing; +using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services diff --git a/src/Umbraco.Tests/Services/Importing/CheckboxList-Content-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/CheckboxList-Content-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CheckboxList-Content-Package.xml diff --git a/src/Umbraco.Tests/Services/Importing/CompositionsTestPackage-Random.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/CompositionsTestPackage-Random.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage-Random.xml diff --git a/src/Umbraco.Tests/Services/Importing/CompositionsTestPackage.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/CompositionsTestPackage.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/CompositionsTestPackage.xml diff --git a/src/Umbraco.Tests/Services/Importing/Fanoe-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/Fanoe-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Fanoe-Package.xml diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs index 488108ebda..f7e0541d95 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing { +namespace Umbraco.Tests.Services.Importing { using System; @@ -19,7 +19,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class ImportResources { @@ -61,6 +61,88 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing { } } + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>CheckboxListTest</name> + /// <version>1</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> + /// <url>1</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>1</name> + /// <website>1</website> + /// </author> + /// <r [rest of string was truncated]";. + /// + internal static string CheckboxList_Content_Package { + get { + return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Compositions Packaged</name> + /// <version>1.0</version> + /// <license url="http://opensource.org/licenses/MIT">MIT License</license> + /// <url>http://blog.sitereactor.dk</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Morten Christensen</name> + /// <website>h [rest of string was truncated]";. + /// + internal static string CompositionsTestPackage { + get { + return ResourceManager.GetString("CompositionsTestPackage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Composite Test</name> + /// <version>dfsfd</version> + /// <license url="http://opensource.org/licenses/MIT">MIT License</license> + /// <url>ddsff</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>fsdfds</name> + /// <website>sfdf</website> + /// </author> + /// <rea [rest of string was truncated]";. + /// + internal static string CompositionsTestPackage_Random { + get { + return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture); + } + } + /// /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> ///<umbPackage> @@ -86,5 +168,243 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing { return ResourceManager.GetString("Dictionary_Package", resourceCulture); } } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>bootstrap.min.js</guid> + /// <orgPath>/js</orgPath> + /// <orgName>bootstrap.min.js</orgName> + /// </file> + /// <file> + /// <guid>jquery.min.js</guid> + /// <orgPath>/js</orgPath> + /// <orgName>jquery.min.js</orgName> + /// </file> + /// <file> + /// <guid>top-image.jpg</guid> + /// <orgPath>/Media/1001</orgPath> + /// <orgName>top-image.jpg</orgName> + /// </file> + /// <file> + /// <guid>top-im [rest of string was truncated]";. + /// + internal static string Fanoe_Package { + get { + return ResourceManager.GetString("Fanoe_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>DocTypeError</name> + /// <version>1</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">Personal license</license> + /// <url>http://www.iseli-webconsulting.de</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Iseli Webconsulting</name> [rest of string was truncated]";. + /// + internal static string InheritedDocTypes_Package { + get { + return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Package With MediaTypes And Media + Folder</name> + /// <version>1.0.0</version> + /// <iconUrl></iconUrl> + /// <license url="http://opensource.org/licenses/MIT">MIT License</license> + /// <url>http://www.umbraco.com</url> + /// <requirements type="Strict"> + /// <major>0</major> + /// <minor>5</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name [rest of string was truncated]";. + /// + internal static string MediaTypesAndMedia_Package_xml { + get { + return ResourceManager.GetString("MediaTypesAndMedia_Package.xml", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<DocumentType> + /// <Info> + /// <Name>test</Name> + /// <Alias>test</Alias> + /// <Icon>folder.gif</Icon> + /// <Thumbnail>folder.png</Thumbnail> + /// <Description> + /// </Description> + /// <AllowAtRoot>False</AllowAtRoot> + /// <AllowedTemplates> + /// <Template>test</Template> + /// </AllowedTemplates> + /// <DefaultTemplate>test</DefaultTemplate> + /// </Info> + /// <Structure> + /// <DocumentType>test</DocumentType> + /// </Structure> + /// <GenericProperties> + /// <GenericProperty> [rest of string was truncated]";. + /// + internal static string SingleDocType { + get { + return ResourceManager.GetString("SingleDocType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>Map.cshtml</guid> + /// <orgPath>/macroScripts</orgPath> + /// <orgName>Map.cshtml</orgName> + /// </file> + /// <file> + /// <guid>AccountController.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>AccountController.cs</orgName> + /// </file> + /// <file> + /// <guid>ContactController.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>ContactController.cs</orgName> + /// </file> + /// [rest of string was truncated]";. + /// + internal static string StandardMvc_Package { + get { + return ResourceManager.GetString("StandardMvc_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Template-Update</name> + /// <version>0.1</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> + /// <url>https://our.umbraco.com/projects</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Morten Christensen</name> + /// [rest of string was truncated]";. + /// + internal static string TemplateOnly_Package { + get { + return ResourceManager.GetString("TemplateOnly_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Template-Update</name> + /// <version>0.1</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> + /// <url>https://our.umbraco.com/projects</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Morten Christensen</name> + /// [rest of string was truncated]";. + /// + internal static string TemplateOnly_Updated_Package { + get { + return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>uBlogsy.BusinessLogic.dll</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.BusinessLogic.dll</orgName> + /// </file> + /// <file> + /// <guid>uBlogsy.BusinessLogic.pdb</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.BusinessLogic.pdb</orgName> + /// </file> + /// <file> + /// <guid>uBlogsy.Common.dll</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.Common.dll</orgNam [rest of string was truncated]";. + /// + internal static string uBlogsy_Package { + get { + return ResourceManager.GetString("uBlogsy_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>XSLTsearch.xslt</guid> + /// <orgPath>/xslt</orgPath> + /// <orgName>XSLTsearch.xslt</orgName> + /// </file> + /// <file> + /// <guid>XSLTsearch.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>XSLTsearch.cs</orgName> + /// </file> + /// </files> + /// <info> + /// <package> + /// <name>XSLTsearch</name> + /// <version>3.0.4</version> + /// <license url="http://www.opensource.org/licenses/mit-li [rest of string was truncated]";. + /// + internal static string XsltSearch_Package { + get { + return ResourceManager.GetString("XsltSearch_Package", resourceCulture); + } + } } } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx index 5823fa1245..e8029b6520 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx @@ -1,17 +1,17 @@  - @@ -118,7 +118,43 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - dictionary-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + InheritedDocTypes-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - \ No newline at end of file + + StandardMvc-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + uBlogsy-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + XsltSearch-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + SingleDocType.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TemplateOnly-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + TemplateOnly-Updated-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + CheckboxList-Content-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + Dictionary-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + CompositionsTestPackage.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + CompositionsTestPackage-Random.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + Fanoe-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + MediaTypesAndMedia-Package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + diff --git a/src/Umbraco.Tests/Services/Importing/InheritedDocTypes-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/InheritedDocTypes-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/InheritedDocTypes-Package.xml diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml new file mode 100644 index 0000000000..e51fee48f8 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/MediaTypesAndMedia-Package.xml @@ -0,0 +1,158 @@ + + + + + + Package With MediaTypes And Media + Folder + 1.0.0 + + MIT License + http://www.umbraco.com + + 0 + 5 + 0 + + + + dteam + http://www.umbraco.com + + + + + + + + + Folder + Folder + icon-folder + icon-folder + + True + + + Folder + Image + File + + + + + + + Image + Image + icon-picture + icon-picture + + True + + + + + Upload image + umbracoFile + Umbraco.ImageCropper + 1df9f033-e6d4-451f-b8d2-e0cbc50a836f + Image + True + + + + false + + + + Width + umbracoWidth + Umbraco.Label + 8e7f995c-bd81-4627-9932-c40e568ec788 + Image + False + + + + false + + + + Height + umbracoHeight + Umbraco.Label + 8e7f995c-bd81-4627-9932-c40e568ec788 + Image + False + + + + false + + + + Size + umbracoBytes + Umbraco.Label + 930861bf-e262-4ead-a704-f99453565708 + Image + False + + + + false + + + + Type + umbracoExtension + Umbraco.Label + f0bc4bfb-b499-40d6-ba86-058885a5178c + Image + False + + + + false + + + + + + 3 + Image + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/SingleDocType.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/SingleDocType.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/SingleDocType.xml diff --git a/src/Umbraco.Tests/Services/Importing/StandardMvc-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/StandardMvc-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/StandardMvc-Package.xml diff --git a/src/Umbraco.Tests/Services/Importing/TemplateOnly-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/TemplateOnly-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/TemplateOnly-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/TemplateOnly-Package.xml diff --git a/src/Umbraco.Tests/Services/Importing/TemplateOnly-Updated-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/TemplateOnly-Updated-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/TemplateOnly-Updated-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/TemplateOnly-Updated-Package.xml diff --git a/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/XsltSearch-Package.xml diff --git a/src/Umbraco.Tests/Services/Importing/uBlogsy-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml similarity index 100% rename from src/Umbraco.Tests/Services/Importing/uBlogsy-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/uBlogsy-Package.xml diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs index 1d3b799679..9600d62051 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs @@ -1,8 +1,9 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; @@ -31,7 +32,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services [TestFixture] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)] public class ThreadSafetyServiceTest : UmbracoIntegrationTest { private IContentService ContentService => GetRequiredService(); @@ -98,13 +99,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services if (Environment.GetEnvironmentVariable("UMBRACO_TMP") != null) Assert.Ignore("Do not run on VSTS."); + var log = GetRequiredService>(); + // the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton var contentService = (ContentService)ContentService; var threads = new List(); var exceptions = new List(); - Debug.WriteLine("Starting..."); + log.LogInformation("Starting..."); var done = TraceLocks(); @@ -114,12 +117,12 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { try { - Debug.WriteLine("[{0}] Running...", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Running...", Thread.CurrentThread.ManagedThreadId); var name1 = "test-" + Guid.NewGuid(); var content1 = contentService.Create(name1, -1, "umbTextpage"); - Debug.WriteLine("[{0}] Saving content #1.", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Saving content #1.", Thread.CurrentThread.ManagedThreadId); Save(contentService, content1); Thread.Sleep(100); //quick pause for maximum overlap! @@ -127,7 +130,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var name2 = "test-" + Guid.NewGuid(); var content2 = contentService.Create(name2, -1, "umbTextpage"); - Debug.WriteLine("[{0}] Saving content #2.", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Saving content #2.", Thread.CurrentThread.ManagedThreadId); Save(contentService, content2); } catch (Exception e) @@ -139,16 +142,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services } // start all threads - Debug.WriteLine("Starting threads"); + log.LogInformation("Starting threads"); threads.ForEach(x => x.Start()); // wait for all to complete - Debug.WriteLine("Joining threads"); + log.LogInformation("Joining threads"); threads.ForEach(x => x.Join()); done.Set(); - Debug.WriteLine("Checking exceptions"); + log.LogInformation("Checking exceptions"); if (exceptions.Count == 0) { //now look up all items, there should be 40! @@ -166,13 +169,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { if (Environment.GetEnvironmentVariable("UMBRACO_TMP") != null) Assert.Ignore("Do not run on VSTS."); + + var log = GetRequiredService>(); + // mimick the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton var mediaService = (MediaService)MediaService; var threads = new List(); var exceptions = new List(); - Debug.WriteLine("Starting..."); + log.LogInformation("Starting..."); var done = TraceLocks(); @@ -182,18 +188,18 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { try { - Debug.WriteLine("[{0}] Running...", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Running...", Thread.CurrentThread.ManagedThreadId); var name1 = "test-" + Guid.NewGuid(); var media1 = mediaService.CreateMedia(name1, -1, Constants.Conventions.MediaTypes.Folder); - Debug.WriteLine("[{0}] Saving media #1.", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Saving media #1.", Thread.CurrentThread.ManagedThreadId); Save(mediaService, media1); Thread.Sleep(100); //quick pause for maximum overlap! var name2 = "test-" + Guid.NewGuid(); var media2 = mediaService.CreateMedia(name2, -1, Constants.Conventions.MediaTypes.Folder); - Debug.WriteLine("[{0}] Saving media #2.", Thread.CurrentThread.ManagedThreadId); + log.LogInformation("[{0}] Saving media #2.", Thread.CurrentThread.ManagedThreadId); Save(mediaService, media2); } catch (Exception e) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs new file mode 100644 index 0000000000..e6a8104355 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs @@ -0,0 +1,72 @@ +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services +{ + [UmbracoTest( + Database = UmbracoTestOptions.Database.NewSchemaPerTest, + PublishedRepositoryEvents = true, + WithApplication = true, + Boot = true)] + public class TrackRelationsTests : UmbracoIntegrationTestWithContent + { + private IMediaTypeService MediaTypeService => GetRequiredService(); + + private IMediaService MediaService => GetRequiredService(); + + private IRelationService RelationService => GetRequiredService(); + + [Test] + public void Automatically_Track_Relations() + { + var mt = MediaTypeBuilder.CreateSimpleMediaType("testMediaType", "Test Media Type"); + MediaTypeService.Save(mt); + var m1 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); + var m2 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); + MediaService.Save(m1); + MediaService.Save(m2); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest", defaultTemplateId: template.Id); + ct.AllowedTemplates = Enumerable.Empty(); + + ContentTypeService.Save(ct); + + var c1 = ContentBuilder.CreateTextpageContent(ct, "my content 1", -1); + ContentService.Save(c1); + + var c2 = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1); + + // 'bodyText' is a property with a RTE property editor which we knows tracks relations + c2.Properties["bodyText"].SetValue(@"

+ +

+

+

+ hello +

"); + + ContentService.Save(c2); + + var relations = RelationService.GetByParentId(c2.Id).ToList(); + Assert.AreEqual(3, relations.Count); + Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[0].RelationType.Alias); + Assert.AreEqual(m1.Id, relations[0].ChildId); + Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[1].RelationType.Alias); + Assert.AreEqual(m2.Id, relations[1].ChildId); + Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedDocumentAlias, relations[2].RelationType.Alias); + Assert.AreEqual(c1.Id, relations[2].ChildId); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index c5b42f9848..0614405e41 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -7,6 +7,10 @@ 8 + + IS_WINDOWS + + @@ -15,6 +19,16 @@ + + ResXFileCodeGenerator + ImportResources.Designer.cs + Designer + + + True + True + ImportResources.resx + @@ -22,7 +36,22 @@ + + Designer + + + + + + + + Designer + + + + + @@ -54,20 +83,4 @@ - - - ImportResources.resx - True - True - - - - - - Designer - ImportResources.Designer.cs - ResXFileCodeGenerator - - - diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs index 2960455a70..dc88455d68 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -13,7 +13,6 @@ using Umbraco.Core.IO; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -273,8 +272,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.Backoffice.Filters public class ComplexTestEditor : NestedContentPropertyEditor { public ComplexTestEditor(ILoggerFactory loggerFactory, Lazy propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizationService localizationService, - IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(loggerFactory, propertyEditors, dataTypeService, localizationService, contentTypeService, ioHelper, shortStringHelper, localizedTextService) + IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IJsonSerializer jsonSerializer) + : base(loggerFactory, propertyEditors, dataTypeService, localizationService, contentTypeService, ioHelper, shortStringHelper, localizedTextService, jsonSerializer) { } @@ -290,17 +289,19 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.Backoffice.Filters [DataEditor("test", "test", "test")] // This alias aligns with the prop editor alias for all properties created from MockedContentTypes.CreateTextPageContentType public class TestEditor : DataEditor { - public TestEditor(ILoggerFactory loggerFactory, - IDataTypeService dataTypeService, - ILocalizationService localizationService, - ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public TestEditor( + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { } - protected override IDataValueEditor CreateValueEditor() => new TestValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new TestValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, JsonSerializer, Attribute); private class TestValueEditor : DataValueEditor { @@ -309,8 +310,9 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.Backoffice.Filters ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { Validators.Add(new NeverValidateValidator()); } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/MembersServiceCollectionExtensionsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/MembersServiceCollectionExtensionsTests.cs index 4991df7bd1..8dd4bee0cf 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/MembersServiceCollectionExtensionsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/MembersServiceCollectionExtensionsTests.cs @@ -1,17 +1,18 @@ -using System; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; -using Umbraco.Extensions; +using Umbraco.Core.DependencyInjection; using Umbraco.Infrastructure.Security; using Umbraco.Tests.Integration.Testing; -using Umbraco.Web.BackOffice.Extensions; +using Umbraco.Web.BackOffice.DependencyInjection; namespace Umbraco.Tests.Integration.Umbraco.Web.BackOffice { [TestFixture] public class MembersServiceCollectionExtensionsTests : UmbracoIntegrationTest { + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.Services.AddMembersIdentity(); + [Test] public void AddMembersIdentity_ExpectMembersUserStoreResolvable() { @@ -28,7 +29,5 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.BackOffice Assert.NotNull(userManager); } - - protected override Action CustomTestSetup => (services) => services.AddMembersIdentity(); } } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs index d9dee389ee..37863da472 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs @@ -1,17 +1,18 @@ -using System; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Security; -using Umbraco.Extensions; using Umbraco.Tests.Integration.Testing; -using Umbraco.Web.Common.Security; +using Umbraco.Web.BackOffice.DependencyInjection; namespace Umbraco.Tests.Integration.Umbraco.Web.BackOffice { [TestFixture] public class UmbracoBackOfficeServiceCollectionExtensionsTests : UmbracoIntegrationTest { + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.Services.AddUmbracoBackOfficeIdentity(); + [Test] public void AddUmbracoBackOfficeIdentity_ExpectBackOfficeUserStoreResolvable() { @@ -37,7 +38,5 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.BackOffice Assert.NotNull(userManager); } - - protected override Action CustomTestSetup => (services) => services.AddUmbracoBackOfficeIdentity(); } } diff --git a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs index 3eb7a83224..b0eac41478 100644 --- a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs @@ -1,6 +1,7 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; -using System.Linq; -using System.Reflection; using AutoFixture; using AutoFixture.AutoMoq; using AutoFixture.Kernel; @@ -14,7 +15,6 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Security; -using Umbraco.Tests.Common.Builders; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Install; @@ -23,20 +23,6 @@ using Umbraco.Web.WebApi; namespace Umbraco.Tests.UnitTests.AutoFixture { - - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = true)] - public class InlineAutoMoqDataAttribute : InlineAutoDataAttribute - { - /// - /// Uses AutoFixture to automatically mock (using Moq) the injected types. E.g when injecting interfaces. - /// AutoFixture is used to generate concrete types. If the concrete type required some types injected, the - /// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test - /// - public InlineAutoMoqDataAttribute(params object[] arguments) : base(() => AutoMoqDataAttribute.AutoMockCustomizations.Default, arguments) - { - } - } - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)] public class AutoMoqDataAttribute : AutoDataAttribute { @@ -45,7 +31,8 @@ namespace Umbraco.Tests.UnitTests.AutoFixture /// AutoFixture is used to generate concrete types. If the concrete type required some types injected, the /// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test ///
- public AutoMoqDataAttribute() : base(() => AutoMockCustomizations.Default) + public AutoMoqDataAttribute() + : base(() => AutoMockCustomizations.Default) { } @@ -58,8 +45,8 @@ namespace Umbraco.Tests.UnitTests.AutoFixture public void Customize(IFixture fixture) { fixture.Customize( - u => u.FromFactory( - (a,b,c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(),a,b,c))); + u => u.FromFactory( + (a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c))); fixture .Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery())) @@ -69,6 +56,7 @@ namespace Umbraco.Tests.UnitTests.AutoFixture .Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery())); fixture.Customize(new AutoMoqCustomization()); + // When requesting an IUserStore ensure we actually uses a IUserLockoutStore fixture.Customize>(cc => cc.FromFactory(() => Mock.Of>())); @@ -94,13 +82,11 @@ namespace Umbraco.Tests.UnitTests.AutoFixture Mock.Of(x => x.Level == RuntimeLevel.Run)))); var connectionStrings = new ConnectionStrings(); - fixture.Customize(x => x.FromFactory(() => connectionStrings )); - + fixture.Customize(x => x.FromFactory(() => connectionStrings)); var httpContextAccessor = new HttpContextAccessor { HttpContext = new DefaultHttpContext() }; fixture.Customize(x => x.FromFactory(() => httpContextAccessor.HttpContext)); fixture.Customize(x => x.FromFactory(() => httpContextAccessor)); - } } } diff --git a/src/Umbraco.Tests.UnitTests/AutoFixture/InlineAutoMoqDataAttribute.cs b/src/Umbraco.Tests.UnitTests/AutoFixture/InlineAutoMoqDataAttribute.cs new file mode 100644 index 0000000000..0c182e6116 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/InlineAutoMoqDataAttribute.cs @@ -0,0 +1,22 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using AutoFixture.NUnit3; + +namespace Umbraco.Tests.UnitTests.AutoFixture +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = true)] + public class InlineAutoMoqDataAttribute : InlineAutoDataAttribute + { + /// + /// Uses AutoFixture to automatically mock (using Moq) the injected types. E.g when injecting interfaces. + /// AutoFixture is used to generate concrete types. If the concrete type required some types injected, the + /// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test + /// + public InlineAutoMoqDataAttribute(params object[] arguments) + : base(() => AutoMoqDataAttribute.AutoMockCustomizations.Default, arguments) + { + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs index 52bc1880a3..d6db3c09f6 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs @@ -1,18 +1,18 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NPoco; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Tests.UnitTests.TestHelpers; -using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.TestHelpers { @@ -23,26 +23,22 @@ namespace Umbraco.Tests.TestHelpers protected ISqlContext SqlContext { get; private set; } - protected Sql Sql() - { - return NPoco.Sql.BuilderFor(SqlContext); - } + protected Sql Sql() => NPoco.Sql.BuilderFor(SqlContext); [SetUp] public virtual void Setup() { - var container = TestHelper.GetServiceCollection(); - var typeLoader = TestHelper.GetMockedTypeLoader(); + IServiceCollection container = TestHelper.GetServiceCollection(); + TypeLoader typeLoader = TestHelper.GetMockedTypeLoader(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); - composition.WithCollectionBuilder() .AddCoreMappers(); - composition.Services.AddUnique(_ => SqlContext); + composition.Services.AddUnique(_ => SqlContext); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); var pocoMappers = new NPoco.MapperCollection { new PocoMapper() }; var pocoDataFactory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, pocoMappers).Init()); var sqlSyntax = new SqlServerSyntaxProvider(); diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs index 5481bfcd76..806878fcc3 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs @@ -1,7 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; namespace Umbraco.Tests.UnitTests.TestHelpers { diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs index 7889d49192..91d05ba0df 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs @@ -1,16 +1,17 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Moq; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Security; -using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Web; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Web.Security; namespace Umbraco.Tests.UnitTests.TestHelpers.Objects { @@ -19,15 +20,31 @@ namespace Umbraco.Tests.UnitTests.TestHelpers.Objects /// public class TestUmbracoContextFactory { - public static IUmbracoContextFactory Create(GlobalSettings globalSettings = null, + public static IUmbracoContextFactory Create( + GlobalSettings globalSettings = null, IUmbracoContextAccessor umbracoContextAccessor = null, IHttpContextAccessor httpContextAccessor = null, IPublishedUrlProvider publishedUrlProvider = null) { - if (globalSettings == null) globalSettings = new GlobalSettings(); - if (umbracoContextAccessor == null) umbracoContextAccessor = new TestUmbracoContextAccessor(); - if (httpContextAccessor == null) httpContextAccessor = Mock.Of(); - if (publishedUrlProvider == null) publishedUrlProvider = Mock.Of(); + if (globalSettings == null) + { + globalSettings = new GlobalSettings(); + } + + if (umbracoContextAccessor == null) + { + umbracoContextAccessor = new TestUmbracoContextAccessor(); + } + + if (httpContextAccessor == null) + { + httpContextAccessor = Mock.Of(); + } + + if (publishedUrlProvider == null) + { + publishedUrlProvider = Mock.Of(); + } var contentCache = new Mock(); var mediaCache = new Mock(); @@ -37,11 +54,10 @@ namespace Umbraco.Tests.UnitTests.TestHelpers.Objects var snapshotService = new Mock(); snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(snapshot.Object); - var hostingEnvironment = Mock.Of(); + IHostingEnvironment hostingEnvironment = Mock.Of(); var backofficeSecurityAccessorMock = new Mock(); backofficeSecurityAccessorMock.Setup(x => x.BackOfficeSecurity).Returns(Mock.Of()); - - + var umbracoContextFactory = new UmbracoContextFactory( umbracoContextAccessor, snapshotService.Object, @@ -52,8 +68,7 @@ namespace Umbraco.Tests.UnitTests.TestHelpers.Objects new UriUtility(hostingEnvironment), new AspNetCoreCookieManager(httpContextAccessor), Mock.Of(), - backofficeSecurityAccessorMock.Object - ); + backofficeSecurityAccessorMock.Object); return umbracoContextFactory; } diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs index e7d6eec391..b23ccc9080 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -1,42 +1,45 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; -using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Net; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; +using Umbraco.Infrastructure.Persistence.Mappers; +using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Web; +using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Routing; using File = System.IO.File; -using Microsoft.Extensions.Options; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Web.Common.AspNetCore; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; -using Umbraco.Infrastructure.Persistence.Mappers; namespace Umbraco.Tests.TestHelpers { @@ -45,14 +48,13 @@ namespace Umbraco.Tests.TestHelpers /// public static class TestHelper { - private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal(); - private static IEmailSender _emailSender; + private static readonly TestHelperInternal s_testHelperInternal = new TestHelperInternal(); private class TestHelperInternal : TestHelperBase { - public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly) + public TestHelperInternal() + : base(typeof(TestHelperInternal).Assembly) { - } public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = Mock.Of(); @@ -68,9 +70,9 @@ namespace Umbraco.Tests.TestHelpers { var testPath = TestContext.CurrentContext.TestDirectory.Split("bin")[0]; return new AspNetCoreHostingEnvironment( - Mock.Of>(x=>x.CurrentValue == new HostingSettings()), + Mock.Of>(x => x.CurrentValue == new HostingSettings()), Mock.Of( - x=> + x => x.WebRootPath == "/" && x.ContentRootPath == testPath)); } @@ -82,13 +84,13 @@ namespace Umbraco.Tests.TestHelpers => Mock.Of(); } - public static ITypeFinder GetTypeFinder() => _testHelperInternal.GetTypeFinder(); + public static ITypeFinder GetTypeFinder() => s_testHelperInternal.GetTypeFinder(); - public static TypeLoader GetMockedTypeLoader() => _testHelperInternal.GetMockedTypeLoader(); + public static TypeLoader GetMockedTypeLoader() => s_testHelperInternal.GetMockedTypeLoader(); public static Lazy GetMockSqlContext() { - var sqlContext = Mock.Of(); + ISqlContext sqlContext = Mock.Of(); var syntax = new SqlServerSyntaxProvider(); Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(syntax); return new Lazy(() => sqlContext); @@ -97,50 +99,48 @@ namespace Umbraco.Tests.TestHelpers public static MapperConfigurationStore CreateMaps() => new MapperConfigurationStore(); - //public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); + //// public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); - public static IBackOfficeInfo GetBackOfficeInfo() => _testHelperInternal.GetBackOfficeInfo(); + public static IBackOfficeInfo GetBackOfficeInfo() => s_testHelperInternal.GetBackOfficeInfo(); - // public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); + //// public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); /// /// Gets the working directory of the test project. /// /// The assembly directory. - public static string WorkingDirectory => _testHelperInternal.WorkingDirectory; + public static string WorkingDirectory => s_testHelperInternal.WorkingDirectory; - 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; - public static CoreDebugSettings CoreDebugSettings => _testHelperInternal.CoreDebugSettings; + public static IShortStringHelper ShortStringHelper => s_testHelperInternal.ShortStringHelper; + public static IJsonSerializer JsonSerializer => s_testHelperInternal.JsonSerializer; - public static IIOHelper IOHelper => _testHelperInternal.IOHelper; - public static IMainDom MainDom => _testHelperInternal.MainDom; - public static UriUtility UriUtility => _testHelperInternal.UriUtility; + 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())); - /// /// 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 static string MapPathForTestFiles(string relativePath) => _testHelperInternal.MapPathForTestFiles(relativePath); + 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 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 CleanContentDirectories() => CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath }); public static void CreateDirectories(string[] directories) { @@ -148,7 +148,9 @@ namespace Umbraco.Tests.TestHelpers { var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory)); if (directoryInfo.Exists == false) + { Directory.CreateDirectory(IOHelper.MapPath(directory)); + } } } @@ -156,15 +158,20 @@ namespace Umbraco.Tests.TestHelpers { var preserves = new Dictionary { - { Constants.SystemDirectories.MvcViews, new[] {"dummy.txt"} } + { 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 (var x in directoryInfo.GetFiles().Where(x => preserve == null || preserve.Contains(x.Name) == false)) - x.Delete(); + { + foreach (FileInfo fileInfo in directoryInfo.GetFiles().Where(x => preserve == null || preserve.Contains(x.Name) == false)) + { + fileInfo.Delete(); + } + } } } @@ -174,7 +181,9 @@ namespace Umbraco.Tests.TestHelpers var umbracoSettingsFile = Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"); if (File.Exists(umbracoSettingsFile)) + { File.Delete(umbracoSettingsFile); + } } // TODO: Move to Assertions or AssertHelper @@ -183,17 +192,21 @@ namespace Umbraco.Tests.TestHelpers { const int dateDeltaMilliseconds = 500; // .5s - var properties = expected.GetType().GetProperties(); - foreach (var property in properties) + PropertyInfo[] properties = expected.GetType().GetProperties(); + foreach (PropertyInfo property in properties) { // ignore properties that are attributed with EditorBrowsableState.Never - var att = property.GetCustomAttribute(false); + EditorBrowsableAttribute att = property.GetCustomAttribute(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); @@ -204,31 +217,36 @@ namespace Umbraco.Tests.TestHelpers private static void AssertAreEqual(PropertyInfo property, object expected, object actual, Func sorter = null, int dateDeltaMilliseconds = 0) { - if (!(expected is string) && expected is IEnumerable) + 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); + { + sorter = e => ((PropertyCollection)e).OrderBy(x => x.Alias); + } // compare lists - AssertListsAreEqual(property, (IEnumerable) actual, (IEnumerable) expected, sorter, dateDeltaMilliseconds); + AssertListsAreEqual(property, (IEnumerable)actual, enumerable, sorter, dateDeltaMilliseconds); } else if (expected is DateTime expectedDateTime) { // compare date & time with delta - var actualDateTime = (DateTime) actual; + 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(); + 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}\"."); @@ -238,22 +256,27 @@ namespace Umbraco.Tests.TestHelpers else if (expected is IDataEditor expectedEditor) { Assert.IsInstanceOf(actual); - var actualEditor = (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() ?? "", actual?.ToString() ?? ""); + Assert.AreEqual( + expected, + actual, + "Property {0}.{1} does not match. Expected: {2} but was: {3}", + property.DeclaringType.Name, + property.Name, + expected?.ToString() ?? "", + actual?.ToString() ?? ""); } } private static void AssertListsAreEqual(PropertyInfo property, IEnumerable expected, IEnumerable actual, Func sorter = null, int dateDeltaMilliseconds = 0) { - - if (sorter == null) { // this is pretty hackerific but saves us some code to write @@ -261,7 +284,7 @@ namespace Umbraco.Tests.TestHelpers { // semi-generic way of ensuring any collection of IEntity are sorted by Ids for comparison var entities = enumerable.OfType().ToList(); - return entities.Count > 0 ? (IEnumerable) entities.OrderBy(x => x.Id) : entities; + return entities.Count > 0 ? (IEnumerable)entities.OrderBy(x => x.Id) : entities; }; } @@ -269,28 +292,30 @@ namespace Umbraco.Tests.TestHelpers var actualListEx = sorter(actual).Cast().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() => _testHelperInternal.GetUmbracoVersion(); + public static IUmbracoVersion GetUmbracoVersion() => s_testHelperInternal.GetUmbracoVersion(); public static IServiceCollection GetServiceCollection() => new ServiceCollection().AddLazySupport(); - public static IHostingEnvironment GetHostingEnvironment() => _testHelperInternal.GetHostingEnvironment(); + public static IHostingEnvironment GetHostingEnvironment() => s_testHelperInternal.GetHostingEnvironment(); - public static ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv) => _testHelperInternal.GetLoggingConfiguration(hostingEnv); + public static ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv) => s_testHelperInternal.GetLoggingConfiguration(hostingEnv); - public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _testHelperInternal.GetHostingEnvironmentLifetime(); + public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => s_testHelperInternal.GetHostingEnvironmentLifetime(); - public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver(); + public static IIpResolver GetIpResolver() => s_testHelperInternal.GetIpResolver(); - public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache(); + public static IRequestCache GetRequestCache() => s_testHelperInternal.GetRequestCache(); - public static IPublishedUrlProvider GetPublishedUrlProvider() => _testHelperInternal.GetPublishedUrlProvider(); + public static IPublishedUrlProvider GetPublishedUrlProvider() => s_testHelperInternal.GetPublishedUrlProvider(); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs index 544765ee9c..7d3099eb58 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/AttemptTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/AttemptTests.cs index 9a16c5b10f..be1e3cc0d8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/AttemptTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/AttemptTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; namespace Umbraco.Tests.UnitTests.Umbraco.Core @@ -9,10 +12,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void AttemptIf() { - // just making sure that it is ok to use TryParse as a condition - - int value; - var attempt = Attempt.If(int.TryParse("1234", out value), value); + // Just making sure that it is ok to use TryParse as a condition. + var attempt = Attempt.If(int.TryParse("1234", out int value), value); Assert.IsTrue(attempt.Success); Assert.AreEqual(1234, attempt.Result); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs index 64bdca6437..e681fc6841 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.Security.Claims; @@ -47,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice [Test] public void CreateAsync_When_User_Is_Null_Expect_ArgumentNullException() { - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); Assert.ThrowsAsync(async () => await sut.CreateAsync(null)); } @@ -55,9 +58,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice [Test] public async Task CreateAsync_Should_Create_Principal_With_Umbraco_Identity() { - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); - var claimsPrincipal = await sut.CreateAsync(_testUser); + ClaimsPrincipal claimsPrincipal = await sut.CreateAsync(_testUser); var umbracoBackOfficeIdentity = claimsPrincipal.Identity as UmbracoBackOfficeIdentity; Assert.IsNotNull(umbracoBackOfficeIdentity); @@ -67,9 +70,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice [TestCase(ClaimTypes.Name, TestUserName)] public async Task CreateAsync_Should_Include_Claim(string expectedClaimType, object expectedClaimValue) { - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); - var claimsPrincipal = await sut.CreateAsync(_testUser); + ClaimsPrincipal claimsPrincipal = await sut.CreateAsync(_testUser); Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue.ToString())); Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue.ToString())); @@ -84,9 +87,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice _mockUserManager.Setup(x => x.SupportsUserSecurityStamp).Returns(true); _mockUserManager.Setup(x => x.GetSecurityStampAsync(_testUser)).ReturnsAsync(_testUser.SecurityStamp); - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); - var claimsPrincipal = await sut.CreateAsync(_testUser); + ClaimsPrincipal claimsPrincipal = await sut.CreateAsync(_testUser); Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue)); Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue)); @@ -100,11 +103,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice _testUser.Roles.Add(new IdentityUserRole { RoleId = expectedClaimValue }); _mockUserManager.Setup(x => x.SupportsUserRole).Returns(true); - _mockUserManager.Setup(x => x.GetRolesAsync(_testUser)).ReturnsAsync(new[] {expectedClaimValue}); + _mockUserManager.Setup(x => x.GetRolesAsync(_testUser)).ReturnsAsync(new[] { expectedClaimValue }); - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); - var claimsPrincipal = await sut.CreateAsync(_testUser); + ClaimsPrincipal claimsPrincipal = await sut.CreateAsync(_testUser); Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue)); } @@ -115,14 +118,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice const string expectedClaimType = "custom"; const string expectedClaimValue = "val"; - _testUser.Claims.Add(new IdentityUserClaim { ClaimType = expectedClaimType, ClaimValue = expectedClaimValue}); + _testUser.Claims.Add(new IdentityUserClaim { ClaimType = expectedClaimType, ClaimValue = expectedClaimValue }); _mockUserManager.Setup(x => x.SupportsUserClaim).Returns(true); _mockUserManager.Setup(x => x.GetClaimsAsync(_testUser)).ReturnsAsync( - new List {new Claim(expectedClaimType, expectedClaimValue)}); + new List { new Claim(expectedClaimType, expectedClaimValue) }); - var sut = CreateSut(); + BackOfficeClaimsPrincipalFactory sut = CreateSut(); - var claimsPrincipal = await sut.CreateAsync(_testUser); + ClaimsPrincipal claimsPrincipal = await sut.CreateAsync(_testUser); Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue)); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/IdentityExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/IdentityExtensionsTests.cs index 0c8b469f02..3b2d0391e2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/IdentityExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/IdentityExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Microsoft.AspNetCore.Identity; using NUnit.Framework; @@ -20,9 +23,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice public void ToErrorMessage_When_Single_Error_Expect_Error_Description() { const string expectedError = "invalid something"; - var errors = new List {new IdentityError {Code = "1", Description = expectedError}}; + var errors = new List { new IdentityError { Code = "1", Description = expectedError } }; - var errorMessage = errors.ToErrorMessage(); + string errorMessage = errors.ToErrorMessage(); Assert.AreEqual(expectedError, errorMessage); } @@ -34,11 +37,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice const string error2 = "invalid something else"; var errors = new List { - new IdentityError {Code = "1", Description = error1}, - new IdentityError {Code = "2", Description = error2} + new IdentityError { Code = "1", Description = error1 }, + new IdentityError { Code = "2", Description = error2 } }; - var errorMessage = errors.ToErrorMessage(); + string errorMessage = errors.ToErrorMessage(); Assert.AreEqual($"{error1}, {error2}", errorMessage); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/NopLookupNormalizerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/NopLookupNormalizerTests.cs index 02ff01ff3b..f4ea348892 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/NopLookupNormalizerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/NopLookupNormalizerTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using NUnit.Framework; using Umbraco.Core.Security; @@ -29,6 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice Assert.AreEqual(name, normalizedName); } + [Test] [TestCase(null)] [TestCase("")] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/UmbracoBackOfficeIdentityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/UmbracoBackOfficeIdentityTests.cs index 79a9456643..35e143277a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/UmbracoBackOfficeIdentityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/UmbracoBackOfficeIdentityTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Linq; using System.Security.Claims; @@ -10,7 +13,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice [TestFixture] public class UmbracoBackOfficeIdentityTests { - public const string TestIssuer = "TestIssuer"; [Test] @@ -19,10 +21,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice var securityStamp = Guid.NewGuid().ToString(); var claimsIdentity = new ClaimsIdentity(new[] { - //This is the id that 'identity' uses to check for the user id + // This is the id that 'identity' uses to check for the user id. new Claim(ClaimTypes.NameIdentifier, "1234", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), - //This is the id that 'identity' uses to check for the username + + // This is the id that 'identity' uses to check for the username. new Claim(ClaimTypes.Name, "testing", ClaimValueTypes.String, TestIssuer, TestIssuer), + new Claim(ClaimTypes.GivenName, "hello world", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(Constants.Security.StartContentNodeIdClaimType, "-1", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), new Claim(Constants.Security.StartMediaNodeIdClaimType, "5543", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), @@ -34,18 +38,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice new Claim(Constants.Security.SecurityStampClaimType, securityStamp, ClaimValueTypes.String, TestIssuer, TestIssuer), }); - if (!UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out var backofficeIdentity)) + if (!UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out UmbracoBackOfficeIdentity backofficeIdentity)) + { Assert.Fail(); + } Assert.IsNull(backofficeIdentity.Actor); Assert.AreEqual(1234, backofficeIdentity.Id); - //Assert.AreEqual(sessionId, backofficeIdentity.SessionId); + //// Assert.AreEqual(sessionId, backofficeIdentity.SessionId); Assert.AreEqual(securityStamp, backofficeIdentity.SecurityStamp); Assert.AreEqual("testing", backofficeIdentity.Username); Assert.AreEqual("hello world", backofficeIdentity.RealName); Assert.AreEqual(1, backofficeIdentity.StartContentNodes.Length); Assert.IsTrue(backofficeIdentity.StartMediaNodes.UnsortedSequenceEqual(new[] { 5543, 5555 })); - Assert.IsTrue(new[] {"content", "media"}.SequenceEqual(backofficeIdentity.AllowedApplications)); + Assert.IsTrue(new[] { "content", "media" }.SequenceEqual(backofficeIdentity.AllowedApplications)); Assert.AreEqual("en-us", backofficeIdentity.Culture); Assert.IsTrue(new[] { "admin" }.SequenceEqual(backofficeIdentity.Roles)); @@ -62,7 +68,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice }); if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out _)) + { Assert.Fail(); + } Assert.Pass(); } @@ -72,8 +80,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice { var claimsIdentity = new ClaimsIdentity(new[] { - //null or empty - new Claim(ClaimTypes.NameIdentifier, "", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), + // Null or empty + new Claim(ClaimTypes.NameIdentifier, string.Empty, ClaimValueTypes.Integer32, TestIssuer, TestIssuer), new Claim(ClaimTypes.Name, "testing", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(ClaimTypes.GivenName, "hello world", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(Constants.Security.StartContentNodeIdClaimType, "-1", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), @@ -85,12 +93,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice }); if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out _)) + { Assert.Fail(); + } Assert.Pass(); } - [Test] public void Create_With_Claims_And_User_Data() { @@ -102,14 +111,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice new Claim("TestClaim1", "test", ClaimValueTypes.Integer32, TestIssuer, TestIssuer) }); - var identity = new UmbracoBackOfficeIdentity(claimsIdentity, - "1234", "testing", "hello world", new[] { 654 }, new[] { 654 }, "en-us", securityStamp, new[] { "content", "media" }, new[] { "admin" }); + var identity = new UmbracoBackOfficeIdentity( + claimsIdentity, + "1234", + "testing", + "hello world", + new[] { 654 }, + new[] { 654 }, + "en-us", + securityStamp, + new[] { "content", "media" }, + new[] { "admin" }); Assert.AreEqual(12, identity.Claims.Count()); Assert.IsNull(identity.Actor); } - [Test] public void Clone() { @@ -121,11 +138,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice // this will be filtered out during cloning identity.AddClaim(new Claim(Constants.Security.TicketExpiresClaimType, "test")); - var cloned = identity.Clone(); + ClaimsIdentity cloned = identity.Clone(); Assert.IsNull(cloned.Actor); Assert.AreEqual(10, cloned.Claims.Count()); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/AppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/AppCacheTests.cs index a30e254235..fe5d1ea819 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/AppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/AppCacheTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core.Cache; @@ -14,21 +18,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [SetUp] public virtual void Setup() { - } [TearDown] - public virtual void TearDown() - { - AppCache.Clear(); - } + public virtual void TearDown() => AppCache.Clear(); [Test] public void Throws_On_Reentry() { // don't run for DictionaryAppCache - not making sense - if (GetType() == typeof (DictionaryAppCacheTests)) + if (GetType() == typeof(DictionaryAppCacheTests)) + { Assert.Ignore("Do not run for DictionaryAppCache."); + } Exception exception = null; var result = AppCache.Get("blah", () => @@ -41,6 +43,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache { exception = e; } + return "value"; }); Assert.IsNotNull(exception); @@ -61,7 +64,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache throw new Exception("Do not cache this"); }); } - catch (Exception){} + catch (Exception) + { + } try { @@ -71,10 +76,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache throw new Exception("Do not cache this"); }); } - catch (Exception){} + catch (Exception) + { + } Assert.Greater(counter, 1); - } [Test] @@ -87,17 +93,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache result = AppCache.Get("Blah", () => { counter++; - return ""; + return string.Empty; }); result = AppCache.Get("Blah", () => { counter++; - return ""; + return string.Empty; }); Assert.AreEqual(1, counter); - } [Test] @@ -114,7 +119,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache Assert.AreEqual(4, GetTotalItemCount); - var result = AppCache.SearchByKey("Tes"); + IEnumerable result = AppCache.SearchByKey("Tes"); Assert.AreEqual(3, result.Count()); } @@ -228,7 +233,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache Assert.AreEqual(4, GetTotalItemCount); - //Provider.ClearCacheObjectTypes("umbraco.MacroCacheContent"); + ////Provider.ClearCacheObjectTypes("umbraco.MacroCacheContent"); AppCache.ClearOfType(); Assert.AreEqual(1, GetTotalItemCount); @@ -253,7 +258,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache Assert.AreEqual(1, GetTotalItemCount); } - //just used for these tests + // Just used for these tests private class MacroCacheContent { } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DeepCloneAppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DeepCloneAppCacheTests.cs index cbcd164b62..f653cf50f1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DeepCloneAppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DeepCloneAppCacheTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using System.Linq; using NUnit.Framework; @@ -40,10 +43,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache new TestClone() }; - var val = _provider.GetCacheItem("test", () => original); + DeepCloneableList val = _provider.GetCacheItem("test", () => original); Assert.AreEqual(original.Count, val.Count); - foreach (var item in val) + foreach (TestClone item in val) { Assert.IsTrue(item.IsClone); } @@ -84,21 +87,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache { Debug.Print("get" + i); if (i < 3) + { throw new Exception("fail"); + } + return "succ" + i; } private class TestClass : BeingDirtyBase, IDeepCloneable { - public TestClass() - { - CloneId = Guid.NewGuid(); - } + public TestClass() => CloneId = Guid.NewGuid(); private string _name; + public string Name { get => _name; + set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DefaultCachePolicyTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DefaultCachePolicyTests.cs index a8592356e9..9cb6af72fc 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DefaultCachePolicyTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DefaultCachePolicyTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Moq; using NUnit.Framework; @@ -29,10 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var isCached = false; var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback(() => - { - isCached = true; - }); + .Callback(() => isCached = true); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); @@ -58,15 +58,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cached = new List(); var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string cacheKey, Func o, TimeSpan? t, bool b, string[] s) => - { - cached.Add(cacheKey); - }); - cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new AuditItem[] {}); + .Callback((string cacheKey, Func o, TimeSpan? t, bool b, string[] s) => cached.Add(cacheKey)); + cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new AuditItem[] { }); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); - AuditItem[] unused = defaultPolicy.GetAll(new object[] {}, ids => new[] + AuditItem[] unused = defaultPolicy.GetAll(new object[] { }, ids => new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -87,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); - AuditItem[] found = defaultPolicy.GetAll(new object[] {}, ids => new[] { (AuditItem)null }); + AuditItem[] found = defaultPolicy.GetAll(new object[] { }, ids => new[] { (AuditItem)null }); Assert.AreEqual(2, found.Length); } @@ -97,10 +94,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cacheCleared = false; var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) - .Callback(() => - { - cacheCleared = true; - }); + .Callback(() => cacheCleared = true); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); try @@ -109,7 +103,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache } catch { - //we need this catch or nunit throw up + // We need this catch or nunit throws up } finally { @@ -123,10 +117,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cacheCleared = false; var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) - .Callback(() => - { - cacheCleared = true; - }); + .Callback(() => cacheCleared = true); var defaultPolicy = new DefaultRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); try @@ -135,7 +126,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache } catch { - //we need this catch or nunit throw up + // We need this catch or nunit throws up } finally { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DictionaryAppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DictionaryAppCacheTests.cs index 91d71d3144..13c0f16d0c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DictionaryAppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DictionaryAppCacheTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Cache; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs index 0d5b1edb31..0f16da11c7 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -15,16 +18,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache { private global::Umbraco.Web.Cache.DistributedCache _distributedCache; - private IServerRegistrar ServerRegistrar { get; set; } + private IServerRoleAccessor ServerRegistrar { get; set; } + private TestServerMessenger ServerMessenger { get; set; } [SetUp] public void Setup() { - ServerRegistrar = new TestServerRegistrar(); - ServerMessenger = new TestServerMessenger(); + ServerRegistrar = new TestServerRegistrar(); + ServerMessenger = new TestServerMessenger(); - var cacheRefresherCollection = new CacheRefresherCollection(new [] + var cacheRefresherCollection = new CacheRefresherCollection(new[] { new TestCacheRefresher() }); @@ -51,7 +55,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache _distributedCache.Refresh( Guid.Parse("E0F452CB-DCB2-4E84-B5A5-4F01744C5C73"), x => x.Id, - new TestObjectWithId{Id = i}); + new TestObjectWithId { Id = i }); } Assert.AreEqual(10, ServerMessenger.IntIdsRefreshed.Count); @@ -90,8 +94,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache Assert.AreEqual(13, ServerMessenger.CountOfFullRefreshes); } - #region Internal test classes - internal class TestObjectWithId { public int Id { get; set; } @@ -105,99 +107,76 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache public string Name => "Test Cache Refresher"; - public void RefreshAll() { } + public void RefreshAll() + { + } - public void Refresh(int id) { } + public void Refresh(int id) + { + } - public void Remove(int id) { } + public void Remove(int id) + { + } - public void Refresh(Guid id) { } + public void Refresh(Guid id) + { + } } internal class TestServerMessenger : IServerMessenger { - //used for tests - public List IntIdsRefreshed = new List(); - public List GuidIdsRefreshed = new List(); - public List IntIdsRemoved = new List(); - public List PayloadsRemoved = new List(); - public List PayloadsRefreshed = new List(); - public int CountOfFullRefreshes = 0; + // Used for tests + public List IntIdsRefreshed { get; } = new List(); + public List GuidIdsRefreshed { get; } = new List(); + public List IntIdsRemoved { get; } = new List(); + public List PayloadsRemoved { get; } = new List(); + public List PayloadsRefreshed { get; } = new List(); + public int CountOfFullRefreshes { get; private set; } = 0; - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { // doing nothing } - public void PerformRefresh(ICacheRefresher refresher, string jsonPayload) - { - PayloadsRefreshed.Add(jsonPayload); - } + public void PerformRefresh(ICacheRefresher refresher, string jsonPayload) => PayloadsRefreshed.Add(jsonPayload); - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) - { - IntIdsRefreshed.AddRange(instances.Select(getNumericId)); - } + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRefreshed.AddRange(instances.Select(getNumericId)); - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) - { - GuidIdsRefreshed.AddRange(instances.Select(getGuidId)); - } + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) => GuidIdsRefreshed.AddRange(instances.Select(getGuidId)); - public void PerformRemove(ICacheRefresher refresher, string jsonPayload) - { - PayloadsRemoved.Add(jsonPayload); - } + public void PerformRemove(ICacheRefresher refresher, string jsonPayload) => PayloadsRemoved.Add(jsonPayload); - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) - { - IntIdsRemoved.AddRange(instances.Select(getNumericId)); - } + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRemoved.AddRange(instances.Select(getNumericId)); - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) - { - IntIdsRemoved.AddRange(numericIds); - } + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) => IntIdsRemoved.AddRange(numericIds); - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) - { - IntIdsRefreshed.AddRange(numericIds); - } + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) => IntIdsRefreshed.AddRange(numericIds); - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) - { - GuidIdsRefreshed.AddRange(guidIds); - } + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) => GuidIdsRefreshed.AddRange(guidIds); - public void PerformRefreshAll(ICacheRefresher refresher) - { - CountOfFullRefreshes++; - } + public void QueueRefreshAll(ICacheRefresher refresher) => CountOfFullRefreshes++; + + public void Sync() { } + + public void SendMessages() { } } - internal class TestServerRegistrar : IServerRegistrar + internal class TestServerRegistrar : IServerRoleAccessor { public IEnumerable Registrations => new List { new TestServerAddress("localhost") }; - public ServerRole GetCurrentServerRole() - { - throw new NotImplementedException(); - } + public ServerRole CurrentServerRole => throw new NotImplementedException(); } public class TestServerAddress : IServerAddress { - public TestServerAddress(string address) - { - ServerAddress = address; - } + public TestServerAddress(string address) => ServerAddress = address; public string ServerAddress { get; private set; } } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/FullDataSetCachePolicyTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/FullDataSetCachePolicyTests.cs index e904f9104e..87b61502c5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/FullDataSetCachePolicyTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/FullDataSetCachePolicyTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -29,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void Caches_Single() { - var getAll = new[] + AuditItem[] getAll = new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -38,21 +41,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var isCached = false; var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback(() => - { - isCached = true; - }); + .Callback(() => isCached = true); var policy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); - var unused = policy.Get(1, id => new AuditItem(1, AuditType.Copy, 123, "test", "blah"), ids => getAll); + AuditItem unused = policy.Get(1, id => new AuditItem(1, AuditType.Copy, 123, "test", "blah"), ids => getAll); Assert.IsTrue(isCached); } [Test] public void Get_Single_From_Cache() { - var getAll = new[] + AuditItem[] getAll = new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -63,14 +63,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); - var found = defaultPolicy.Get(1, id => null, ids => getAll); + AuditItem found = defaultPolicy.Get(1, id => null, ids => getAll); Assert.IsNotNull(found); } [Test] public void Get_All_Caches_Empty_List() { - var getAll = new AuditItem[] {}; + var getAll = new AuditItem[] { }; var cached = new List(); @@ -84,20 +84,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache list = o() as IList; }); - cache.Setup(x => x.Get(It.IsAny())).Returns(() => - { - //return null if this is the first pass - return cached.Any() ? new DeepCloneableList(ListCloneBehavior.CloneOnce) : null; - }); + + // Return null if this is the first pass. + cache.Setup(x => x.Get(It.IsAny())) + .Returns(() => cached.Any() ? new DeepCloneableList(ListCloneBehavior.CloneOnce) : null); var policy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); - var found = policy.GetAll(new object[] {}, ids => getAll); + AuditItem[] found = policy.GetAll(new object[] { }, ids => getAll); Assert.AreEqual(1, cached.Count); Assert.IsNotNull(list); - //Do it again, ensure that its coming from the cache! + // Do it again, ensure that its coming from the cache! policy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); found = policy.GetAll(new object[] { }, ids => getAll); @@ -109,7 +108,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void Get_All_Caches_As_Single_List() { - var getAll = new[] + AuditItem[] getAll = new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -130,7 +129,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); - var found = defaultPolicy.GetAll(new object[] { }, ids => getAll); + AuditItem[] found = defaultPolicy.GetAll(new object[] { }, ids => getAll); Assert.AreEqual(1, cached.Count); Assert.IsNotNull(list); @@ -139,7 +138,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void Get_All_Without_Ids_From_Cache() { - var getAll = new[] { (AuditItem)null }; + AuditItem[] getAll = new[] { (AuditItem)null }; var cache = new Mock(); @@ -151,14 +150,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); - var found = defaultPolicy.GetAll(new object[] { }, ids => getAll); + AuditItem[] found = defaultPolicy.GetAll(new object[] { }, ids => getAll); Assert.AreEqual(2, found.Length); } [Test] public void If_CreateOrUpdate_Throws_Cache_Is_Removed() { - var getAll = new[] + AuditItem[] getAll = new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -167,19 +166,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cacheCleared = false; var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) - .Callback(() => - { - cacheCleared = true; - }); + .Callback(() => cacheCleared = true); var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); try { - defaultPolicy.Update(new AuditItem(1, AuditType.Copy, 123, "test", "blah"), item => { throw new Exception("blah!"); }); + defaultPolicy.Update(new AuditItem(1, AuditType.Copy, 123, "test", "blah"), item => throw new Exception("blah!")); } catch { - //we need this catch or nunit throw up + // We need this catch or nunit throws up. } finally { @@ -190,7 +186,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void If_Removes_Throws_Cache_Is_Removed() { - var getAll = new[] + AuditItem[] getAll = new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -199,19 +195,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cacheCleared = false; var cache = new Mock(); cache.Setup(x => x.Clear(It.IsAny())) - .Callback(() => - { - cacheCleared = true; - }); + .Callback(() => cacheCleared = true); var defaultPolicy = new FullDataSetRepositoryCachePolicy(cache.Object, DefaultAccessor, item => item.Id, false); try { - defaultPolicy.Delete(new AuditItem(1, AuditType.Copy, 123, "test", "blah"), item => { throw new Exception("blah!"); }); + defaultPolicy.Delete(new AuditItem(1, AuditType.Copy, 123, "test", "blah"), item => throw new Exception("blah!")); } catch { - //we need this catch or nunit throw up + // We need this catch or nunit throws up. } finally { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/HttpRequestAppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/HttpRequestAppCacheTests.cs index 02a10fcff4..ac8ded80e3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/HttpRequestAppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/HttpRequestAppCacheTests.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Http; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.AspNetCore.Http; using NUnit.Framework; using Umbraco.Core.Cache; @@ -13,7 +16,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache public override void Setup() { base.Setup(); - _httpContext = new DefaultHttpContext();; + _httpContext = new DefaultHttpContext(); _appCache = new HttpRequestAppCache(() => _httpContext.Items); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/ObjectAppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/ObjectAppCacheTests.cs index 51639d7c49..255c76ff46 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/ObjectAppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/ObjectAppCacheTests.cs @@ -1,4 +1,7 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using NUnit.Framework; using Umbraco.Core.Cache; @@ -9,10 +12,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache { private ObjectCacheAppCache _provider; - protected override int GetTotalItemCount - { - get { return _provider.MemoryCache.Count(); } - } + protected override int GetTotalItemCount => _provider.MemoryCache.Count(); public override void Setup() { @@ -20,14 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache _provider = new ObjectCacheAppCache(); } - internal override IAppCache AppCache - { - get { return _provider; } - } + internal override IAppCache AppCache => _provider; - internal override IAppPolicyCache AppPolicyCache - { - get { return _provider; } - } + internal override IAppPolicyCache AppPolicyCache => _provider; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RefresherTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RefresherTests.cs index 59d2f010d2..754dc8b830 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RefresherTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RefresherTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Services.Changes; @@ -7,14 +10,14 @@ using Umbraco.Web.Cache; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache { [TestFixture] - public class RefreshersTests + public class RefresherTests { [Test] public void MediaCacheRefresherCanDeserializeJsonPayload() { - var source = new[] { new MediaCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) }; + MediaCacheRefresher.JsonPayload[] source = new[] { new MediaCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) }; var json = JsonConvert.SerializeObject(source); - var payload = JsonConvert.DeserializeObject(json); + MediaCacheRefresher.JsonPayload[] payload = JsonConvert.DeserializeObject(json); Assert.AreEqual(source[0].Id, payload[0].Id); Assert.AreEqual(source[0].Key, payload[0].Key); Assert.AreEqual(source[0].ChangeTypes, payload[0].ChangeTypes); @@ -23,9 +26,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void ContentCacheRefresherCanDeserializeJsonPayload() { - var source = new[] { new ContentCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) }; + ContentCacheRefresher.JsonPayload[] source = new[] { new ContentCacheRefresher.JsonPayload(1234, Guid.NewGuid(), TreeChangeTypes.None) }; var json = JsonConvert.SerializeObject(source); - var payload = JsonConvert.DeserializeObject(json); + ContentCacheRefresher.JsonPayload[] payload = JsonConvert.DeserializeObject(json); Assert.AreEqual(source[0].Id, payload[0].Id); Assert.AreEqual(source[0].Key, payload[0].Key); Assert.AreEqual(source[0].ChangeTypes, payload[0].ChangeTypes); @@ -34,9 +37,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void ContentTypeCacheRefresherCanDeserializeJsonPayload() { - var source = new[] { new ContentTypeCacheRefresher.JsonPayload("xxx", 1234, ContentTypeChangeTypes.None) }; + ContentTypeCacheRefresher.JsonPayload[] source = new[] { new ContentTypeCacheRefresher.JsonPayload("xxx", 1234, ContentTypeChangeTypes.None) }; var json = JsonConvert.SerializeObject(source); - var payload = JsonConvert.DeserializeObject(json); + ContentTypeCacheRefresher.JsonPayload[] payload = JsonConvert.DeserializeObject(json); Assert.AreEqual(source[0].ItemType, payload[0].ItemType); Assert.AreEqual(source[0].Id, payload[0].Id); Assert.AreEqual(source[0].ChangeTypes, payload[0].ChangeTypes); @@ -45,9 +48,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void DataTypeCacheRefresherCanDeserializeJsonPayload() { - var source = new[] { new DataTypeCacheRefresher.JsonPayload(1234, Guid.NewGuid(), true) }; + DataTypeCacheRefresher.JsonPayload[] source = new[] { new DataTypeCacheRefresher.JsonPayload(1234, Guid.NewGuid(), true) }; var json = JsonConvert.SerializeObject(source); - var payload = JsonConvert.DeserializeObject(json); + DataTypeCacheRefresher.JsonPayload[] payload = JsonConvert.DeserializeObject(json); Assert.AreEqual(source[0].Id, payload[0].Id); Assert.AreEqual(source[0].Key, payload[0].Key); Assert.AreEqual(source[0].Removed, payload[0].Removed); @@ -56,9 +59,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache [Test] public void DomainCacheRefresherCanDeserializeJsonPayload() { - var source = new[] { new DomainCacheRefresher.JsonPayload(1234, DomainChangeTypes.None) }; + DomainCacheRefresher.JsonPayload[] source = new[] { new DomainCacheRefresher.JsonPayload(1234, DomainChangeTypes.None) }; var json = JsonConvert.SerializeObject(source); - var payload = JsonConvert.DeserializeObject(json); + DomainCacheRefresher.JsonPayload[] payload = JsonConvert.DeserializeObject(json); Assert.AreEqual(source[0].Id, payload[0].Id); Assert.AreEqual(source[0].ChangeType, payload[0].ChangeType); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RuntimeAppCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RuntimeAppCacheTests.cs index 33a71b1044..41214bdb58 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RuntimeAppCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/RuntimeAppCacheTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Threading; using NUnit.Framework; using Umbraco.Core.Cache; @@ -18,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache Assert.AreEqual(now, AppCache.GetCacheItem("DateTimeTest")); Assert.AreEqual(now, AppCache.GetCacheItem("DateTimeTest")); - Thread.Sleep(300); //sleep longer than the cache expiration + Thread.Sleep(300); // sleep longer than the cache expiration Assert.AreEqual(default(DateTime), AppCache.GetCacheItem("DateTimeTest")); Assert.AreEqual(null, AppCache.GetCacheItem("DateTimeTest")); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/SingleItemsOnlyCachePolicyTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/SingleItemsOnlyCachePolicyTests.cs index 323b83699c..ffd5c90ce3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/SingleItemsOnlyCachePolicyTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/SingleItemsOnlyCachePolicyTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Moq; using NUnit.Framework; @@ -29,15 +32,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var cached = new List(); var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string cacheKey, Func o, TimeSpan? t, bool b, string[] s) => - { - cached.Add(cacheKey); - }); + .Callback((string cacheKey, Func o, TimeSpan? t, bool b, string[] s) => cached.Add(cacheKey)); cache.Setup(x => x.SearchByKey(It.IsAny())).Returns(new AuditItem[] { }); var defaultPolicy = new SingleItemsOnlyRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); - var unused = defaultPolicy.GetAll(new object[] { }, ids => new[] + AuditItem[] unused = defaultPolicy.GetAll(new object[] { }, ids => new[] { new AuditItem(1, AuditType.Copy, 123, "test", "blah"), new AuditItem(2, AuditType.Copy, 123, "test", "blah2") @@ -52,14 +52,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache var isCached = false; var cache = new Mock(); cache.Setup(x => x.Insert(It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback(() => - { - isCached = true; - }); + .Callback(() => isCached = true); var defaultPolicy = new SingleItemsOnlyRepositoryCachePolicy(cache.Object, DefaultAccessor, new RepositoryCachePolicyOptions()); - var unused = defaultPolicy.Get(1, id => new AuditItem(1, AuditType.Copy, 123, "test", "blah"), ids => null); + AuditItem unused = defaultPolicy.Get(1, id => new AuditItem(1, AuditType.Copy, 123, "test", "blah"), ids => null); Assert.IsTrue(isCached); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ClaimsIdentityExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ClaimsIdentityExtensionsTests.cs index 76f928ca46..7125e13e90 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ClaimsIdentityExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ClaimsIdentityExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Security.Claims; using NUnit.Framework; @@ -27,7 +30,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void FindFirstValue_WhenMatchingClaimPresent_ExpectCorrectValue() { var expectedClaim = new Claim("test", "123", "string", "Umbraco"); - var identity = new ClaimsIdentity(new List {expectedClaim}); + var identity = new ClaimsIdentity(new List { expectedClaim }); var value = identity.FindFirstValue("test"); @@ -39,7 +42,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var expectedClaim = new Claim("test", "123", "string", "Umbraco"); var dupeClaim = new Claim(expectedClaim.Type, Guid.NewGuid().ToString()); - var identity = new ClaimsIdentity(new List {expectedClaim, dupeClaim}); + var identity = new ClaimsIdentity(new List { expectedClaim, dupeClaim }); var value = identity.FindFirstValue("test"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/DeepCloneableListTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/DeepCloneableListTests.cs index bcfe142d8d..57237d907e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/DeepCloneableListTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/DeepCloneableListTests.cs @@ -1,4 +1,7 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using NUnit.Framework; using Umbraco.Core.Collections; using Umbraco.Tests.Common; @@ -11,33 +14,35 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections [Test] public void Deep_Clones_Each_Item_Once() { - var list = new DeepCloneableList(ListCloneBehavior.CloneOnce); - list.Add(new TestClone()); - list.Add(new TestClone()); - list.Add(new TestClone()); + var list = new DeepCloneableList(ListCloneBehavior.CloneOnce) + { + new TestClone(), + new TestClone(), + new TestClone() + }; var cloned = list.DeepClone() as DeepCloneableList; - //Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) + // Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) Assert.IsTrue(list.SequenceEqual(cloned)); - //Test that each instance in the list is not the same one - foreach (var item in list) + // Test that each instance in the list is not the same one + foreach (TestClone item in list) { - var clone = cloned.Single(x => x.Id == item.Id); + TestClone clone = cloned.Single(x => x.Id == item.Id); Assert.AreNotSame(item, clone); } - //clone again from the clone - since it's clone once the items should be the same + // Clone again from the clone - since it's clone once the items should be the same var cloned2 = cloned.DeepClone() as DeepCloneableList; - //Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) + // Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) Assert.IsTrue(cloned.SequenceEqual(cloned2)); - //Test that each instance in the list is the same one - foreach (var item in cloned) + // Test that each instance in the list is the same one + foreach (TestClone item in cloned) { - var clone = cloned2.Single(x => x.Id == item.Id); + TestClone clone = cloned2.Single(x => x.Id == item.Id); Assert.AreSame(item, clone); } } @@ -45,10 +50,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections [Test] public void Deep_Clones_All_Elements() { - var list = new DeepCloneableList(ListCloneBehavior.Always); - list.Add(new TestClone()); - list.Add(new TestClone()); - list.Add(new TestClone()); + var list = new DeepCloneableList(ListCloneBehavior.Always) + { + new TestClone(), + new TestClone(), + new TestClone() + }; var cloned = list.DeepClone() as DeepCloneableList; @@ -60,14 +67,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections [Test] public void Clones_Each_Item() { - var list = new DeepCloneableList(ListCloneBehavior.Always); - list.Add(new TestClone()); - list.Add(new TestClone()); - list.Add(new TestClone()); + var list = new DeepCloneableList(ListCloneBehavior.Always) + { + new TestClone(), + new TestClone(), + new TestClone() + }; - var cloned = (DeepCloneableList) list.DeepClone(); + var cloned = (DeepCloneableList)list.DeepClone(); - foreach (var item in cloned) + foreach (TestClone item in cloned) { Assert.IsTrue(item.IsClone); } @@ -76,20 +85,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections [Test] public void Cloned_Sequence_Equals() { - var list = new DeepCloneableList(ListCloneBehavior.Always); - list.Add(new TestClone()); - list.Add(new TestClone()); - list.Add(new TestClone()); + var list = new DeepCloneableList(ListCloneBehavior.Always) + { + new TestClone(), + new TestClone(), + new TestClone() + }; - var cloned = (DeepCloneableList) list.DeepClone(); + var cloned = (DeepCloneableList)list.DeepClone(); - //Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) + // Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) Assert.IsTrue(list.SequenceEqual(cloned)); - //Test that each instance in the list is not the same one - foreach (var item in list) + // Test that each instance in the list is not the same one + foreach (TestClone item in list) { - var clone = cloned.Single(x => x.Id == item.Id); + TestClone clone = cloned.Single(x => x.Id == item.Id); Assert.AreNotSame(item, clone); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/OrderedHashSetTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/OrderedHashSetTests.cs index df7f004884..06d935cfd8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/OrderedHashSetTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/OrderedHashSetTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core.Collections; @@ -11,8 +14,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections public void Keeps_Last() { var list = new OrderedHashSet(keepOldest: false); - var items = new[] {new MyClass("test"), new MyClass("test"), new MyClass("test")}; - foreach (var item in items) + MyClass[] items = new[] { new MyClass("test"), new MyClass("test"), new MyClass("test") }; + foreach (MyClass item in items) { list.Add(item); } @@ -26,8 +29,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections public void Keeps_First() { var list = new OrderedHashSet(keepOldest: true); - var items = new[] {new MyClass("test"), new MyClass("test"), new MyClass("test")}; - foreach (var item in items) + MyClass[] items = new[] { new MyClass("test"), new MyClass("test"), new MyClass("test") }; + foreach (MyClass item in items) { list.Add(item); } @@ -45,37 +48,49 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections } public string Name { get; } + public Guid Id { get; } public bool Equals(MyClass other) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + return string.Equals(Name, other.Name); } public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((MyClass) obj); + if (obj is null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != GetType()) + { + return false; + } + + return Equals((MyClass)obj); } - public override int GetHashCode() - { - return Name.GetHashCode(); - } + public override int GetHashCode() => Name.GetHashCode(); - public static bool operator ==(MyClass left, MyClass right) - { - return Equals(left, right); - } + public static bool operator ==(MyClass left, MyClass right) => Equals(left, right); - public static bool operator !=(MyClass left, MyClass right) - { - return Equals(left, right) == false; - } + public static bool operator !=(MyClass left, MyClass right) => Equals(left, right) == false; } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index 6d51603502..7e43eb4b83 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.IO; @@ -35,18 +38,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components private static IServiceProvider MockFactory(Action> setup = null) { // FIXME: use IUmbracoDatabaseFactory vs UmbracoDatabaseFactory, clean it all up! - var mock = new Mock(); - var loggerFactory = NullLoggerFactory.Instance; - var logger = loggerFactory.CreateLogger("GenericLogger"); - var typeFinder = TestHelper.GetTypeFinder(); + NullLoggerFactory loggerFactory = NullLoggerFactory.Instance; + ILogger logger = loggerFactory.CreateLogger("GenericLogger"); var globalSettings = new GlobalSettings(); var connectionStrings = new ConnectionStrings(); var f = new UmbracoDatabaseFactory(loggerFactory.CreateLogger(), loggerFactory, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator); var fs = new FileSystems(mock.Object, loggerFactory.CreateLogger(), loggerFactory, IOHelper, Options.Create(globalSettings), Mock.Of()); var coreDebug = new CoreDebugSettings(); - var mediaFileSystem = Mock.Of(); - var p = new ScopeProvider(f, fs, Options.Create(coreDebug), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, typeFinder, NoAppCache.Instance); + IMediaFileSystem mediaFileSystem = Mock.Of(); + var p = new ScopeProvider(f, fs, Options.Create(coreDebug), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(logger); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(loggerFactory.CreateLogger); @@ -59,57 +60,63 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components return mock.Object; } - private static IServiceCollection MockRegister() - { - // Why mock something you can spin up an instance of? - return new ServiceCollection(); // Mock.Of(); - } - - private static TypeLoader MockTypeLoader() - { - var ioHelper = IOHelper; - return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); - } - + private static IServiceCollection MockRegister() => new ServiceCollection(); + private static TypeLoader MockTypeLoader() => new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); [Test] public void Boot1A() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); + // 2 is Core and requires 4 // 3 is User // => reorder components accordingly composers.Compose(); AssertTypeArray(TypeArray(), Composed); - var factory = MockFactory(m => + IServiceProvider factory = MockFactory(m => { m.Setup(x => x.GetService(It.Is(t => t == typeof(ISomeResource)))).Returns(() => new SomeResource()); m.Setup(x => x.GetService(It.IsAny())).Returns((type) => { if (type == typeof(Composer1)) + { return new Composer1(); + } + if (type == typeof(Composer5)) + { return new Composer5(); + } + if (type == typeof(Component5)) + { return new Component5(new SomeResource()); + } + if (type == typeof(IProfilingLogger)) + { return new ProfilingLogger(Mock.Of>(), Mock.Of()); + } + if (type == typeof(ILogger)) + { return Mock.Of>(); + } + throw new NotSupportedException(type.FullName); }); }); - var builder = composition.WithCollectionBuilder(); + ComponentCollectionBuilder builder = composition.WithCollectionBuilder(); builder.RegisterWith(register); - var components = builder.CreateCollection(factory); + ComponentCollection components = builder.CreateCollection(factory); Assert.IsEmpty(components); components.Initialize(); @@ -121,12 +128,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Boot1B() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); + // 2 is Core and requires 4 // 3 is User - stays with RuntimeLevel.Run // => reorder components accordingly @@ -137,12 +145,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Boot2() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); + // 21 is required by 20 // => reorder components accordingly composers.Compose(); @@ -152,12 +161,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Boot3() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); + // i23 requires 22 // 24, 25 implement i23 // 25 required by i23 @@ -169,10 +179,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void BrokenRequire() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); try @@ -192,12 +202,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void BrokenRequired() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = TypeArray(); + Type[] types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); + // 2 is Core and requires 4 // 13 is required by 1 // 1 is missing @@ -213,42 +224,63 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components Initialized.Clear(); Terminated.Clear(); - var register = MockRegister(); - var typeLoader = MockTypeLoader(); - var factory = MockFactory(m => + IServiceCollection register = MockRegister(); + TypeLoader typeLoader = MockTypeLoader(); + IServiceProvider factory = MockFactory(m => { m.Setup(x => x.GetService(It.Is(t => t == typeof(ISomeResource)))).Returns(() => new SomeResource()); m.Setup(x => x.GetService(It.IsAny())).Returns((type) => { if (type == typeof(Composer1)) + { return new Composer1(); + } + if (type == typeof(Composer5)) + { return new Composer5(); + } + if (type == typeof(Composer5a)) + { return new Composer5a(); + } + if (type == typeof(Component5)) + { return new Component5(new SomeResource()); + } + if (type == typeof(Component5a)) + { return new Component5a(); + } + if (type == typeof(IProfilingLogger)) + { return new ProfilingLogger(Mock.Of>(), Mock.Of()); + } + if (type == typeof(ILogger)) + { return Mock.Of>(); + } + throw new NotSupportedException(type.FullName); }); }); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) }; + Type[] types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Assert.IsEmpty(Composed); composers.Compose(); AssertTypeArray(TypeArray(), Composed); - var builder = composition.WithCollectionBuilder(); + ComponentCollectionBuilder builder = composition.WithCollectionBuilder(); builder.RegisterWith(register); - var components = builder.CreateCollection(factory); + ComponentCollection components = builder.CreateCollection(factory); Assert.IsEmpty(Initialized); components.Initialize(); @@ -262,10 +294,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Requires1() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; + Type[] types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); @@ -277,10 +309,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Requires2A() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; + Type[] types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); @@ -292,18 +324,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void Requires2B() { - var register = MockRegister(); - var typeLoader = MockTypeLoader(); - var factory = MockFactory(); + IServiceCollection register = MockRegister(); + TypeLoader typeLoader = MockTypeLoader(); + IServiceProvider factory = MockFactory(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; + Type[] types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); - var builder = composition.WithCollectionBuilder(); + ComponentCollectionBuilder builder = composition.WithCollectionBuilder(); builder.RegisterWith(register); - var components = builder.CreateCollection(factory); + ComponentCollection components = builder.CreateCollection(factory); Assert.AreEqual(3, Composed.Count); Assert.AreEqual(typeof(Composer4), Composed[0]); Assert.AreEqual(typeof(Composer2), Composed[1]); @@ -313,10 +345,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void WeakDependencies() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer10) }; + Type[] types = new[] { typeof(Composer10) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); @@ -329,7 +361,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components Assert.Throws(() => composers.Compose()); Console.WriteLine("throws:"); composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); - var requirements = composers.GetRequirements(false); + Dictionary> requirements = composers.GetRequirements(false); Console.WriteLine(Composers.GetComposersReport(requirements)); types = new[] { typeof(Composer2) }; @@ -352,10 +384,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void DisableMissing() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list + Type[] types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); @@ -367,11 +399,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void AttributesPriorities() { - var register = MockRegister(); + IServiceCollection register = MockRegister(); var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var types = new[] { typeof(Composer26) }; - var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) }; + Type[] types = new[] { typeof(Composer26) }; + DisableComposerAttribute[] enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) }; var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>()); Composed.Clear(); composers.Compose(); @@ -389,47 +421,47 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components [Test] public void AllComposers() { - var typeFinder = TestHelper.GetTypeFinder(); + ITypeFinder typeFinder = TestHelper.GetTypeFinder(); var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), Mock.Of>(), Mock.Of()); - var register = MockRegister(); + IServiceCollection register = MockRegister(); var builder = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); - var allComposers = typeLoader.GetTypes().ToList(); var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList(); var composers = new Composers(builder, types, Enumerable.Empty(), Mock.Of>()); - var requirements = composers.GetRequirements(); - var report = Composers.GetComposersReport(requirements); + Dictionary> requirements = composers.GetRequirements(); + string report = Composers.GetComposersReport(requirements); Console.WriteLine(report); - var composerTypes = composers.SortComposers(requirements); + IEnumerable composerTypes = composers.SortComposers(requirements); - foreach (var type in composerTypes) - Console.WriteLine(type); - } - - #region Compothings - - public class TestComposerBase : IComposer - { - public virtual void Compose(IUmbracoBuilder builder) + foreach (Type type in composerTypes) { - Composed.Add(GetType()); + Console.WriteLine(type); } } + public class TestComposerBase : IComposer + { + public virtual void Compose(IUmbracoBuilder builder) => Composed.Add(GetType()); + } + public class Composer1 : TestComposerBase - { } + { + } [ComposeAfter(typeof(Composer4))] public class Composer2 : TestComposerBase, ICoreComposer - { } + { + } public class Composer3 : TestComposerBase, IUserComposer - { } + { + } public class Composer4 : TestComposerBase - { } + { + } public class Composer5 : TestComposerBase { @@ -452,151 +484,135 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public class TestComponentBase : IComponent { - public virtual void Initialize() - { - Initialized.Add(GetType()); - } + public virtual void Initialize() => Initialized.Add(GetType()); - public virtual void Terminate() - { - Terminated.Add(GetType()); - } + public virtual void Terminate() => Terminated.Add(GetType()); } public class Component5 : TestComponentBase { private readonly ISomeResource _resource; - public Component5(ISomeResource resource) - { - _resource = resource; - } + public Component5(ISomeResource resource) => _resource = resource; } public class Component5a : TestComponentBase - { } + { + } [Disable] public class Composer6 : TestComposerBase - { } + { + } public class Composer7 : TestComposerBase - { } + { + } [Disable(typeof(Composer7))] [Enable(typeof(Composer6))] public class Composer8 : TestComposerBase - { } + { + } public interface ITestComposer : IUserComposer - { } + { + } public class Composer9 : TestComposerBase, ITestComposer - { } + { + } [ComposeAfter(typeof(ITestComposer))] public class Composer10 : TestComposerBase - { } + { + } [ComposeAfter(typeof(ITestComposer), false)] public class Composer11 : TestComposerBase - { } + { + } [ComposeAfter(typeof(Composer4), true)] public class Composer12 : TestComposerBase, ICoreComposer - { } + { + } [ComposeBefore(typeof(Composer1))] public class Composer13 : TestComposerBase - { } + { + } - public interface ISomeResource { } + public interface ISomeResource + { + } - public class SomeResource : ISomeResource { } + public class SomeResource : ISomeResource + { + } public class Composer20 : TestComposerBase - { } + { + } [ComposeBefore(typeof(Composer20))] public class Composer21 : TestComposerBase - { } + { + } public class Composer22 : TestComposerBase - { } + { + } [ComposeAfter(typeof(Composer22))] public interface IComposer23 : IComposer - { } + { + } public class Composer24 : TestComposerBase, IComposer23 - { } + { + } // should insert itself between 22 and anything i23 [ComposeBefore(typeof(IComposer23))] - //[RequireComponent(typeof(Component22))] - not needed, implement i23 + ////[RequireComponent(typeof(Component22))] - not needed, implement i23 public class Composer25 : TestComposerBase, IComposer23 - { } + { + } public class Composer26 : TestComposerBase - { } + { + } [Enable(typeof(Composer26))] public class Composer27 : TestComposerBase - { } - - #endregion - - #region TypeArray + { + } // FIXME: move to Testing + private static Type[] TypeArray() => new[] { typeof(T1) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7) }; - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7) }; - } - - private static Type[] TypeArray() - { - return new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8) }; - } + private static Type[] TypeArray() => new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8) }; private static void AssertTypeArray(IReadOnlyList expected, IReadOnlyList test) { Assert.AreEqual(expected.Count, test.Count); - for (var i = 0; i < expected.Count; i++) + for (int i = 0; i < expected.Count; i++) + { Assert.AreEqual(expected[i], test[i]); + } } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs index b4131ca790..1c4a401e2e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.Linq; @@ -20,7 +23,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [SetUp] public void Setup() { - var register = TestHelper.GetServiceCollection(); + IServiceCollection register = TestHelper.GetServiceCollection(); _composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); } @@ -32,24 +35,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void ContainsTypes() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); Assert.IsTrue(builder.Has()); Assert.IsTrue(builder.Has()); Assert.IsFalse(builder.Has()); - //Assert.IsFalse(col.ContainsType()); // does not compile + //// Assert.IsFalse(col.ContainsType()); // does not compile - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); } [Test] public void CanClearBuilderBeforeCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); @@ -57,20 +60,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsFalse(builder.Has()); Assert.IsFalse(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col); } [Test] public void CannotClearBuilderOnceCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); Assert.Throws(() => builder.Clear()); } @@ -78,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void CanAppendToBuilder() { - var builder = _composition.WithCollectionBuilder(); + TestCollectionBuilder builder = _composition.WithCollectionBuilder(); builder.Append(); builder.Append(); @@ -86,52 +89,48 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(builder.Has()); Assert.IsFalse(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); } [Test] public void CannotAppendToBuilderOnceCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder(); + TestCollectionBuilder builder = _composition.WithCollectionBuilder(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); - Assert.Throws(() => - builder.Append() - ); + Assert.Throws(() => builder.Append()); } [Test] public void CanAppendDuplicateToBuilderAndDeDuplicate() { - var builder = _composition.WithCollectionBuilder(); + TestCollectionBuilder builder = _composition.WithCollectionBuilder(); builder.Append(); builder.Append(); - var factory = _composition.CreateServiceProvider(); + IServiceProvider factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1)); } [Test] public void CannotAppendInvalidTypeToBUilder() { - var builder = _composition.WithCollectionBuilder(); + TestCollectionBuilder builder = _composition.WithCollectionBuilder(); - //builder.Append(); // does not compile - Assert.Throws(() => - builder.Append(new[] { typeof(Resolved4) }) // throws - ); + ////builder.Append(); // does not compile + Assert.Throws(() => builder.Append(new[] { typeof(Resolved4) })); } [Test] public void CanRemoveFromBuilder() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .Remove(); @@ -140,42 +139,40 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsFalse(builder.Has()); Assert.IsFalse(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1)); } [Test] public void CanRemoveMissingFromBuilder() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .Remove(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved2)); } [Test] public void CannotRemoveFromBuilderOnceCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); - Assert.Throws(() => - builder.Remove() // throws - ); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); + Assert.Throws(() => builder.Remove()); } [Test] public void CanInsertIntoBuilder() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .Insert(); @@ -184,69 +181,63 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(builder.Has()); Assert.IsTrue(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved3), typeof(Resolved1), typeof(Resolved2)); } [Test] public void CannotInsertIntoBuilderOnceCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); - Assert.Throws(() => - builder.Insert() // throws - ); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); + Assert.Throws(() => builder.Insert()); } [Test] public void CanInsertDuplicateIntoBuilderAndDeDuplicate() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .Insert(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); } [Test] public void CanInsertIntoEmptyBuilder() { - var builder = _composition.WithCollectionBuilder(); + TestCollectionBuilder builder = _composition.WithCollectionBuilder(); builder.Insert(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved2)); } [Test] public void CannotInsertIntoBuilderAtWrongIndex() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); - Assert.Throws(() => - builder.Insert(99) // throws - ); + Assert.Throws(() => builder.Insert(99)); - Assert.Throws(() => - builder.Insert(-1) // throws - ); + Assert.Throws(() => builder.Insert(-1)); } [Test] public void CanInsertIntoBuilderBefore() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .InsertBefore(); @@ -255,15 +246,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(builder.Has()); Assert.IsTrue(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved3), typeof(Resolved2)); } [Test] public void CanInsertIntoBuilderAfter() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .InsertAfter(); @@ -272,15 +263,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(builder.Has()); Assert.IsTrue(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved3), typeof(Resolved2)); } [Test] public void CanInsertIntoBuilderAfterLast() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .InsertAfter(); @@ -289,47 +280,45 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(builder.Has()); Assert.IsTrue(builder.Has()); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved1), typeof(Resolved2), typeof(Resolved3)); } [Test] public void CannotInsertIntoBuilderBeforeOnceCollectionIsCreated() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); Assert.Throws(() => - builder.InsertBefore() - ); + builder.InsertBefore()); } [Test] public void CanInsertDuplicateIntoBuilderBeforeAndDeDuplicate() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append() .Append() .InsertBefore(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); } [Test] public void CannotInsertIntoBuilderBeforeMissing() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilder builder = _composition.WithCollectionBuilder() .Append(); Assert.Throws(() => - builder.InsertBefore() - ); + builder.InsertBefore()); } [Test] @@ -341,21 +330,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing // CreateCollection creates a new collection each time // but the container manages the scope, so to test the scope - // the collection must come from the container + // the collection must come from the container. + IServiceProvider factory = _composition.CreateServiceProvider(); - var factory = _composition.CreateServiceProvider(); - - using (var scope = factory.CreateScope()) + using (IServiceScope scope = factory.CreateScope()) { - var col1 = scope.ServiceProvider.GetRequiredService(); + TestCollection col1 = scope.ServiceProvider.GetRequiredService(); AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); - var col2 = scope.ServiceProvider.GetRequiredService(); + TestCollection col2 = scope.ServiceProvider.GetRequiredService(); AssertCollection(col2, typeof(Resolved1), typeof(Resolved2)); AssertSameCollection(scope.ServiceProvider, col1, col2); } - } [Test] @@ -367,14 +354,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing // CreateCollection creates a new collection each time // but the container manages the scope, so to test the scope - // the collection must come from the container + // the collection must come from the container. + IServiceProvider factory = _composition.CreateServiceProvider(); - var factory = _composition.CreateServiceProvider(); - - var col1 = factory.GetRequiredService(); + TestCollection col1 = factory.GetRequiredService(); AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); - var col2 = factory.GetRequiredService(); + TestCollection col2 = factory.GetRequiredService(); AssertCollection(col1, typeof(Resolved1), typeof(Resolved2)); AssertNotSameCollection(col1, col2); @@ -383,13 +369,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void BuilderRespectsTypesOrder() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilderTransient builder = _composition.WithCollectionBuilder() .Append() .Insert() .InsertBefore(); - var factory = _composition.CreateServiceProvider(); - var col1 = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col1 = builder.CreateCollection(factory); AssertCollection(col1, typeof(Resolved1), typeof(Resolved2), typeof(Resolved3)); } @@ -402,13 +388,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing // CreateCollection creates a new collection each time // but the container manages the scope, so to test the scope - // the collection must come from the container + // the collection must come from the container/ + IServiceProvider serviceProvider = _composition.CreateServiceProvider(); TestCollection col1A, col1B; - - var serviceProvider = _composition.CreateServiceProvider(); - - using (var scope = serviceProvider.CreateScope()) + using (IServiceScope scope = serviceProvider.CreateScope()) { col1A = scope.ServiceProvider.GetRequiredService(); col1B = scope.ServiceProvider.GetRequiredService(); @@ -420,7 +404,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing TestCollection col2; - using (var scope = serviceProvider.CreateScope()) + using (IServiceScope scope = serviceProvider.CreateScope()) { col2 = scope.ServiceProvider.GetRequiredService(); } @@ -432,43 +416,43 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void WeightedBuilderCreatesWeightedCollection() { - var builder = _composition.WithCollectionBuilder() + TestCollectionBuilderWeighted builder = _composition.WithCollectionBuilder() .Add() .Add(); - var factory = _composition.CreateServiceProvider(); - var col = builder.CreateCollection(factory); + IServiceProvider factory = _composition.CreateServiceProvider(); + TestCollection col = builder.CreateCollection(factory); AssertCollection(col, typeof(Resolved2), typeof(Resolved1)); } - #region Assertions - private static void AssertCollection(IEnumerable col, params Type[] expected) { - var colA = col.ToArray(); + Resolved[] colA = col.ToArray(); Assert.AreEqual(expected.Length, colA.Length); - for (var i = 0; i < expected.Length; i++) + for (int i = 0; i < expected.Length; i++) + { Assert.IsInstanceOf(expected[i], colA[i]); + } } private static void AssertSameCollection(IServiceProvider factory, IEnumerable col1, IEnumerable col2) { Assert.AreSame(col1, col2); - var col1A = col1.ToArray(); - var col2A = col2.ToArray(); + Resolved[] col1A = col1.ToArray(); + Resolved[] col2A = col2.ToArray(); Assert.AreEqual(col1A.Length, col2A.Length); // Ensure each item in each collection is the same but also // resolve each item from the factory to ensure it's also the same since // it should have the same lifespan. - for (var i = 0; i < col1A.Length; i++) + for (int i = 0; i < col1A.Length; i++) { Assert.AreSame(col1A[i], col2A[i]); - var itemA = factory.GetRequiredService(col1A[i].GetType()); - var itemB = factory.GetRequiredService(col2A[i].GetType()); + object itemA = factory.GetRequiredService(col1A[i].GetType()); + object itemB = factory.GetRequiredService(col2A[i].GetType()); Assert.AreSame(itemA, itemB); } @@ -478,36 +462,37 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { Assert.AreNotSame(col1, col2); - var col1A = col1.ToArray(); - var col2A = col2.ToArray(); + Resolved[] col1A = col1.ToArray(); + Resolved[] col2A = col2.ToArray(); Assert.AreEqual(col1A.Length, col2A.Length); - for (var i = 0; i < col1A.Length; i++) + for (int i = 0; i < col1A.Length; i++) { Assert.AreNotSame(col1A[i], col2A[i]); } } - #endregion - - #region Test Objects - public abstract class Resolved - { } + { + } public class Resolved1 : Resolved - { } + { + } [Weight(50)] // default is 100 public class Resolved2 : Resolved - { } + { + } public class Resolved3 : Resolved - { } + { + } public class Resolved4 // not! : Resolved - { } + { + } // ReSharper disable once ClassNeverInstantiated.Local private class TestCollectionBuilder : OrderedCollectionBuilderBase @@ -542,9 +527,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { public TestCollection(IEnumerable items) : base(items) - { } + { + } } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs index 1c8bf139ac..1010424f75 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Collections.Generic; using System.IO; using System.Reflection; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs index 1401d7c66f..984f598ef4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs @@ -1,10 +1,12 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { [TestFixture] public class CompositionTests { - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs index c87b267c1a..9179e9e086 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Configuration; @@ -6,118 +9,113 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Core.DependencyInjection; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.TestHelpers; -using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { + /// + /// Tests for lazy collection builder. + /// + /// + /// Lazy collection builder does not throw on duplicate, just uses distinct types + /// so we don't have a test for duplicates as we had with resolvers in v7. + /// [TestFixture] public class LazyCollectionBuilderTests { - private IServiceCollection CreateRegister() - { - return TestHelper.GetServiceCollection(); - } - - // note - // lazy collection builder does not throw on duplicate, just uses distinct types - // so we don't have a test for duplicates as we had with resolvers in v7 + private IServiceCollection CreateRegister() => TestHelper.GetServiceCollection(); [Test] public void LazyCollectionBuilderHandlesTypes() { - var container = CreateRegister(); + IServiceCollection container = CreateRegister(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); - composition.WithCollectionBuilder() .Add() .Add() .Add() .Add(); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); - var values = factory.GetRequiredService(); + TestCollection values = factory.GetRequiredService(); Assert.AreEqual(3, values.Count()); Assert.IsTrue(values.Select(x => x.GetType()) .ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) })); - var other = factory.GetRequiredService(); + TestCollection other = factory.GetRequiredService(); Assert.AreNotSame(values, other); // transient - var o1 = other.FirstOrDefault(x => x is TransientObject1); + ITestInterface o1 = other.FirstOrDefault(x => x is TransientObject1); Assert.IsFalse(values.Contains(o1)); // transient } [Test] public void LazyCollectionBuilderHandlesProducers() { - var container = CreateRegister(); + IServiceCollection container = CreateRegister(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); - composition.WithCollectionBuilder() .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) }) .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) }) .Add(() => new[] { typeof(TransientObject1) }); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); - var values = factory.GetRequiredService(); + TestCollection values = factory.GetRequiredService(); Assert.AreEqual(3, values.Count()); Assert.IsTrue(values.Select(x => x.GetType()) .ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) })); - var other = factory.GetRequiredService(); + TestCollection other = factory.GetRequiredService(); Assert.AreNotSame(values, other); // transient - var o1 = other.FirstOrDefault(x => x is TransientObject1); + ITestInterface o1 = other.FirstOrDefault(x => x is TransientObject1); Assert.IsFalse(values.Contains(o1)); // transient } [Test] public void LazyCollectionBuilderHandlesTypesAndProducers() { - var container = CreateRegister(); + IServiceCollection container = CreateRegister(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); - composition.WithCollectionBuilder() .Add() .Add() .Add() .Add(() => new[] { typeof(TransientObject1) }); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); - var values = factory.GetRequiredService(); + TestCollection values = factory.GetRequiredService(); Assert.AreEqual(3, values.Count()); Assert.IsTrue(values.Select(x => x.GetType()) .ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) })); - var other = factory.GetRequiredService(); + TestCollection other = factory.GetRequiredService(); Assert.AreNotSame(values, other); // transient - var o1 = other.FirstOrDefault(x => x is TransientObject1); + ITestInterface o1 = other.FirstOrDefault(x => x is TransientObject1); Assert.IsFalse(values.Contains(o1)); // transient } [Test] public void LazyCollectionBuilderThrowsOnIllegalTypes() { - var container = CreateRegister(); + IServiceCollection container = CreateRegister(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); composition.WithCollectionBuilder() .Add() // illegal, does not implement the interface! - //.Add() + ////.Add() // legal so far... .Add(() => new[] { typeof(TransientObject4) }); @@ -125,14 +123,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.Throws(() => { // but throws here when trying to register the types, right before creating the factory - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); }); } [Test] public void LazyCollectionBuilderCanExcludeTypes() { - var container = CreateRegister(); + IServiceCollection container = CreateRegister(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); composition.WithCollectionBuilder() @@ -140,9 +138,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2), typeof(TransientObject1) }) .Exclude(); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); - var values = factory.GetRequiredService(); + TestCollection values = factory.GetRequiredService(); Assert.AreEqual(2, values.Count()); Assert.IsFalse(values.Select(x => x.GetType()) @@ -150,28 +148,31 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(values.Select(x => x.GetType()) .ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2) })); - var other = factory.GetRequiredService(); + TestCollection other = factory.GetRequiredService(); Assert.AreNotSame(values, other); // transient - var o1 = other.FirstOrDefault(x => x is TransientObject1); + ITestInterface o1 = other.FirstOrDefault(x => x is TransientObject1); Assert.IsFalse(values.Contains(o1)); // transient } - #region Test Objects - private interface ITestInterface - { } + { + } private class TransientObject1 : ITestInterface - { } + { + } private class TransientObject2 : ITestInterface - { } + { + } private class TransientObject3 : ITestInterface - { } + { + } private class TransientObject4 - { } + { + } // ReSharper disable once ClassNeverInstantiated.Local private class TestCollectionBuilder : LazyCollectionBuilderBase @@ -186,9 +187,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { public TestCollection(IEnumerable items) : base(items) - { } + { + } } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs index 17e406e02f..702d4f9c8a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; using System.Xml; using System.Xml.Linq; @@ -7,13 +11,11 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.PackageActions; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.TestHelpers; -using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { @@ -23,76 +25,47 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void PackageActionCollectionBuilderWorks() { - var container = TestHelper.GetServiceCollection(); + IServiceCollection container = TestHelper.GetServiceCollection(); var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); - - var expectedPackageActions = TypeLoader.GetPackageActions(); + IEnumerable expectedPackageActions = TypeLoader.GetPackageActions(); composition.WithCollectionBuilder() .Add(() => expectedPackageActions); - var factory = composition.CreateServiceProvider(); + IServiceProvider factory = composition.CreateServiceProvider(); - var actions = factory.GetRequiredService(); + PackageActionCollection actions = factory.GetRequiredService(); Assert.AreEqual(2, actions.Count()); // order is unspecified, but both must be there - var hasAction1 = actions.ElementAt(0) is PackageAction1 || actions.ElementAt(1) is PackageAction1; - var hasAction2 = actions.ElementAt(0) is PackageAction2 || actions.ElementAt(1) is PackageAction2; + bool hasAction1 = actions.ElementAt(0) is PackageAction1 || actions.ElementAt(1) is PackageAction1; + bool hasAction2 = actions.ElementAt(0) is PackageAction2 || actions.ElementAt(1) is PackageAction2; Assert.IsTrue(hasAction1); Assert.IsTrue(hasAction2); } - #region Test Objects - public class PackageAction1 : IPackageAction { - public bool Execute(string packageName, XElement xmlData) - { - throw new NotImplementedException(); - } + public bool Execute(string packageName, XElement xmlData) => throw new NotImplementedException(); - public string Alias() - { - return "pa1"; - } + public string Alias() => "pa1"; - public bool Undo(string packageName, XElement xmlData) - { - throw new NotImplementedException(); - } + public bool Undo(string packageName, XElement xmlData) => throw new NotImplementedException(); - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } + public XmlNode SampleXml() => throw new NotImplementedException(); } public class PackageAction2 : IPackageAction { - public bool Execute(string packageName, XElement xmlData) - { - throw new NotImplementedException(); - } + public bool Execute(string packageName, XElement xmlData) => throw new NotImplementedException(); - public string Alias() - { - return "pa2"; - } + public string Alias() => "pa2"; - public bool Undo(string packageName, XElement xmlData) - { - throw new NotImplementedException(); - } + public bool Undo(string packageName, XElement xmlData) => throw new NotImplementedException(); - public XmlNode SampleXml() - { - throw new NotImplementedException(); - } + public XmlNode SampleXml() => throw new NotImplementedException(); } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs index 9ef2cf5ae0..1becc88138 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs @@ -1,17 +1,18 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web.BackOffice.Trees; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { - /// /// Tests for typefinder /// @@ -24,11 +25,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing private Assembly[] _assemblies; [SetUp] - public void Initialize() - { - _assemblies = new[] + public void Initialize() => _assemblies = new[] { - this.GetType().Assembly, + GetType().Assembly, typeof(System.Guid).Assembly, typeof(NUnit.Framework.Assert).Assembly, typeof(System.Xml.NameTable).Assembly, @@ -36,13 +35,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing typeof(TypeFinder).Assembly, }; - } - [Test] public void Find_Class_Of_Type_With_Attribute() { var typeFinder = new TypeFinder(Mock.Of>(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); - var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies); + IEnumerable typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies); Assert.AreEqual(2, typesFound.Count()); } @@ -50,10 +47,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void Find_Classes_With_Attribute() { var typeFinder = new TypeFinder(Mock.Of>(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); - var typesFound = typeFinder.FindClassesWithAttribute(_assemblies); + IEnumerable typesFound = typeFinder.FindClassesWithAttribute(_assemblies); Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree] - typesFound = typeFinder.FindClassesWithAttribute(new[] { typeof (TreeAttribute).Assembly }); + typesFound = typeFinder.FindClassesWithAttribute(new[] { typeof(TreeAttribute).Assembly }); Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] typesFound = typeFinder.FindClassesWithAttribute(); @@ -63,27 +60,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class MyTestAttribute : Attribute { - } public abstract class TestEditor { - } [MyTest] public class BenchmarkTestEditor : TestEditor { - } [MyTest] public class MyOtherTestEditor : TestEditor { - } - } - - } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs index c78992d68c..3126cce538 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data.Odbc; @@ -7,6 +10,7 @@ using System.Data.SqlClient; using System.Linq; using System.Reflection; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Composing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing @@ -17,19 +21,29 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [TestFixture] public class TypeHelperTests { + private class Base + { + } + private interface IBase + { + } - class Base { } + private interface IDerived : IBase + { + } - interface IBase { } + private class Derived : Base, IBase + { + } - interface IDerived : IBase { } + private class Derived2 : Derived + { + } - class Derived : Base, IBase { } - - class Derived2 : Derived { } - - class DerivedI : IDerived { } + private class DerivedI : IDerived + { + } [Test] public void Is_Static_Class() @@ -41,44 +55,41 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [Test] public void Find_Common_Base_Class() { - var t1 = TypeHelper.GetLowestBaseType(typeof (OleDbCommand), - typeof (OdbcCommand), - typeof (SqlCommand)); + Attempt t1 = TypeHelper.GetLowestBaseType( + typeof(OleDbCommand), + typeof(OdbcCommand), + typeof(SqlCommand)); Assert.IsFalse(t1.Success); - var t2 = TypeHelper.GetLowestBaseType(typeof (OleDbCommand), - typeof (OdbcCommand), - typeof (SqlCommand), - typeof (Component)); + Attempt t2 = TypeHelper.GetLowestBaseType( + typeof(OleDbCommand), + typeof(OdbcCommand), + typeof(SqlCommand), + typeof(Component)); Assert.IsTrue(t2.Success); Assert.AreEqual(typeof(Component), t2.Result); - var t3 = TypeHelper.GetLowestBaseType(typeof (OleDbCommand), - typeof (OdbcCommand), - typeof (SqlCommand), - typeof (Component), - typeof (Component).BaseType); + Attempt t3 = TypeHelper.GetLowestBaseType( + typeof(OleDbCommand), + typeof(OdbcCommand), + typeof(SqlCommand), + typeof(Component), + typeof(Component).BaseType); Assert.IsTrue(t3.Success); Assert.AreEqual(typeof(MarshalByRefObject), t3.Result); - var t4 = TypeHelper.GetLowestBaseType(typeof(OleDbCommand), - typeof(OdbcCommand), - typeof(SqlCommand), - typeof(Component), - typeof(Component).BaseType, - typeof(int)); + Attempt t4 = TypeHelper.GetLowestBaseType( + typeof(OleDbCommand), + typeof(OdbcCommand), + typeof(SqlCommand), + typeof(Component), + typeof(Component).BaseType, + typeof(int)); Assert.IsFalse(t4.Success); - var t5 = TypeHelper.GetLowestBaseType(typeof(PropertyAliasDto)); + Attempt t5 = TypeHelper.GetLowestBaseType(typeof(PropertyAliasDto)); Assert.IsTrue(t5.Success); Assert.AreEqual(typeof(PropertyAliasDto), t5.Result); - - //var t6 = TypeHelper.GetLowestBaseType(typeof (IApplicationEventHandler), - // typeof (SchedulerComponent), - // typeof(CacheRefresherComponent)); - //Assert.IsTrue(t6.Success); - //Assert.AreEqual(typeof(IApplicationEventHandler), t6.Result); - } [Test] @@ -96,10 +107,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(TypeHelper.MatchType(typeof(List), typeof(System.Collections.IEnumerable), bindings)); Assert.AreEqual(0, bindings.Count); - var t1 = typeof(IList<>); // IList<> - var a1 = t1.GetGenericArguments()[0]; // + Type t1 = typeof(IList<>); // IList<> + Type a1 = t1.GetGenericArguments()[0]; // t1 = t1.MakeGenericType(a1); // IList - var t2 = a1; + Type t2 = a1; bindings = new Dictionary(); Assert.IsTrue(TypeHelper.MatchType(typeof(int), t2, bindings)); @@ -145,12 +156,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing // both are OK Assert.IsTrue(TypeHelper.MatchType(typeof(List), typeof(IEnumerable<>))); - var t1 = typeof (IDictionary<,>); // IDictionary<,> - var a1 = t1.GetGenericArguments()[0]; + Type t1 = typeof(IDictionary<,>); // IDictionary<,> + Type a1 = t1.GetGenericArguments()[0]; t1 = t1.MakeGenericType(a1, a1); // IDictionary // both are OK - Assert.IsTrue(TypeHelper.MatchType(typeof(Dictionary), t1)); Assert.IsFalse(TypeHelper.MatchType(typeof(Dictionary), t1)); @@ -164,7 +174,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(TypeHelper.MatchType(typeof(Derived2), typeof(IBase<>))); Assert.IsTrue(TypeHelper.MatchType(typeof(int?), typeof(Nullable<>))); - Assert.IsTrue(TypeHelper.MatchType(typeof(Derived), typeof(object))); Assert.IsFalse(TypeHelper.MatchType(typeof(Derived), typeof(List<>))); Assert.IsFalse(TypeHelper.MatchType(typeof(Derived), typeof(IEnumerable<>))); @@ -172,21 +181,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.IsTrue(TypeHelper.MatchType(typeof(List), typeof(IEnumerable))); Assert.IsFalse(TypeHelper.MatchType(typeof(int), typeof(Nullable<>))); - //This get's the "Type" from the Count extension method on IEnumerable, however the type IEnumerable isn't + // This get's the "Type" from the Count extension method on IEnumerable, however the type IEnumerable isn't // IEnumerable<> and it is not a generic definition, this attempts to explain that: // http://blogs.msdn.com/b/haibo_luo/archive/2006/02/17/534480.aspx - - var genericEnumerableNonGenericDefinition = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) + Type genericEnumerableNonGenericDefinition = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public) .Single(x => x.Name == "Count" && x.GetParameters().Count() == 1) .GetParameters() .Single() .ParameterType; Assert.IsTrue(TypeHelper.MatchType(typeof(List), genericEnumerableNonGenericDefinition)); - } - [Test] public void CreateOpenGenericTypes() { @@ -198,7 +204,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing // assembly; or null if the current instance represents a generic type parameter, an array type, pointer // type, or byref type based on a type parameter, or a generic type that is not a generic type definition // but contains unresolved type parameters." - var t = Type.GetType("System.Collections.Generic.IList`1"); Assert.IsNotNull(t); Assert.IsTrue(t.IsGenericTypeDefinition); @@ -206,7 +211,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing Assert.AreEqual("System.Collections.Generic.IList`1", t.FullName); Assert.AreEqual("System.Collections.Generic.IList`1[T]", t.ToString()); - t = typeof (IList<>); + t = typeof(IList<>); Assert.IsTrue(t.IsGenericTypeDefinition); Assert.AreEqual("IList`1", t.Name); Assert.AreEqual("System.Collections.Generic.IList`1", t.FullName); @@ -241,7 +246,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing t = typeof(IList); Assert.AreEqual("System.Collections.Generic.IList`1[System.Int32]", t.ToString()); - t = typeof (IDictionary<,>); + t = typeof(IDictionary<,>); t = t.MakeGenericType(typeof(int), t.GetGenericArguments()[1]); Assert.IsFalse(t.IsGenericTypeDefinition); // not anymore Assert.AreEqual("IDictionary`2", t.Name); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs index 6bab57ee41..3179985c99 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Umbraco.Core.Composing; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index 36843ad1cc..5049f6cc0b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -1,11 +1,14 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; @@ -26,28 +29,30 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void Initialize() { // this ensures it's reset - var typeFinder = TestHelper.GetTypeFinder(); - _typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, - new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), - Mock.Of>(), new ProfilingLogger(Mock.Of>(), Mock.Of()), false, + ITypeFinder typeFinder = TestHelper.GetTypeFinder(); - // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver - // TODO: Should probably update this so it only searches this assembly and add custom types to be found - new[] + // For testing, we'll specify which assemblies are scanned for the PluginTypeResolver + // TODO: Should probably update this so it only searches this assembly and add custom types to be found + Assembly[] assemblies = new[] { - this.GetType().Assembly, - typeof(System.Guid).Assembly, - typeof(NUnit.Framework.Assert).Assembly, + GetType().Assembly, + typeof(Guid).Assembly, + typeof(Assert).Assembly, typeof(System.Xml.NameTable).Assembly, typeof(System.Configuration.GenericEnumConverter).Assembly, - //typeof(TabPage).Assembly, + ////typeof(TabPage).Assembly, typeof(TypeFinder).Assembly, typeof(UmbracoContext).Assembly, typeof(CheckBoxListPropertyEditor).Assembly - }); - - - + }; + _typeLoader = new TypeLoader( + typeFinder, + NoAppCache.Instance, + new DirectoryInfo(TestHelper.GetHostingEnvironment().MapPathContentRoot(Constants.SystemDirectories.TempData)), + Mock.Of>(), + new ProfilingLogger(Mock.Of>(), Mock.Of()), + false, + assemblies); } [TearDown] @@ -55,106 +60,108 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { _typeLoader = null; - // cleanup - var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - var tlDir = Path.Combine(assDir.FullName, "TypeLoader"); + DirectoryInfo assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + string tlDir = Path.Combine(assDir.FullName, "TypeLoader"); if (!Directory.Exists(tlDir)) + { return; + } + Directory.Delete(tlDir, true); } private DirectoryInfo PrepareFolder() { - var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - var tlDir = Path.Combine(assDir.FullName, "TypeLoader"); - var dir = Directory.CreateDirectory(Path.Combine(tlDir, Guid.NewGuid().ToString("N"))); + DirectoryInfo assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + string tlDir = Path.Combine(assDir.FullName, "TypeLoader"); + DirectoryInfo dir = Directory.CreateDirectory(Path.Combine(tlDir, Guid.NewGuid().ToString("N"))); return dir; } - //[Test] - //public void Scan_Vs_Load_Benchmark() - //{ - // var typeLoader = new TypeLoader(false); - // var watch = new Stopwatch(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var refreshers = typeLoader.GetTypes(false); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); - //} + ////[Test] + ////public void Scan_Vs_Load_Benchmark() + ////{ + //// var typeLoader = new TypeLoader(false); + //// var watch = new Stopwatch(); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); + //// watch.Reset(); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var refreshers = typeLoader.GetTypes(false); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); + ////} - ////NOTE: This test shows that Type.GetType is 100% faster than Assembly.Load(..).GetType(...) so we'll use that :) - //[Test] - //public void Load_Type_Benchmark() - //{ - // var watch = new Stopwatch(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.macroCacheRefresh"); - // var type3 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.templateCacheRefresh"); - // var type4 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.presentation.cache.MediaLibraryRefreshers"); - // var type5 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.presentation.cache.pageRefresher"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - //} + //////NOTE: This test shows that Type.GetType is 100% faster than Assembly.Load(..).GetType(...) so we'll use that :) + ////[Test] + ////public void Load_Type_Benchmark() + ////{ + //// var watch = new Stopwatch(); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); + //// watch.Reset(); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var type2 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") + //// .GetType("umbraco.macroCacheRefresh"); + //// var type3 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") + //// .GetType("umbraco.templateCacheRefresh"); + //// var type4 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") + //// .GetType("umbraco.presentation.cache.MediaLibraryRefreshers"); + //// var type5 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") + //// .GetType("umbraco.presentation.cache.pageRefresher"); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); + //// watch.Reset(); + //// watch.Start(); + //// for (var i = 0; i < 1000; i++) + //// { + //// var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); + //// } + //// watch.Stop(); + //// Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); + ////} [Test] public void Detect_Legacy_Plugin_File_List() { - var filePath = _typeLoader.GetTypesListFilePath(); - var fileDir = Path.GetDirectoryName(filePath); + string filePath = _typeLoader.GetTypesListFilePath(); + string fileDir = Path.GetDirectoryName(filePath); Directory.CreateDirectory(fileDir); File.WriteAllText(filePath, @" @@ -192,35 +199,41 @@ AnotherContentFinder [Test] public void Create_Cached_Plugin_File() { - var types = new[] { typeof(TypeLoader), typeof(TypeLoaderTests), typeof(IUmbracoContext) }; + Type[] types = new[] { typeof(TypeLoader), typeof(TypeLoaderTests), typeof(IUmbracoContext) }; var typeList1 = new TypeLoader.TypeList(typeof(object), null); - foreach (var type in types) typeList1.Add(type); + foreach (Type type in types) + { + typeList1.Add(type); + } + _typeLoader.AddTypeList(typeList1); _typeLoader.WriteCache(); - var plugins = _typeLoader.TryGetCached(typeof(object), null); - var diffType = _typeLoader.TryGetCached(typeof(object), typeof(ObsoleteAttribute)); + Attempt> plugins = _typeLoader.TryGetCached(typeof(object), null); + Attempt> diffType = _typeLoader.TryGetCached(typeof(object), typeof(ObsoleteAttribute)); Assert.IsTrue(plugins.Success); - //this will be false since there is no cache of that type resolution kind + + // This will be false since there is no cache of that type resolution kind Assert.IsFalse(diffType.Success); Assert.AreEqual(3, plugins.Result.Count()); - var shouldContain = types.Select(x => x.AssemblyQualifiedName); - //ensure they are all found + IEnumerable shouldContain = types.Select(x => x.AssemblyQualifiedName); + + // Ensure they are all found Assert.IsTrue(plugins.Result.ContainsAll(shouldContain)); } [Test] public void Get_Plugins_Hash_With_Hash_Generator() { - //Arrange - var dir = PrepareFolder(); - var d1 = dir.CreateSubdirectory("1"); - var d2 = dir.CreateSubdirectory("2"); - var d3 = dir.CreateSubdirectory("3"); - var d4 = dir.CreateSubdirectory("4"); + // Arrange + DirectoryInfo dir = PrepareFolder(); + DirectoryInfo d1 = dir.CreateSubdirectory("1"); + DirectoryInfo d2 = dir.CreateSubdirectory("2"); + DirectoryInfo d3 = dir.CreateSubdirectory("3"); + DirectoryInfo d4 = dir.CreateSubdirectory("4"); var f1 = new FileInfo(Path.Combine(d1.FullName, "test1.dll")); var f2 = new FileInfo(Path.Combine(d1.FullName, "test2.dll")); var f3 = new FileInfo(Path.Combine(d2.FullName, "test1.dll")); @@ -235,16 +248,16 @@ AnotherContentFinder f5.CreateText().Close(); f6.CreateText().Close(); f7.CreateText().Close(); - var list1 = new[] { f1, f2, f3, f4, f5, f6 }; - var list2 = new[] { f1, f3, f5 }; - var list3 = new[] { f1, f3, f5, f7 }; + FileInfo[] list1 = new[] { f1, f2, f3, f4, f5, f6 }; + FileInfo[] list2 = new[] { f1, f3, f5 }; + FileInfo[] list3 = new[] { f1, f3, f5, f7 }; - //Act - var hash1 = GetFileHash(list1, new ProfilingLogger(Mock.Of>(), Mock.Of())); - var hash2 = GetFileHash(list2, new ProfilingLogger(Mock.Of>(), Mock.Of())); - var hash3 = GetFileHash(list3, new ProfilingLogger(Mock.Of>(), Mock.Of())); + // Act + string hash1 = GetFileHash(list1, new ProfilingLogger(Mock.Of>(), Mock.Of())); + string hash2 = GetFileHash(list2, new ProfilingLogger(Mock.Of>(), Mock.Of())); + string hash3 = GetFileHash(list3, new ProfilingLogger(Mock.Of>(), Mock.Of())); - //Assert + // Assert Assert.AreNotEqual(hash1, hash2); Assert.AreNotEqual(hash1, hash3); Assert.AreNotEqual(hash2, hash3); @@ -263,14 +276,14 @@ AnotherContentFinder [Test] public void Resolves_Types() { - var foundTypes1 = _typeLoader.ResolveFindMeTypes(); + IEnumerable foundTypes1 = _typeLoader.ResolveFindMeTypes(); Assert.AreEqual(2, foundTypes1.Count()); } [Test] public void GetDataEditors() { - var types = _typeLoader.GetDataEditors(); + IEnumerable types = _typeLoader.GetDataEditors(); Assert.AreEqual(39, types.Count()); } @@ -287,32 +300,28 @@ AnotherContentFinder propEditors.Add(typeof(LabelPropertyEditor)); types.Add(propEditors); - var found = types.SingleOrDefault(x => x.BaseType == typeof(DataEditor) && x.AttributeType == null); + TypeLoader.TypeList found = types.SingleOrDefault(x => x.BaseType == typeof(DataEditor) && x.AttributeType == null); Assert.IsNotNull(found); - //This should not find a type list of this type - var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof(IDataEditor) && x.AttributeType == null); + // This should not find a type list of this type + TypeLoader.TypeList shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof(IDataEditor) && x.AttributeType == null); Assert.IsNull(shouldNotFind); } public interface IFindMe : IDiscoverable { - } public class FindMe1 : IFindMe { - } public class FindMe2 : IFindMe { - } - /// /// Returns a unique hash for a combination of FileInfo objects. /// @@ -324,19 +333,23 @@ AnotherContentFinder { using (logger.DebugDuration("Determining hash of code files on disk", "Hash determined")) { - using (var generator = new HashGenerator()) - { - // get the distinct file infos to hash - var uniqInfos = new HashSet(); + using var generator = new HashGenerator(); - foreach (var fileOrFolder in filesAndFolders) + // Get the distinct file infos to hash. + var uniqInfos = new HashSet(); + + foreach (FileSystemInfo fileOrFolder in filesAndFolders) + { + if (uniqInfos.Contains(fileOrFolder.FullName)) { - if (uniqInfos.Contains(fileOrFolder.FullName)) continue; - uniqInfos.Add(fileOrFolder.FullName); - generator.AddFileSystemItem(fileOrFolder); + continue; } - return generator.GenerateHash(); + + uniqInfos.Add(fileOrFolder.FullName); + generator.AddFileSystemItem(fileOrFolder); } + + return generator.GenerateHash(); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Extensions/HealthCheckSettingsExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Extensions/HealthCheckSettingsExtensionsTests.cs index 5bc14b3792..d3e2ca3014 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Extensions/HealthCheckSettingsExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Extensions/HealthCheckSettingsExtensionsTests.cs @@ -4,8 +4,8 @@ using System; using NUnit.Framework; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Extensions; using Umbraco.Core.Configuration.Models; -using Umbraco.Infrastructure.Configuration.Extensions; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Extensions { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/GlobalSettingsTests.cs similarity index 88% rename from src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/GlobalSettingsTests.cs index 3b0d13c584..3c3de455f5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/GlobalSettingsTests.cs @@ -1,4 +1,7 @@ -using AutoFixture.NUnit3; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using AutoFixture.NUnit3; using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Core.Configuration; @@ -6,8 +9,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Tests.UnitTests.AutoFixture; using Umbraco.Web.Common.AspNetCore; - -namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configurations +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models { [TestFixture] public class GlobalSettingsTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs index f286dd42b0..ca20129092 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Configuration.Models.Validation; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validation { [TestFixture] - public class GlobalSettingsValidationTests + public class GlobalSettingsValidatorTests { [Test] public void Returns_Success_ForValid_Configuration() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/HealthChecksSettingsValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/HealthChecksSettingsValidatorTests.cs index 9ae5444134..b645c758dc 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/HealthChecksSettingsValidatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/HealthChecksSettingsValidatorTests.cs @@ -11,7 +11,7 @@ using Umbraco.Core.Configuration.Models.Validation; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validation { [TestFixture] - public class HealthChecksSettingsValidationTests + public class HealthChecksSettingsValidatorTests { [Test] public void Returns_Success_ForValid_Configuration() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/NCronTabParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/NCronTabParserTests.cs similarity index 89% rename from src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/NCronTabParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/NCronTabParserTests.cs index 4a38de831d..8ab3d01882 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/NCronTabParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/NCronTabParserTests.cs @@ -1,7 +1,10 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Configuration; -namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configurations +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration { [TestFixture] public class NCronTabParserTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs index dec0ff9a29..82eef0eb71 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs @@ -1,5 +1,7 @@ -using NUnit.Framework; -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Scoping; @@ -8,39 +10,27 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [TestFixture] public class CallContextTests { - private static bool _first; + private static bool s_first; - static CallContextTests() - { - SafeCallContext.Register(() => - { - CallContext.SetData("test1", null); - CallContext.SetData("test2", null); - return null; - }, o => { }); - } + static CallContextTests() => SafeCallContext.Register( + () => + { + CallContext.SetData("test1", null); + CallContext.SetData("test2", null); + return null; + }, o => { }); [OneTimeSetUp] - public void SetUpFixture() - { - _first = true; - } + public void SetUpFixture() => s_first = true; // logical call context leaks between tests // is is required to clear it before tests begin // (don't trust other tests properly tearing down) - [SetUp] - public void Setup() - { - SafeCallContext.Clear(); - } + public void Setup() => SafeCallContext.Clear(); [TearDown] - public void TearDown() - { - SafeCallContext.Clear(); - } + public void TearDown() => SafeCallContext.Clear(); [Test] public void Test1() @@ -50,9 +40,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings CallContext.SetData("test3b", "test3b"); - if (_first) + if (s_first) { - _first = false; + s_first = false; } else { @@ -72,9 +62,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { CallContext.SetData("test3a", "test3a"); - if (_first) + if (s_first) { - _first = false; + s_first = false; } else { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs index f3fa46ef5e..848edddf1c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -23,16 +26,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings } [TearDown] - public void TestTearDown() - { - Thread.CurrentThread.CurrentCulture = _savedCulture; - } + public void TestTearDown() => Thread.CurrentThread.CurrentCulture = _savedCulture; [Test] public void Can_Convert_List_To_Enumerable() { - var list = new List {"hello", "world", "awesome"}; - var result = list.TryConvertTo>(); + var list = new List { "hello", "world", "awesome" }; + Attempt> result = list.TryConvertTo>(); Assert.IsTrue(result.Success); Assert.AreEqual(3, result.Result.Count()); } @@ -40,16 +40,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ObjectExtensions_Object_To_Dictionary() { - //Arrange - + // Arrange var obj = new { Key1 = "value1", Key2 = "value2", Key3 = "value3" }; - //Act - - var d = obj.ToDictionary(); - - //Assert + // Act + IDictionary d = obj.ToDictionary(); + // Assert Assert.IsTrue(d.Keys.Contains("Key1")); Assert.IsTrue(d.Keys.Contains("Key2")); Assert.IsTrue(d.Keys.Contains("Key3")); @@ -61,8 +58,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void CanConvertIntToNullableInt() { - var i = 1; - var result = i.TryConvertTo(); + int i = 1; + Attempt result = i.TryConvertTo(); Assert.That(result.Success, Is.True); } @@ -70,7 +67,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings public void CanConvertNullableIntToInt() { int? i = 1; - var result = i.TryConvertTo(); + Attempt result = i.TryConvertTo(); Assert.That(result.Success, Is.True); } @@ -79,20 +76,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { var testCases = new Dictionary { - {"TRUE", true}, - {"True", true}, - {"true", true}, - {"1", true}, - {"FALSE", false}, - {"False", false}, - {"false", false}, - {"0", false}, - {"", false} + { "TRUE", true }, + { "True", true }, + { "true", true }, + { "1", true }, + { "FALSE", false }, + { "False", false }, + { "false", false }, + { "0", false }, + { string.Empty, false } }; - foreach (var testCase in testCases) + foreach (KeyValuePair testCase in testCases) { - var result = testCase.Key.TryConvertTo(); + Attempt result = testCase.Key.TryConvertTo(); Assert.IsTrue(result.Success, testCase.Key); Assert.AreEqual(testCase.Value, result.Result, testCase.Key); @@ -113,7 +110,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { var dateTime = new DateTime(2012, 11, 10, 13, 14, 15); - var result = date.TryConvertTo(); + Attempt result = date.TryConvertTo(); Assert.IsTrue(result.Success, date); Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), outcome, date); @@ -122,7 +119,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public virtual void CanConvertBlankStringToNullDateTime() { - var result = "".TryConvertTo(); + Attempt result = string.Empty.TryConvertTo(); Assert.IsTrue(result.Success); Assert.IsNull(result.Result); } @@ -130,7 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public virtual void CanConvertBlankStringToNullBool() { - var result = "".TryConvertTo(); + Attempt result = string.Empty.TryConvertTo(); Assert.IsTrue(result.Success); Assert.IsNull(result.Result); } @@ -138,7 +135,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public virtual void CanConvertBlankStringToDateTime() { - var result = "".TryConvertTo(); + Attempt result = string.Empty.TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual(DateTime.MinValue, result.Result); } @@ -146,7 +143,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public virtual void CanConvertObjectToString_Using_ToString_Overload() { - var result = new MyTestObject().TryConvertTo(); + Attempt result = new MyTestObject().TryConvertTo(); Assert.IsTrue(result.Success); Assert.AreEqual("Hello world", result.Result); @@ -156,7 +153,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings public virtual void CanConvertObjectToSameObject() { var obj = new MyTestObject(); - var result = obj.TryConvertTo(); + Attempt result = obj.TryConvertTo(); Assert.AreEqual(obj, result.Result); } @@ -164,7 +161,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ConvertToIntegerTest() { - var conv = "100".TryConvertTo(); + Attempt conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100, conv.Result); @@ -198,7 +195,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ConvertToDecimalTest() { - var conv = "100".TryConvertTo(); + Attempt conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100m, conv.Result); @@ -234,7 +231,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ConvertToNullableDecimalTest() { - var conv = "100".TryConvertTo(); + Attempt conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100m, conv.Result); @@ -270,7 +267,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ConvertToDateTimeTest() { - var conv = "2016-06-07".TryConvertTo(); + Attempt conv = "2016-06-07".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result); } @@ -278,7 +275,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ConvertToNullableDateTimeTest() { - var conv = "2016-06-07".TryConvertTo(); + Attempt conv = "2016-06-07".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result); } @@ -286,19 +283,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var result = valueEditor.TryConvertValueToCrlType(12.34d); + Attempt result = valueEditor.TryConvertValueToCrlType(12.34d); Assert.IsTrue(result.Success); Assert.AreEqual(12.34d, result.Result); } private class MyTestObject { - public override string ToString() - { - return "Hello world"; - } + public override string ToString() => "Hello world"; } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index a0dddd8b5e..7ebbe72ac1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -1,11 +1,9 @@ -using System; -using Microsoft.Extensions.Options; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Strings; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs index e8fe9d5415..8703d4d7f4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -14,10 +17,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings public class UdiTests { [SetUp] - public void SetUp() - { - UdiParser.ResetUdiTypes(); - } + public void SetUp() => UdiParser.ResetUdiTypes(); [Test] public void StringUdiCtorTest() @@ -31,7 +31,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void StringUdiParseTest() { - var udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id"); + Udi udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id"); Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.IsInstanceOf(udi); var stringEntityId = udi as StringUdi; @@ -56,7 +56,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Assert.AreEqual("%2Fthis%20is%20a%20test", Uri.EscapeDataString("/this is a test")); Assert.AreEqual("/this%20is%20a%20test", Uri.EscapeUriString("/this is a test")); - var udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test"); + Udi udi = UdiParser.Parse("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test"); Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType); Assert.IsInstanceOf(udi); var stringEntityId = udi as StringUdi; @@ -76,13 +76,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { // reserved = : / ? # [ ] @ ! $ & ' ( ) * + , ; = // unreserved = alpha digit - . _ ~ - Assert.AreEqual("%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2B%2C%3B%3D.-_~%25", Uri.EscapeDataString(":/?#[]@!$&'()+,;=.-_~%")); Assert.AreEqual(":/?#[]@!$&'()+,;=.-_~%25", Uri.EscapeUriString(":/?#[]@!$&'()+,;=.-_~%")); // we cannot have reserved chars at random places // we want to keep the / in string udis - var r = string.Join("/", "path/to/View[1].cshtml".Split('/').Select(Uri.EscapeDataString)); Assert.AreEqual("path/to/View%5B1%5D.cshtml", r); Assert.IsTrue(Uri.IsWellFormedUriString("umb://partial-view-macro/" + r, UriKind.Absolute)); @@ -90,8 +88,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings // with the proper fix in StringUdi this should work: var udi1 = new StringUdi("partial-view-macro", "path/to/View[1].cshtml"); Assert.AreEqual("umb://partial-view-macro/path/to/View%5B1%5D.cshtml", udi1.ToString()); - var udi2 = UdiParser.Parse("umb://partial-view-macro/path/to/View%5B1%5D.cshtml"); - Assert.AreEqual("path/to/View[1].cshtml", ((StringUdi) udi2).Id); + Udi udi2 = UdiParser.Parse("umb://partial-view-macro/path/to/View%5B1%5D.cshtml"); + Assert.AreEqual("path/to/View[1].cshtml", ((StringUdi)udi2).Id); } [Test] @@ -109,7 +107,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { var guid = Guid.NewGuid(); var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"); - var udi = UdiParser.Parse(s); + Udi udi = UdiParser.Parse(s); Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.IsInstanceOf(udi); var gudi = udi as GuidUdi; @@ -127,8 +125,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Assert.IsTrue(new GuidUdi("type", guid1).Equals(new GuidUdi("type", guid1))); Assert.IsTrue(new GuidUdi("type", guid1) == new GuidUdi("type", guid1)); - Assert.IsTrue(((Udi)new GuidUdi("type", guid1)).Equals((Udi)new GuidUdi("type", guid1))); - Assert.IsTrue((Udi)new GuidUdi("type", guid1) == (Udi)new GuidUdi("type", guid1)); + Assert.IsTrue(new GuidUdi("type", guid1).Equals(new GuidUdi("type", guid1))); + Assert.IsTrue(new GuidUdi("type", guid1) == new GuidUdi("type", guid1)); Assert.IsFalse(new GuidUdi("type", guid1).Equals(new GuidUdi("typex", guid1))); Assert.IsFalse(new GuidUdi("type", guid1) == new GuidUdi("typex", guid1)); @@ -143,7 +141,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings public void DistinctTest() { var guid1 = Guid.NewGuid(); - var entities = new[] + GuidUdi[] entities = new[] { new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1), new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1), @@ -160,7 +158,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType); Assert.AreEqual(guid, ((GuidUdi)udi).Guid); - // *not* testing whether Udi.Create(type, invalidValue) throws // because we don't throw anymore - see U4-10409 } @@ -176,7 +173,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Assert.IsTrue(guidUdi.IsRoot); Assert.AreEqual("umb://any-guid/00000000000000000000000000000000", guidUdi.ToString()); - var udi = UdiParser.Parse("umb://any-string/"); + Udi udi = UdiParser.Parse("umb://any-string/"); Assert.IsTrue(udi.IsRoot); Assert.IsInstanceOf(udi); @@ -194,14 +191,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings { // can parse open string udi var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString; - Udi stringUdi; - Assert.IsTrue(UdiParser.TryParse(stringUdiString, out stringUdi)); + Assert.IsTrue(UdiParser.TryParse(stringUdiString, out Udi stringUdi)); Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id); // can parse open guid udi var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid; - Udi guidUdi; - Assert.IsTrue(UdiParser.TryParse(guidUdiString, out guidUdi)); + Assert.IsTrue(UdiParser.TryParse(guidUdiString, out Udi guidUdi)); Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid); // can create a range @@ -219,13 +214,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Converters = new JsonConverter[] { new UdiJsonConverter(), new UdiRangeJsonConverter() } }; - var guid = Guid.NewGuid(); var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid); var json = JsonConvert.SerializeObject(udi, settings); Assert.AreEqual(string.Format("\"umb://any-guid/{0:N}\"", guid), json); - var dudi = JsonConvert.DeserializeObject(json, settings); + Udi dudi = JsonConvert.DeserializeObject(json, settings); Assert.AreEqual(Constants.UdiEntityType.AnyGuid, dudi.EntityType); Assert.AreEqual(guid, ((GuidUdi)dudi).Guid); @@ -233,7 +227,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings json = JsonConvert.SerializeObject(range, settings); Assert.AreEqual(string.Format("\"umb://any-guid/{0:N}?children\"", guid), json); - var drange = JsonConvert.DeserializeObject(json, settings); + UdiRange drange = JsonConvert.DeserializeObject(json, settings); Assert.AreEqual(udi, drange.Udi); Assert.AreEqual(string.Format("umb://any-guid/{0:N}", guid), drange.Udi.UriValue.ToString()); Assert.AreEqual(Constants.DeploySelector.ChildrenOfThis, drange.Selector); @@ -242,9 +236,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void ValidateUdiEntityType() { - var types = UdiParser.GetKnownUdiTypes(); + Dictionary types = UdiParser.GetKnownUdiTypes(); - foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static)) + foreach (FieldInfo fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static)) { // IsLiteral determines if its value is written at // compile time and not changeable @@ -257,7 +251,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings var value = fi.GetValue(null).ToString(); if (types.ContainsKey(value) == false) + { Assert.Fail("Error in class Constants.UdiEntityType, type \"{0}\" is not declared by GetTypes.", value); + } + types.Remove(value); } } @@ -268,11 +265,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings [Test] public void KnownTypes() { - Udi udi; - // cannot parse an unknown type, udi is null // this will scan - Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", out udi)); + Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", out Udi udi)); Assert.IsNull(udi); UdiParser.ResetUdiTypes(); @@ -299,52 +294,28 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings Assert.IsInstanceOf(udi); // can get method for Deploy compatibility - var method = typeof(UdiParser).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(bool) }, null); + MethodInfo method = typeof(UdiParser).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(bool) }, null); Assert.IsNotNull(method); } [UdiDefinition("foo", UdiType.GuidUdi)] public class FooConnector : IServiceConnector { - public IArtifact GetArtifact(Udi udi) - { - throw new NotImplementedException(); - } + public IArtifact GetArtifact(Udi udi) => throw new NotImplementedException(); - public IArtifact GetArtifact(object entity) - { - throw new NotImplementedException(); - } + public IArtifact GetArtifact(object entity) => throw new NotImplementedException(); - public ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context) - { - throw new NotImplementedException(); - } + public ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context) => throw new NotImplementedException(); - public void Process(ArtifactDeployState dart, IDeployContext context, int pass) - { - throw new NotImplementedException(); - } + public void Process(ArtifactDeployState dart, IDeployContext context, int pass) => throw new NotImplementedException(); - public void Explode(UdiRange range, List udis) - { - throw new NotImplementedException(); - } + public void Explode(UdiRange range, List udis) => throw new NotImplementedException(); - public NamedUdiRange GetRange(Udi udi, string selector) - { - throw new NotImplementedException(); - } + public NamedUdiRange GetRange(Udi udi, string selector) => throw new NotImplementedException(); - public NamedUdiRange GetRange(string entityType, string sid, string selector) - { - throw new NotImplementedException(); - } + public NamedUdiRange GetRange(string entityType, string sid, string selector) => throw new NotImplementedException(); - public bool Compare(IArtifact art1, IArtifact art2, ICollection differences = null) - { - throw new NotImplementedException(); - } + public bool Compare(IArtifact art1, IArtifact art2, ICollection differences = null) => throw new NotImplementedException(); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs index 42e3aa7357..e91f47893f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Xml; using System.Xml.XPath; - using NUnit.Framework; namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml @@ -12,7 +10,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml [TestFixture] public class FrameworkXmlTests { - const string Xml1 = @" + private const string Xml1 = @" @@ -27,31 +25,29 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "; - // Umbraco : the following test shows that when legacy imports the whole tree in a // "contentAll" xslt macro parameter, the entire collection of nodes is cloned ie is // duplicated. // // What is the impact on memory? // What happens for non-xslt macros? - [Test] public void ImportNodeClonesImportedNode() { var doc1 = new XmlDocument(); doc1.LoadXml(Xml1); - var node1 = doc1.SelectSingleNode("//item2"); + XmlNode node1 = doc1.SelectSingleNode("//item2"); Assert.IsNotNull(node1); var doc2 = new XmlDocument(); doc2.LoadXml(""); - var node2 = doc2.ImportNode(node1, true); - var root2 = doc2.DocumentElement; + XmlNode node2 = doc2.ImportNode(node1, true); + XmlElement root2 = doc2.DocumentElement; Assert.IsNotNull(root2); root2.AppendChild(node2); - var node3 = doc2.SelectSingleNode("//item2"); + XmlNode node3 = doc2.SelectSingleNode("//item2"); Assert.AreNotSame(node1, node2); // has been cloned Assert.AreSame(node2, node3); // has been appended @@ -59,19 +55,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.AreNotSame(node1.FirstChild, node2.FirstChild); // deep clone } - // Umbraco: the CanRemove...NodeAndNavigate tests shows that if the underlying XmlDocument // is modified while navigating, then strange situations can be created. For xslt macros, // the result depends on what the xslt engine is doing at the moment = unpredictable. // // What happens for non-xslt macros? - [Test] public void CanRemoveCurrentNodeAndNavigate() { var doc1 = new XmlDocument(); doc1.LoadXml(Xml1); - var nav1 = doc1.CreateNavigator(); + XPathNavigator nav1 = doc1.CreateNavigator(); Assert.IsTrue(nav1.MoveToFirstChild()); Assert.AreEqual("root", nav1.Name); @@ -82,15 +76,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsTrue(nav1.MoveToNext()); Assert.AreEqual("item2", nav1.Name); - var node1 = doc1.SelectSingleNode("//item2"); + XmlNode node1 = doc1.SelectSingleNode("//item2"); Assert.IsNotNull(node1); - var parent1 = node1.ParentNode; + XmlNode parent1 = node1.ParentNode; Assert.IsNotNull(parent1); parent1.RemoveChild(node1); // navigator now navigates on an isolated fragment // that is rooted on the node that was removed - Assert.AreEqual("item2", nav1.Name); Assert.IsFalse(nav1.MoveToPrevious()); Assert.IsFalse(nav1.MoveToNext()); @@ -110,7 +103,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml { var doc1 = new XmlDocument(); doc1.LoadXml(Xml1); - var nav1 = doc1.CreateNavigator(); + XPathNavigator nav1 = doc1.CreateNavigator(); Assert.IsTrue(nav1.MoveToFirstChild()); Assert.AreEqual("root", nav1.Name); @@ -123,15 +116,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsTrue(nav1.MoveToFirstChild()); Assert.AreEqual("item21", nav1.Name); - var node1 = doc1.SelectSingleNode("//item2"); + XmlNode node1 = doc1.SelectSingleNode("//item2"); Assert.IsNotNull(node1); - var parent1 = node1.ParentNode; + XmlNode parent1 = node1.ParentNode; Assert.IsNotNull(parent1); parent1.RemoveChild(node1); // navigator now navigates on an isolated fragment // that is rooted on the node that was removed - Assert.AreEqual("item21", nav1.Name); Assert.IsTrue(nav1.MoveToParent()); Assert.AreEqual("item2", nav1.Name); @@ -148,7 +140,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml { var doc1 = new XmlDocument(); doc1.LoadXml(Xml1); - var nav1 = doc1.CreateNavigator(); + XPathNavigator nav1 = doc1.CreateNavigator(); Assert.IsTrue(nav1.MoveToFirstChild()); Assert.AreEqual("root", nav1.Name); @@ -163,14 +155,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsTrue(nav1.MoveToNext()); Assert.AreEqual("item4", nav1.Name); - var node1 = doc1.SelectSingleNode("//item2"); + XmlNode node1 = doc1.SelectSingleNode("//item2"); Assert.IsNotNull(node1); - var parent1 = node1.ParentNode; + XmlNode parent1 = node1.ParentNode; Assert.IsNotNull(parent1); parent1.RemoveChild(node1); // navigator sees the change - Assert.AreEqual("item4", nav1.Name); Assert.IsTrue(nav1.MoveToPrevious()); Assert.AreEqual("item3", nav1.Name); @@ -183,33 +174,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // on what the xslt engine is doing at the moment = unpredictable. // // What happens for non-xslt macros? - [Test] public void CanRemoveNodeAndIterate() { var doc1 = new XmlDocument(); doc1.LoadXml(Xml1); - var nav1 = doc1.CreateNavigator(); + XPathNavigator nav1 = doc1.CreateNavigator(); - var iter1 = nav1.Select("//items/*"); - var iter2 = nav1.Select("//items/*"); + XPathNodeIterator iter1 = nav1.Select("//items/*"); + XPathNodeIterator iter2 = nav1.Select("//items/*"); Assert.AreEqual(6, iter1.Count); - var node1 = doc1.SelectSingleNode("//item2"); + XmlNode node1 = doc1.SelectSingleNode("//item2"); Assert.IsNotNull(node1); - var parent1 = node1.ParentNode; + XmlNode parent1 = node1.ParentNode; Assert.IsNotNull(parent1); parent1.RemoveChild(node1); // iterator partially sees the change - Assert.AreEqual(6, iter1.Count); // has been cached, not updated Assert.AreEqual(5, iter2.Count); // not calculated yet, correct value - var count = 0; + int count = 0; while (iter1.MoveNext()) + { count++; + } Assert.AreEqual(5, count); } @@ -218,22 +209,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml public void OldFrameworkXPathBugIsFixed() { // see http://bytes.com/topic/net/answers/177129-reusing-xpathexpression-multiple-iterations - var doc = new XmlDocument(); doc.LoadXml(""); - var nav = doc.CreateNavigator(); - var expr = nav.Compile("*"); + XPathNavigator nav = doc.CreateNavigator(); + XPathExpression expr = nav.Compile("*"); - nav.MoveToFirstChild(); //root - var iter1 = nav.Select(expr); - iter1.MoveNext(); //root/a - var iter2 = iter1.Current.Select(expr); + nav.MoveToFirstChild(); // root + XPathNodeIterator iter1 = nav.Select(expr); + iter1.MoveNext(); // root/a + XPathNodeIterator iter2 = iter1.Current.Select(expr); iter2.MoveNext(); // /root/a/a1 iter2.MoveNext(); // /root/a/a2 // used to fail because iter1 and iter2 would conflict - Assert.IsTrue(iter1.MoveNext()); //root/b + Assert.IsTrue(iter1.MoveNext()); // root/b } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs index c5629aca10..d0990114e8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -7,9 +10,9 @@ using System.Net; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; +using NUnit.Framework; using Umbraco.Core.Xml; using Umbraco.Core.Xml.XPath; -using NUnit.Framework; namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml { @@ -20,8 +23,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml public void NewNavigatorIsAtRoot() { const string xml = @""; - var doc = XmlHelper.CreateXPathDocument(xml); - var nav = doc.CreateNavigator(); + XPathDocument doc = XmlHelper.CreateXPathDocument(xml); + XPathNavigator nav = doc.CreateNavigator(); Assert.AreEqual(XPathNodeType.Root, nav.NodeType); Assert.AreEqual(string.Empty, nav.Name); @@ -56,8 +59,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml ]]> "; - var doc = XmlHelper.CreateXPathDocument(xml); - var nav = doc.CreateNavigator(); + XPathDocument doc = XmlHelper.CreateXPathDocument(xml); + XPathNavigator nav = doc.CreateNavigator(); NavigatorValues(nav, true); } @@ -71,7 +74,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml NavigatorValues(nav, false); } - static void NavigatorValues(XPathNavigator nav, bool native) + private static void NavigatorValues(XPathNavigator nav, bool native) { // in non-native we can't have Value dump everything, else // we'd dump the entire database? Makes not much sense. @@ -106,7 +109,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // we have no way to tell the navigable that a value is CDATA // so the rule is, if it's null it's not there, anything else is there // and the filtering has to be done when building the content - Assert.IsTrue(nav.MoveToNext()); Assert.AreEqual("item2c", nav.Name); Assert.AreEqual("\n ", nav.Value.Lf()); // ok since it's a property @@ -166,7 +168,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var nav = new NavigableNavigator(source); nav.MoveToRoot(); - Assert.AreEqual("", nav.Name); // because we're at root + Assert.AreEqual(string.Empty, nav.Name); // because we're at root nav.MoveToFirstChild(); Assert.AreEqual("root", nav.Name); nav.MoveToFirstChild(); @@ -206,7 +208,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml nav.MoveToFirstChild(); // "poo" - Assert.AreEqual(XPathNodeType.Element, nav.NodeType); Assert.AreEqual("data", nav.Name); @@ -232,8 +233,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml { const string xml = @""; - var doc = XmlHelper.CreateXPathDocument(xml); - var nnav = doc.CreateNavigator(); + XPathDocument doc = XmlHelper.CreateXPathDocument(xml); + XPathNavigator nnav = doc.CreateNavigator(); Assert.AreEqual(xml, nnav.OuterXml); var source = new TestSource0(); @@ -285,7 +286,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource1(); var nav = new NavigableNavigator(source); - var iterator = nav.Select("//type1"); + XPathNodeIterator iterator = nav.Select("//type1"); Assert.AreEqual(1, iterator.Count); iterator.MoveNext(); Assert.AreEqual("type1", iterator.Current.Name); @@ -302,17 +303,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource2(); var nav = new NavigableNavigator(source); - var doc = XmlHelper.CreateXPathDocument("poo"); - var docNav = doc.CreateNavigator(); - var docIter = docNav.Select("//item2 [@xx=33]"); + XPathDocument doc = XmlHelper.CreateXPathDocument("poo"); + XPathNavigator docNav = doc.CreateNavigator(); + XPathNodeIterator docIter = docNav.Select("//item2 [@xx=33]"); Assert.AreEqual(1, docIter.Count); - Assert.AreEqual("", docIter.Current.Name); + Assert.AreEqual(string.Empty, docIter.Current.Name); docIter.MoveNext(); Assert.AreEqual("item2", docIter.Current.Name); - var iterator = nav.Select("//item2 [@xx=33]"); + XPathNodeIterator iterator = nav.Select("//item2 [@xx=33]"); Assert.AreEqual(1, iterator.Count); - Assert.AreEqual("", iterator.Current.Name); + Assert.AreEqual(string.Empty, iterator.Current.Name); iterator.MoveNext(); Assert.AreEqual("item2", iterator.Current.Name); } @@ -323,7 +324,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource1(); var nav = new NavigableNavigator(source); - var iterator = nav.Select("//* [@prop1=$var]", new XPathVariable("var", "1:p1")); + XPathNodeIterator iterator = nav.Select("//* [@prop1=$var]", new XPathVariable("var", "1:p1")); Assert.AreEqual(1, iterator.Count); iterator.MoveNext(); Assert.AreEqual("type1", iterator.Current.Name); @@ -335,7 +336,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource2(); var nav = new NavigableNavigator(source); - var iterator = nav.Select("//item2 [@xx=$var]", new XPathVariable("var", "33")); + XPathNodeIterator iterator = nav.Select("//item2 [@xx=$var]", new XPathVariable("var", "33")); Assert.AreEqual(1, iterator.Count); iterator.MoveNext(); Assert.AreEqual("item2", iterator.Current.Name); @@ -347,12 +348,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource4(); var nav = new NavigableNavigator(source); - var doc = XmlHelper.CreateXPathDocument(@" + XPathDocument doc = XmlHelper.CreateXPathDocument(@" dang "); - var docNav = doc.CreateNavigator(); + XPathNavigator docNav = doc.CreateNavigator(); docNav.MoveToRoot(); Assert.IsTrue(docNav.MoveToFirstChild()); @@ -366,7 +367,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsFalse(docNav.MoveToNext()); docNav.MoveToRoot(); - var docOuter = docNav.OuterXml; + string docOuter = docNav.OuterXml; nav.MoveToRoot(); Assert.IsTrue(nav.MoveToFirstChild()); @@ -380,7 +381,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsFalse(nav.MoveToNext()); nav.MoveToRoot(); - var outer = nav.OuterXml; + string outer = nav.OuterXml; Assert.AreEqual(docOuter, outer); } @@ -392,14 +393,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource1(); var nav = new NavigableNavigator(source); - var iterator = nav.Select("/*"); + XPathNodeIterator iterator = nav.Select("/*"); // but, that requires that the underlying navigator implements IHasXmlNode // so it is possible to obtain nodes from the navigator - not possible yet - var nodes = XmlNodeListFactory.CreateNodeList(iterator); + XmlNodeList nodes = XmlNodeListFactory.CreateNodeList(iterator); Assert.AreEqual(nodes.Count, 1); - var node = nodes[0]; + XmlNode node = nodes[0]; Assert.AreEqual(3, node.Attributes.Count); Assert.AreEqual("1", node.Attributes["id"].Value); @@ -434,7 +435,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.AreEqual(3, (nav.UnderlyingObject as TestContent).Id); // at that point nav is at /root/1/3 - var clone = nav.Clone() as NavigableNavigator; // move nav to /root/1/5 and ensure that clone stays at /root/1/3 @@ -475,7 +475,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource5(); var nav = new NavigableNavigator(source); - var iter = nav.Select(string.Format("//* [@id={0}]", id)); + XPathNodeIterator iter = nav.Select(string.Format("//* [@id={0}]", id)); Assert.IsTrue(iter.MoveNext()); var current = iter.Current as NavigableNavigator; Assert.AreEqual(NavigableNavigator.StatePosition.Element, current.InternalState.Position); @@ -493,7 +493,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var source = new TestSource5(); var nav = new NavigableNavigator(source); - var iter = nav.Select("//* [@id=$id]", new XPathVariable("id", id.ToString(CultureInfo.InvariantCulture))); + XPathNodeIterator iter = nav.Select("//* [@id=$id]", new XPathVariable("id", id.ToString(CultureInfo.InvariantCulture))); Assert.IsTrue(iter.MoveNext()); var current = iter.Current as NavigableNavigator; Assert.AreEqual(NavigableNavigator.StatePosition.Element, current.InternalState.Position); @@ -578,8 +578,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // go to (/root) /1/prop1 Assert.IsTrue(nav.MoveToFirstChild()); + // go to (/root) /1/prop2 Assert.IsTrue(nav.MoveToNext()); + // go to (/root) /1/3 Assert.IsTrue(nav.MoveToNext()); Assert.AreEqual(NavigableNavigator.StatePosition.Element, nav.InternalState.Position); @@ -666,13 +668,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // go to /root/1/prop1 Assert.IsTrue(nav.MoveToFirstChild()); + // go to /root/1/prop2 Assert.IsTrue(nav.MoveToNext()); + // can't go to /root/1/3 Assert.IsFalse(nav.MoveToNext()); Assert.IsFalse(nav.MoveToId("3")); - //Assert.AreEqual(NavigableNavigator.StatePosition.Element, nav.InternalState.Position); - //Assert.AreEqual(3, (nav.UnderlyingObject as TestContent).Id); + + //// Assert.AreEqual(NavigableNavigator.StatePosition.Element, nav.InternalState.Position); + //// Assert.AreEqual(3, (nav.UnderlyingObject as TestContent).Id); } [TestCase(true, true)] @@ -755,7 +760,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // see http://www.onenaught.com/posts/352/xslt-performance-tip-dont-indent-output // why aren't we using an XmlWriter here? - var transform = new XslCompiledTransform(debug); var xmlReader = new XmlTextReader(new StringReader(xslt)) { @@ -774,8 +778,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml if (!native) { var source = new TestSource7(); - var nav = new NavigableNavigator(source); - //args.AddParam("currentPage", string.Empty, nav.Clone()); + ////var nav = new NavigableNavigator(source); + ////args.AddParam("currentPage", string.Empty, nav.Clone()); var x = new XmlDocument(); x.LoadXml(xml); @@ -784,14 +788,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml { // it even fails like that => macro nav. issue? new MacroNavigator.MacroParameter("nav", x.CreateNavigator()) // nav.Clone()) - } - ); + }); } else { var doc = new XmlDocument(); doc.LoadXml(""); - var nav = doc.CreateElement("nav"); + XmlElement nav = doc.CreateElement("nav"); doc.DocumentElement.AppendChild(nav); var x = new XmlDocument(); x.LoadXml(xml); @@ -807,22 +810,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml // but was NOT working (changing the order of nodes) with macro nav, debug // was due to an issue with macro nav IsSamePosition, fixed - //Debug.Print("--------"); - //Debug.Print(writer.ToString()); + ////Debug.Print("--------"); + ////Debug.Print(writer.ToString()); Assert.AreEqual(expected.Lf(), writer.ToString().Lf()); } [Test] public void WhiteSpacesAndEmptyValues() { - // "When Microsoft’s DOM builder receives a text node from the parser // that contains only white space, it is thrown away." - so if it's ONLY // spaces, it's nothing, but spaces are NOT trimmed. // For attributes, spaces are preserved even when there's only spaces. - - var doc = XmlHelper.CreateXPathDocument(@" + XPathDocument doc = XmlHelper.CreateXPathDocument(@" @@ -835,9 +836,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "); - var docNav = doc.CreateNavigator(); + XPathNavigator docNav = doc.CreateNavigator(); - Assert.AreEqual(@" + Assert.AreEqual( + @" @@ -859,7 +861,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml -".Lf(), docNav.OuterXml.Lf()); +".Lf(), + docNav.OuterXml.Lf()); docNav.MoveToRoot(); Assert.IsTrue(docNav.MoveToFirstChild()); @@ -870,18 +873,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml Assert.IsTrue(docNav.MoveToNext()); Assert.IsTrue(docNav.MoveToFirstChild()); // prop Assert.IsFalse(docNav.IsEmptyElement); - Assert.AreEqual("", docNav.Value); // contains an empty text node + Assert.AreEqual(string.Empty, docNav.Value); // contains an empty text node Assert.IsTrue(docNav.MoveToParent()); Assert.IsTrue(docNav.MoveToNext()); Assert.IsTrue(docNav.MoveToFirstChild()); // prop Assert.IsFalse(docNav.IsEmptyElement); - Assert.AreEqual("", docNav.Value); // contains an empty text node + Assert.AreEqual(string.Empty, docNav.Value); // contains an empty text node var source = new TestSource8(); var nav = new NavigableNavigator(source); // shows how whitespaces are handled by NavigableNavigator - Assert.AreEqual(@" + Assert.AreEqual( + @" @@ -902,9 +906,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - #region Navigable implementation - - class TestPropertyType : INavigableFieldType + internal class TestPropertyType : INavigableFieldType { public TestPropertyType(string name, bool isXmlContent = false, Func xmlStringConverter = null) { @@ -914,11 +916,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } public string Name { get; private set; } + public bool IsXmlContent { get; private set; } + public Func XmlStringConverter { get; private set; } } - class TestContentType : INavigableContentType + internal class TestContentType : INavigableContentType { public TestContentType(TestSourceBase source, string name, params INavigableFieldType[] properties) { @@ -928,25 +932,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } public TestSourceBase Source { get; private set; } + public string Name { get; private set; } + public INavigableFieldType[] FieldTypes { get; protected set; } } - class TestRootContentType : TestContentType + internal class TestRootContentType : TestContentType { public TestRootContentType(TestSourceBase source, params INavigableFieldType[] properties) - : base(source, "root") - { - FieldTypes = properties; - } + : base(source, "root") => FieldTypes = properties; - public TestContentType CreateType(string name, params INavigableFieldType[] properties) - { - return new TestContentType(Source, name, FieldTypes.Union(properties).ToArray()); - } + public TestContentType CreateType(string name, params INavigableFieldType[] properties) => new TestContentType(Source, name, FieldTypes.Union(properties).ToArray()); } - class TestContent : INavigableContent + internal class TestContent : INavigableContent { public TestContent(TestContentType type, int id, int parentId) { @@ -956,39 +956,56 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } private readonly TestContentType _type; + public int Id { get; private set; } + public int ParentId { get; private set; } - public INavigableContentType Type { get { return _type; } } + + public INavigableContentType Type => _type; + public IList ChildIds { get; private set; } public object Value(int id) { - var fieldType = _type.FieldTypes[id] as TestPropertyType; - if (fieldType == null) throw new Exception("Oops"); + if (!(_type.FieldTypes[id] is TestPropertyType fieldType)) + { + throw new Exception("Oops"); + } - var value = FieldValues[id]; - var isAttr = id <= _type.Source.LastAttributeIndex; + object value = FieldValues[id]; + bool isAttr = id <= _type.Source.LastAttributeIndex; // null => return null - if (value == null) return null; + if (value == null) + { + return null; + } // attribute => return string value - if (isAttr) return value.ToString(); + if (isAttr) + { + return value.ToString(); + } // has a converter => use the converter if (fieldType.XmlStringConverter != null) + { return fieldType.XmlStringConverter(value); + } // not a string => return value as a string - var s = value as string; - if (s == null) return value.ToString(); + if (!(value is string s)) + { + return value.ToString(); + } // xml content... try xml if (fieldType.IsXmlContent) { - XPathDocument doc; - if (XmlHelper.TryCreateXPathDocumentFromPropertyValue(s, out doc)) + if (XmlHelper.TryCreateXPathDocumentFromPropertyValue(s, out XPathDocument doc)) + { return doc.CreateNavigator(); + } } // return the string @@ -1007,37 +1024,31 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml public TestContent WithValues(params object[] values) { - FieldValues = values == null ? new object[] {null} : values; + FieldValues = values ?? (new object[] { null }); return this; } } - class TestRootContent : TestContent + internal class TestRootContent : TestContent { public TestRootContent(TestContentType type) : base(type, -1, -1) - { } + { + } } - abstract class TestSourceBase : INavigableSource + internal abstract class TestSourceBase : INavigableSource { protected readonly Dictionary Content = new Dictionary(); - public INavigableContent Get(int id) - { - return Content.ContainsKey(id) ? Content[id] : null; - } + public INavigableContent Get(int id) => Content.ContainsKey(id) ? Content[id] : null; public int LastAttributeIndex { get; protected set; } public INavigableContent Root { get; protected set; } } - #endregion - - #region Navigable sources - - class TestSource0 : TestSourceBase + internal class TestSource0 : TestSourceBase { public TestSource0() { @@ -1047,7 +1058,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - class TestSource1 : TestSourceBase + internal class TestSource1 : TestSourceBase { public TestSource1() { @@ -1059,15 +1070,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop2 = new TestPropertyType("prop2"); var prop3 = new TestPropertyType("prop3"); var type = new TestRootContentType(this, prop1, prop2); - var type1 = type.CreateType("type1", prop3); + TestContentType type1 = type.CreateType("type1", prop3); Content[1] = new TestContent(type1, 1, -1).WithValues("1:p1", "1:p2", "1:p3"); - Root = new TestRootContent(type).WithValues("", "").WithChildren(1); + Root = new TestRootContent(type).WithValues(string.Empty, string.Empty).WithChildren(1); } } - class TestSource2 : TestSourceBase + internal class TestSource2 : TestSourceBase { public TestSource2() { @@ -1075,7 +1086,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop1 = new TestPropertyType("prop1", true); var type = new TestRootContentType(this); - var type1 = type.CreateType("type1", prop1); + TestContentType type1 = type.CreateType("type1", prop1); const string xml = "poo"; Content[1] = new TestContent(type1, 1, 1).WithValues(xml); @@ -1084,7 +1095,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - class TestSource3 : TestSourceBase + internal class TestSource3 : TestSourceBase { public TestSource3() { @@ -1094,7 +1105,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop2 = new TestPropertyType("prop2"); var prop3 = new TestPropertyType("prop3"); var type = new TestRootContentType(this, prop1, prop2); - var type1 = type.CreateType("type1", prop3); + TestContentType type1 = type.CreateType("type1", prop3); Content[1] = new TestContent(type1, 1, 1).WithValues("1:p1", "1:p2", "1:p3").WithChildren(2); Content[2] = new TestContent(type1, 2, 1).WithValues("2:p1", "2:p2", "2:p3"); @@ -1103,7 +1114,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - class TestSource4 : TestSourceBase + internal class TestSource4 : TestSourceBase { public TestSource4() { @@ -1112,17 +1123,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop1 = new TestPropertyType("prop1", true); var prop2 = new TestPropertyType("prop2"); var type = new TestRootContentType(this); - var type1 = type.CreateType("type1", prop1, prop2); + TestContentType type1 = type.CreateType("type1", prop1, prop2); Content[1] = new TestContent(type1, 1, -1).WithValues("", "dang"); - Content[2] = new TestContent(type1, 2, -1).WithValues(null, ""); + Content[2] = new TestContent(type1, 2, -1).WithValues(null, string.Empty); Content[3] = new TestContent(type1, 3, -1).WithValues(null, null); Root = new TestRootContent(type).WithChildren(1, 2, 3); } } - class TestSource5 : TestSourceBase + internal class TestSource5 : TestSourceBase { public TestSource5() { @@ -1131,7 +1142,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop1 = new TestPropertyType("prop1"); var prop2 = new TestPropertyType("prop2"); var type = new TestRootContentType(this); - var type1 = type.CreateType("type1", prop1, prop2); + TestContentType type1 = type.CreateType("type1", prop1, prop2); Content[1] = new TestContent(type1, 1, -1).WithValues("p11", "p12").WithChildren(3, 5); Content[2] = new TestContent(type1, 2, -1).WithValues("p21", "p22").WithChildren(4, 6); @@ -1144,32 +1155,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - class TestSource6 : TestSourceBase + internal class TestSource6 : TestSourceBase { - // - // - // - // - // - // - // - // - // blah - // - // bam - // - // - // - // - // + //// + //// + //// + //// + //// + //// + //// + //// + //// blah + //// + //// bam + //// + //// + //// + //// + //// public TestSource6() { LastAttributeIndex = -1; var type = new TestRootContentType(this); - var type1 = type.CreateType("wrap", + TestContentType type1 = type.CreateType( + "wrap", new TestPropertyType("item1"), new TestPropertyType("item2"), new TestPropertyType("item2a"), @@ -1178,8 +1190,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml new TestPropertyType("item3"), new TestPropertyType("item3a"), new TestPropertyType("item4", true), - new TestPropertyType("item5", true) - ); + new TestPropertyType("item5", true)); Content[1] = new TestContent(type1, 1, -1) .WithValues( @@ -1191,14 +1202,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "blah", "\n blah\n ", "bam", - "\n " - ); + "\n "); Root = new TestRootContent(type).WithChildren(1); } } - class TestSource7 : TestSourceBase + internal class TestSource7 : TestSourceBase { public TestSource7() { @@ -1207,7 +1217,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var prop1 = new TestPropertyType("isDoc"); var prop2 = new TestPropertyType("title"); var type = new TestRootContentType(this, prop1); - var type1 = type.CreateType("node", prop1, prop2); + TestContentType type1 = type.CreateType("node", prop1, prop2); Content[1] = new TestContent(type1, 1, -1).WithValues(1, "title-1").WithChildren(3, 5); Content[2] = new TestContent(type1, 2, -1).WithValues(1, "title-2").WithChildren(4, 6); @@ -1223,7 +1233,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml } } - class TestSource8 : TestSourceBase + internal class TestSource8 : TestSourceBase { public TestSource8() { @@ -1232,15 +1242,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml var attr = new TestPropertyType("attr"); var prop = new TestPropertyType("prop"); var type = new TestRootContentType(this, attr); - var type1 = type.CreateType("item", attr, prop); + TestContentType type1 = type.CreateType("item", attr, prop); Content[1] = new TestContent(type1, 1, -1).WithValues(null, null); - Content[2] = new TestContent(type1, 2, -1).WithValues("", ""); + Content[2] = new TestContent(type1, 2, -1).WithValues(string.Empty, string.Empty); Content[3] = new TestContent(type1, 3, -1).WithValues(" ", " "); - Content[4] = new TestContent(type1, 4, -1).WithValues("", "\n"); + Content[4] = new TestContent(type1, 4, -1).WithValues(string.Empty, "\n"); Content[5] = new TestContent(type1, 5, -1).WithValues(" ooo ", " ooo "); Root = new TestRootContent(type).WithValues(null).WithChildren(1, 2, 3, 4, 5); } } - - #endregion } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs index 5afc68955d..2b6b584ca8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs @@ -1,4 +1,7 @@ -using System.Runtime.InteropServices; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Runtime.InteropServices; using System.Xml; using System.Xml.XPath; using NUnit.Framework; @@ -19,7 +22,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "); var nav = doc.CreateNavigator(); var xml = nav.OuterXml; - Assert.AreEqual(EnsureNativeLineEndings(@" + Assert.AreEqual( + EnsureNativeLineEndings(@" "), xml); @@ -35,7 +39,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "); var nav = doc.CreateNavigator(); var xml = nav.OuterXml; - Assert.AreEqual(EnsureNativeLineEndings(@" + Assert.AreEqual( + EnsureNativeLineEndings(@" "), xml); @@ -51,7 +56,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "); var nav = new RenamedRootNavigator(doc.CreateNavigator(), "test"); var xml = nav.OuterXml; - Assert.AreEqual(EnsureNativeLineEndings(@" + Assert.AreEqual( + EnsureNativeLineEndings(@" "), xml); @@ -73,7 +79,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreXml "); var nav = new RenamedRootNavigator(doc.CreateNavigator(), "test"); var xml = nav.OuterXml; - Assert.AreEqual(EnsureNativeLineEndings(@" + Assert.AreEqual( + EnsureNativeLineEndings(@" "), xml); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/DelegateExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/DelegateExtensionsTests.cs index a3e36c8ae6..cc4b716944 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/DelegateExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/DelegateExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Lucene.Net.Index; using NUnit.Framework; using Umbraco.Core; @@ -13,11 +16,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { const int maxTries = 5; var totalTries = 0; - DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) => - { - totalTries = currentTry; - return Attempt.Fail(); - }, 5, TimeSpan.FromMilliseconds(10)); + DelegateExtensions.RetryUntilSuccessOrMaxAttempts( + (currentTry) => + { + totalTries = currentTry; + return Attempt.Fail(); + }, + 5, + TimeSpan.FromMilliseconds(10)); Assert.AreEqual(maxTries, totalTries); } @@ -26,11 +32,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void Quits_On_Success_Count() { var totalTries = 0; - DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) => - { - totalTries = currentTry; - return totalTries == 2 ? Attempt.Succeed() : Attempt.Fail(); - }, 5, TimeSpan.FromMilliseconds(10)); + DelegateExtensions.RetryUntilSuccessOrMaxAttempts( + (currentTry) => + { + totalTries = currentTry; + return totalTries == 2 ? Attempt.Succeed() : Attempt.Fail(); + }, + 5, + TimeSpan.FromMilliseconds(10)); Assert.AreEqual(2, totalTries); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumExtensionsTests.cs index d5ea4d2677..bf1e35a5ac 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.Trees; @@ -14,13 +17,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, false)] public void HasFlagTest(TreeUse value, TreeUse test, bool expected) { - // the built-in Enum.HasFlag() method determines whether - // all bits from are set (other bits can be set too) - + // The built-in Enum.HasFlag() method determines whether + // all bits from are set (other bits can be set too). if (expected) + { Assert.IsTrue(value.HasFlag(test)); + } else + { Assert.IsFalse(value.HasFlag(test)); + } } [Obsolete] @@ -30,13 +36,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, false)] public void HasFlagAllTest(TreeUse value, TreeUse test, bool expected) { - // the HasFlagAll() extension method determines whether - // all bits from are set (other bits can be set too) - + // The HasFlagAll() extension method determines whether + // all bits from are set (other bits can be set too). if (expected) + { Assert.IsTrue(value.HasFlagAll(test)); + } else + { Assert.IsFalse(value.HasFlagAll(test)); + } } [TestCase(TreeUse.Dialog, TreeUse.Dialog, true)] @@ -45,13 +54,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, true)] public void HasFlagAnyTest(TreeUse value, TreeUse test, bool expected) { - // the HasFlagAny() extension method determines whether - // at least one bit from is set - + // The HasFlagAny() extension method determines whether + // at least one bit from is set. if (expected) + { Assert.IsTrue(value.HasFlagAny(test)); + } else + { Assert.IsFalse(value.HasFlagAny(test)); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumerableExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumerableExtensionsTests.cs index 32e039f26a..72a1ce25c6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumerableExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/EnumerableExtensionsTests.cs @@ -1,4 +1,8 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core; @@ -27,9 +31,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void Contains_All() { - var list1 = new[] {1, 2, 3, 4, 5, 6}; - var list2 = new[] {6, 5, 3, 2, 1, 4}; - var list3 = new[] {6, 5, 4, 3}; + var list1 = new[] { 1, 2, 3, 4, 5, 6 }; + var list2 = new[] { 6, 5, 3, 2, 1, 4 }; + var list3 = new[] { 6, 5, 4, 3 }; Assert.IsTrue(list1.ContainsAll(list2)); Assert.IsTrue(list2.ContainsAll(list1)); @@ -42,15 +46,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var hierarchy = new TestItem("1") { - Children = new List - { - new TestItem("1.1"), - new TestItem("1.2"), - new TestItem("1.3") - } - }; + Children = new List + { + new TestItem("1.1"), + new TestItem("1.2"), + new TestItem("1.3") + } + }; - var selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children); + IEnumerable selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children); Assert.AreEqual(3, selectRecursive.Count()); } @@ -111,7 +115,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core } }; - var selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children); + IEnumerable selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children); Assert.AreEqual(10, selectRecursive.Count()); } @@ -122,7 +126,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Children = Enumerable.Empty(); Name = name; } + public string Name { get; } + public IEnumerable Children { get; set; } } @@ -131,7 +137,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var integers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; - var groupsOfTwo = integers.InGroupsOf(2).ToArray(); + IEnumerable[] groupsOfTwo = integers.InGroupsOf(2).ToArray(); var flattened = groupsOfTwo.SelectMany(x => x).ToArray(); @@ -139,7 +145,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.That(flattened.Length, Is.EqualTo(integers.Length)); CollectionAssert.AreEquivalent(integers, flattened); - var groupsOfMassive = integers.InGroupsOf(100).ToArray(); + IEnumerable[] groupsOfMassive = integers.InGroupsOf(100).ToArray(); Assert.That(groupsOfMassive.Length, Is.EqualTo(1)); flattened = groupsOfMassive.SelectMany(x => x).ToArray(); Assert.That(flattened.Length, Is.EqualTo(integers.Length)); @@ -150,7 +156,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void InGroupsOf_CanRepeat() { var integers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; - var inGroupsOf = integers.InGroupsOf(2); + IEnumerable> inGroupsOf = integers.InGroupsOf(2); Assert.AreEqual(5, inGroupsOf.Count()); Assert.AreEqual(5, inGroupsOf.Count()); // again } @@ -172,7 +178,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core }; // Act - var iteratorSource = list.DistinctBy(x => x.Item2); + IEnumerable> iteratorSource = list.DistinctBy(x => x.Item2); // Assert // First check distinction diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs index 08d78af59e..cbf3d02542 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs @@ -13,6 +13,7 @@ using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Events { + [TestFixture] public class EventAggregatorTests { private const int A = 3; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/ClaimsPrincipalExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/ClaimsPrincipalExtensionsTests.cs index ad0f292fae..7b699e7b0c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/ClaimsPrincipalExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/ClaimsPrincipalExtensionsTests.cs @@ -1,11 +1,13 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using Umbraco.Extensions; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Security; +using Umbraco.Extensions; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions { @@ -15,16 +17,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions [Test] public void Get_Remaining_Ticket_Seconds() { - var backOfficeIdentity = new UmbracoBackOfficeIdentity(Constants.Security.SuperUserIdAsString, "test", "test", - Enumerable.Empty(), Enumerable.Empty(), "en-US", Guid.NewGuid().ToString(), - Enumerable.Empty(), Enumerable.Empty()); + var backOfficeIdentity = new UmbracoBackOfficeIdentity( + Constants.Security.SuperUserIdAsString, + "test", + "test", + Enumerable.Empty(), + Enumerable.Empty(), + "en-US", + Guid.NewGuid().ToString(), + Enumerable.Empty(), + Enumerable.Empty()); var principal = new ClaimsPrincipal(backOfficeIdentity); var expireSeconds = 99; var elapsedSeconds = 3; var remainingSeconds = expireSeconds - elapsedSeconds; - var now = DateTimeOffset.Now; - var then = now.AddSeconds(elapsedSeconds); + DateTimeOffset now = DateTimeOffset.Now; + DateTimeOffset then = now.AddSeconds(elapsedSeconds); var expires = now.AddSeconds(expireSeconds).ToString("o"); backOfficeIdentity.AddClaim(new Claim( diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs index e832f13671..a072a1a189 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs @@ -1,12 +1,13 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.Models; -using Umbraco.Tests.Common; -using Umbraco.Tests.Common.Builders; using Umbraco.Web.Common.AspNetCore; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/GuidUtilsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/GuidUtilsTests.cs index 62e0955d78..db16dbeb8b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/GuidUtilsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/GuidUtilsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashCodeCombinerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashCodeCombinerTests.cs index ecd2d13e78..e9b43852c3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashCodeCombinerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashCodeCombinerTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.IO; using System.Reflection; using NUnit.Framework; @@ -11,10 +14,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { private DirectoryInfo PrepareFolder() { - var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - var dir = Directory.CreateDirectory(Path.Combine(assDir.FullName, "HashCombiner", - Guid.NewGuid().ToString("N"))); - foreach (var f in dir.GetFiles()) + DirectoryInfo assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + DirectoryInfo dir = Directory.CreateDirectory( + Path.Combine(assDir.FullName, "HashCombiner", Guid.NewGuid().ToString("N"))); + foreach (FileInfo f in dir.GetFiles()) { f.Delete(); } @@ -57,7 +60,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void HashCombiner_Test_DateTime() { - var dt = DateTime.Now; + DateTime dt = DateTime.Now; var combiner1 = new HashCodeCombiner(); combiner1.AddDateTime(dt); @@ -74,19 +77,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void HashCombiner_Test_File() { - var dir = PrepareFolder(); + DirectoryInfo dir = PrepareFolder(); var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); File.Delete(file1Path); - using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) + using (StreamWriter file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) { file1.WriteLine("hello"); } var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); File.Delete(file2Path); - using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + using (StreamWriter file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) { - //even though files are the same, the dates are different + // even though files are the same, the dates are different file2.WriteLine("hello"); } @@ -110,15 +113,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void HashCombiner_Test_Folder() { - var dir = PrepareFolder(); + DirectoryInfo dir = PrepareFolder(); var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); File.Delete(file1Path); - using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) + using (StreamWriter file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) { file1.WriteLine("hello"); } - //first test the whole folder + // first test the whole folder var combiner1 = new HashCodeCombiner(); combiner1.AddFolder(dir); @@ -127,13 +130,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.AreEqual(combiner1.GetCombinedHashCode(), combiner2.GetCombinedHashCode()); - //now add a file to the folder - + // now add a file to the folder var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); File.Delete(file2Path); - using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + using (StreamWriter file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) { - //even though files are the same, the dates are different + // even though files are the same, the dates are different file2.WriteLine("hello"); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashGeneratorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashGeneratorTests.cs index 08f5b69cab..a0e75352dd 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashGeneratorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HashGeneratorTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.IO; using System.Reflection; using NUnit.Framework; @@ -11,18 +14,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { private string Generate(bool isCaseSensitive, params string[] strs) { - using (var generator = new HashGenerator()) + using var generator = new HashGenerator(); + foreach (var str in strs) { - foreach (var str in strs) + if (isCaseSensitive) { - if (isCaseSensitive) - generator.AddString(str); - else - generator.AddCaseInsensitiveString(str); + generator.AddString(str); + } + else + { + generator.AddCaseInsensitiveString(str); } - - return generator.GenerateHash(); } + + return generator.GenerateHash(); } [Test] @@ -53,10 +58,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core private DirectoryInfo PrepareFolder() { - var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - var dir = Directory.CreateDirectory(Path.Combine(assDir.FullName, "HashCombiner", - Guid.NewGuid().ToString("N"))); - foreach (var f in dir.GetFiles()) + DirectoryInfo assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + DirectoryInfo dir = Directory.CreateDirectory( + Path.Combine(assDir.FullName, "HashCombiner", Guid.NewGuid().ToString("N"))); + foreach (FileInfo f in dir.GetFiles()) { f.Delete(); } @@ -95,92 +100,85 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void HashCombiner_Test_DateTime() { - using (var combiner1 = new HashGenerator()) - using (var combiner2 = new HashGenerator()) - { - var dt = DateTime.Now; - combiner1.AddDateTime(dt); - combiner2.AddDateTime(dt); - Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); - combiner2.AddDateTime(DateTime.Now); - Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); - } + using var combiner1 = new HashGenerator(); + using var combiner2 = new HashGenerator(); + DateTime dt = DateTime.Now; + combiner1.AddDateTime(dt); + combiner2.AddDateTime(dt); + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + combiner2.AddDateTime(DateTime.Now); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); } [Test] public void HashCombiner_Test_File() { - using (var combiner1 = new HashGenerator()) - using (var combiner2 = new HashGenerator()) - using (var combiner3 = new HashGenerator()) + using var combiner1 = new HashGenerator(); + using var combiner2 = new HashGenerator(); + using var combiner3 = new HashGenerator(); + DirectoryInfo dir = PrepareFolder(); + var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); + File.Delete(file1Path); + using (StreamWriter file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) { - var dir = PrepareFolder(); - var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); - File.Delete(file1Path); - using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) - { - file1.WriteLine("hello"); - } - - var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); - File.Delete(file2Path); - using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) - { - //even though files are the same, the dates are different - file2.WriteLine("hello"); - } - - combiner1.AddFile(new FileInfo(file1Path)); - - combiner2.AddFile(new FileInfo(file1Path)); - - combiner3.AddFile(new FileInfo(file2Path)); - - Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); - Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); - - combiner2.AddFile(new FileInfo(file2Path)); - - Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + file1.WriteLine("hello"); } + + var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); + File.Delete(file2Path); + using (StreamWriter file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + { + // even though files are the same, the dates are different + file2.WriteLine("hello"); + } + + combiner1.AddFile(new FileInfo(file1Path)); + + combiner2.AddFile(new FileInfo(file1Path)); + + combiner3.AddFile(new FileInfo(file2Path)); + + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); + + combiner2.AddFile(new FileInfo(file2Path)); + + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); } [Test] public void HashCombiner_Test_Folder() { - using (var combiner1 = new HashGenerator()) - using (var combiner2 = new HashGenerator()) - using (var combiner3 = new HashGenerator()) + using var combiner1 = new HashGenerator(); + using var combiner2 = new HashGenerator(); + using var combiner3 = new HashGenerator(); + DirectoryInfo dir = PrepareFolder(); + var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); + File.Delete(file1Path); + using (StreamWriter file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) { - var dir = PrepareFolder(); - var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); - File.Delete(file1Path); - using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) - { - file1.WriteLine("hello"); - } - - //first test the whole folder - combiner1.AddFolder(dir); - - combiner2.AddFolder(dir); - - Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); - - //now add a file to the folder - - var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); - File.Delete(file2Path); - using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) - { - //even though files are the same, the dates are different - file2.WriteLine("hello"); - } - - combiner3.AddFolder(dir); - - Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); + file1.WriteLine("hello"); } + + // first test the whole folder + combiner1.AddFolder(dir); + + combiner2.AddFolder(dir); + + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + + // now add a file to the folder + var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); + File.Delete(file2Path); + using (StreamWriter file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + { + // even though files are the same, the dates are different + file2.WriteLine("hello"); + } + + combiner3.AddFolder(dir); + + Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HexEncoderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HexEncoderTests.cs index f22c3f2ac1..47d97ffaf8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/HexEncoderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/HexEncoderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Text; using NUnit.Framework; using Umbraco.Core; @@ -39,7 +42,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.AreEqual(expected, actual); } - private static readonly char[] _bytesToHexStringLookup = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + private static readonly char[] s_bytesToHexStringLookup = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; // Reference implementation taken from original extension method. private static string ToHexString(byte[] bytes, char separator, int blockSize, int blockCount) @@ -49,8 +52,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core for (var i = 0; i < bytesLength; i++) { var b = bytes[i]; - chars[p++] = _bytesToHexStringLookup[b / 0x10]; - chars[p++] = _bytesToHexStringLookup[b % 0x10]; + chars[p++] = s_bytesToHexStringLookup[b / 0x10]; + chars[p++] = s_bytesToHexStringLookup[b % 0x10]; if (count == blockCount) { continue; @@ -65,6 +68,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core size = 0; count++; } + return new string(chars, 0, chars.Length); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/AbstractFileSystemTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/AbstractFileSystemTests.cs index 3502c74494..71757c788d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/AbstractFileSystemTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/AbstractFileSystemTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -14,10 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO { protected IFileSystem _fileSystem; - protected AbstractFileSystemTests(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } + protected AbstractFileSystemTests(IFileSystem fileSystem) => _fileSystem = fileSystem; [Test] public void Can_Create_And_Delete_Files() @@ -28,7 +29,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.DeleteFile("test.txt"); - Assert.IsFalse(_fileSystem.FileExists("test.txt")); + Assert.IsFalse(_fileSystem.FileExists("test.txt")); } [Test] @@ -37,7 +38,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.AddFile("test/test.txt", CreateStream()); _fileSystem.AddFile("test/test.txt", CreateStream()); - var files = _fileSystem.GetFiles("test"); + IEnumerable files = _fileSystem.GetFiles("test"); Assert.AreEqual(1, files.Count()); @@ -50,16 +51,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO } [Test] - public void Cant_Overwrite_File() - { + public void Cant_Overwrite_File() => Assert.Throws(() => - { - _fileSystem.AddFile("test.txt", CreateStream()); - _fileSystem.AddFile("test.txt", CreateStream(), false); + { + _fileSystem.AddFile("test.txt", CreateStream()); + _fileSystem.AddFile("test.txt", CreateStream(), false); - _fileSystem.DeleteFile("test.txt"); - }); - } + _fileSystem.DeleteFile("test.txt"); + }); [Test] public void Can_Get_Files() @@ -69,7 +68,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.AddFile("test/test3.txt", CreateStream()); _fileSystem.AddFile("test/test4.bak", CreateStream()); - var files = _fileSystem.GetFiles("test"); + IEnumerable files = _fileSystem.GetFiles("test"); Assert.AreEqual(4, files.Count()); @@ -85,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO { _fileSystem.AddFile("test.txt", CreateStream("hello world")); - var stream = _fileSystem.OpenFile("test.txt"); + Stream stream = _fileSystem.OpenFile("test.txt"); var reader = new StreamReader(stream); var contents = reader.ReadToEnd(); reader.Close(); @@ -102,7 +101,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.AddFile("test/sub2/test.txt", CreateStream()); _fileSystem.AddFile("test/sub3/test.txt", CreateStream()); - var dirs = _fileSystem.GetDirectories("test"); + IEnumerable dirs = _fileSystem.GetDirectories("test"); Assert.AreEqual(3, dirs.Count()); Assert.IsTrue(_fileSystem.DirectoryExists("test/sub1")); @@ -119,8 +118,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.AddFile("test.txt", CreateStream()); - var created = _fileSystem.GetCreated("test.txt"); - var modified = _fileSystem.GetLastModified("test.txt"); + DateTimeOffset created = _fileSystem.GetCreated("test.txt"); + DateTimeOffset modified = _fileSystem.GetLastModified("test.txt"); Assert.AreEqual(DateTime.UtcNow.Year, created.Year); Assert.AreEqual(DateTime.UtcNow.Month, created.Month); @@ -142,7 +141,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO Assert.AreEqual(ConstructUrl("test.txt"), url); - _fileSystem.DeleteFile("test.txt"); + _fileSystem.DeleteFile("test.txt"); } [Test] @@ -165,7 +164,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO [Test] public void Can_Get_Size() { - var stream = CreateStream(); + Stream stream = CreateStream(); var streamLength = stream.Length; _fileSystem.AddFile("test.txt", stream); @@ -174,12 +173,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO _fileSystem.DeleteFile("test.txt"); } - #region Helper Methods - protected Stream CreateStream(string contents = null) { if (string.IsNullOrEmpty(contents)) + { contents = "test"; + } var bytes = Encoding.UTF8.GetBytes(contents); var stream = new MemoryStream(bytes); @@ -188,7 +187,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO } protected abstract string ConstructUrl(string path); - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/PhysicalFileSystemTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/PhysicalFileSystemTests.cs index 7b98d77f58..5ec7e5873e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/PhysicalFileSystemTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/IO/PhysicalFileSystemTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.IO; using System.Text; using System.Threading; @@ -16,19 +19,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO { public PhysicalFileSystemTests() : base(new PhysicalFileSystem(TestHelper.IOHelper, TestHelper.GetHostingEnvironment(), Mock.Of>(), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"), "/Media/")) - { } + { + } [SetUp] public void Setup() { - } [TearDown] public void TearDown() { var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"); - if (Directory.Exists(path) == false) return; + if (Directory.Exists(path) == false) + { + return; + } var files = Directory.GetFiles(path); foreach (var f in files) @@ -39,16 +45,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO Directory.Delete(path, true); } - protected override string ConstructUrl(string path) - { - return "/Media/" + path; - } + protected override string ConstructUrl(string path) => "/Media/" + path; private string Repeat(string pattern, int count) { var text = new StringBuilder(); for (var i = 0; i < count; i++) + { text.Append(pattern); + } + return text.ToString(); } @@ -58,7 +64,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO var basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) + { _fileSystem.AddFile("sub/f3.txt", ms); + } Assert.IsTrue(File.Exists(Path.Combine(basePath, "sub/f3.txt"))); @@ -80,14 +88,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.IO // here we initialize the PhysicalFileSystem with // rootPath = /path/to/FileSysTests // rootUrl = /Media/ - var basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"); // ensure that GetFullPath // - does return the proper full path // - does properly normalize separators // - does throw on invalid paths - // works var path = _fileSystem.GetFullPath("foo.tmp"); Assert.AreEqual(Path.Combine(basePath, @"foo.tmp"), path); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs index 92876f1b98..b3c75adfde 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs @@ -1,14 +1,16 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using Moq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core.IO; using Umbraco.Core.Manifest; using Umbraco.Core.Models; +using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Membership; using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Composing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest { @@ -18,64 +20,68 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest [Test] public void Test() { - var contentType = Mock.Of(); + IContentType contentType = Mock.Of(); Mock.Get(contentType).Setup(x => x.Alias).Returns("type1"); - var content = Mock.Of(); + IContent content = Mock.Of(); Mock.Get(content).Setup(x => x.ContentType).Returns(new SimpleContentType(contentType)); - var group1 = Mock.Of(); + IReadOnlyUserGroup group1 = Mock.Of(); Mock.Get(group1).Setup(x => x.Alias).Returns("group1"); - var group2 = Mock.Of(); + IReadOnlyUserGroup group2 = Mock.Of(); Mock.Get(group2).Setup(x => x.Alias).Returns("group2"); // no rule = ok - AssertDefinition(content, true, Array.Empty(), new [] { group1, group2 }); + AssertDefinition(content, true, Array.Empty(), new[] { group1, group2 }); // wildcards = ok - AssertDefinition(content, true, new [] { "+content/*" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "+media/*" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+content/*" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "+media/*" }, new[] { group1, group2 }); // explicitly enabling / disabling - AssertDefinition(content, true, new[] { "+content/type1" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "-content/type1" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+content/type1" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "-content/type1" }, new[] { group1, group2 }); // when there are type rules, failing to approve the type = no app - AssertDefinition(content, false, new[] { "+content/type2" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "+media/type1" }, new [] { group1, group2 }); + AssertDefinition(content, false, new[] { "+content/type2" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "+media/type1" }, new[] { group1, group2 }); // can have multiple rule, first one that matches = end - AssertDefinition(content, false, new[] { "-content/type1", "+content/*" }, new [] { group1, group2 }); - AssertDefinition(content, true, new[] { "-content/type2", "+content/*" }, new [] { group1, group2 }); - AssertDefinition(content, true, new[] { "+content/*", "-content/type1" }, new [] { group1, group2 }); + AssertDefinition(content, false, new[] { "-content/type1", "+content/*" }, new[] { group1, group2 }); + AssertDefinition(content, true, new[] { "-content/type2", "+content/*" }, new[] { group1, group2 }); + AssertDefinition(content, true, new[] { "+content/*", "-content/type1" }, new[] { group1, group2 }); // when there are role rules, failing to approve a role = no app - AssertDefinition(content, false, new[] { "+role/group33" }, new [] { group1, group2 }); + AssertDefinition(content, false, new[] { "+role/group33" }, new[] { group1, group2 }); // wildcards = ok - AssertDefinition(content, true, new[] { "+role/*" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+role/*" }, new[] { group1, group2 }); // explicitly enabling / disabling - AssertDefinition(content, true, new[] { "+role/group1" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "-role/group1" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+role/group1" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "-role/group1" }, new[] { group1, group2 }); // can have multiple rule, first one that matches = end - AssertDefinition(content, true, new[] { "+role/group1", "-role/group2" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+role/group1", "-role/group2" }, new[] { group1, group2 }); // mixed type and role rules, both are evaluated and need to match - AssertDefinition(content, true, new[] { "+role/group1", "+content/type1" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "+role/group1", "+content/type2" }, new [] { group1, group2 }); - AssertDefinition(content, false, new[] { "+role/group33", "+content/type1" }, new [] { group1, group2 }); + AssertDefinition(content, true, new[] { "+role/group1", "+content/type1" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "+role/group1", "+content/type2" }, new[] { group1, group2 }); + AssertDefinition(content, false, new[] { "+role/group33", "+content/type1" }, new[] { group1, group2 }); } private void AssertDefinition(object source, bool expected, string[] show, IReadOnlyUserGroup[] groups) { - var definition = JsonConvert.DeserializeObject("{" + (show.Length == 0 ? "" : " \"show\": [" + string.Join(",", show.Select(x => "\"" + x + "\"")) + "] ") + "}"); + ManifestContentAppDefinition definition = JsonConvert.DeserializeObject("{" + (show.Length == 0 ? string.Empty : " \"show\": [" + string.Join(",", show.Select(x => "\"" + x + "\"")) + "] ") + "}"); var factory = new ManifestContentAppFactory(definition, TestHelper.IOHelper); - var app = factory.GetContentAppFor(source, groups); + ContentApp app = factory.GetContentAppFor(source, groups); if (expected) + { Assert.IsNotNull(app); + } else + { Assert.IsNull(app); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs index e1a34e38a3..ccab1885bb 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs @@ -1,21 +1,24 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; -using Moq; using System.Text; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using NUnit.Framework; +using Moq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Umbraco.Core.Dashboards; +using Umbraco.Core.IO; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; -using Umbraco.Core.Services; -using Umbraco.Core.Dashboards; -using Umbraco.Core.IO; using Umbraco.Core.Serialization; +using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -37,14 +40,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest new DelimitedValueValidator(), }; _ioHelper = TestHelper.IOHelper; - var loggerFactory = NullLoggerFactory.Instance; + NullLoggerFactory loggerFactory = NullLoggerFactory.Instance; _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), new ManifestFilterCollection(Array.Empty()), loggerFactory.CreateLogger(), loggerFactory, _ioHelper, TestHelper.GetHostingEnvironment(), Mock.Of(), Mock.Of(), new JsonNetSerializer(), Mock.Of(), Mock.Of()); } [Test] public void DelimitedValueValidator() { - const string json = @"{'propertyEditors': [ { alias: 'Test.Test2', @@ -64,7 +66,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(1, manifest.ParameterEditors.Length); Assert.AreEqual(1, manifest.ParameterEditors[0].GetValueEditor().Validators.Count); @@ -80,7 +82,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest [Test] public void CanParseComments() { - const string json1 = @" // this is a single-line comment { @@ -92,7 +93,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Manifest } "; - var jobject = (JObject) JsonConvert.DeserializeObject(json1); + var jobject = (JObject)JsonConvert.DeserializeObject(json1); Assert.AreEqual("2", jobject.Property("x").Value.ToString()); Assert.AreEqual("3", jobject.Property("y").Value.ToString()); Assert.AreEqual("4", jobject.Property("z").Value.ToString()); @@ -115,8 +116,8 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 [Test] public void CanParseManifest_ScriptsAndStylesheets() { - var json = "{}"; - var manifest = _parser.ParseManifest(json); + string json = "{}"; + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(0, manifest.Scripts.Length); json = "{javascript: []}"; @@ -139,7 +140,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.Throws(() => _parser.ParseManifest(json)); json = "{}"; - manifest = _parser.ParseManifest(json); + manifest = _parser.ParseManifest(json); Assert.AreEqual(0, manifest.Stylesheets.Length); json = "{css: []}"; @@ -154,8 +155,6 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Stylesheets.Length); - - json = "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js'], css: ['~/stylesheet.css', '~/random-long-name.css']}"; manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Scripts.Length); @@ -212,10 +211,10 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.PropertyEditors.Length); - var editor = manifest.PropertyEditors[1]; + IDataEditor editor = manifest.PropertyEditors[1]; Assert.IsTrue((editor.Type & EditorType.MacroParameter) > 0); editor = manifest.PropertyEditors[0]; @@ -223,18 +222,18 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("Test 1", editor.Name); Assert.IsFalse((editor.Type & EditorType.MacroParameter) > 0); - var valueEditor = editor.GetValueEditor(); + IDataValueEditor valueEditor = editor.GetValueEditor(); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html"), valueEditor.View); Assert.AreEqual("int", valueEditor.ValueType); Assert.IsTrue(valueEditor.HideLabel); // these two don't make much sense here - // valueEditor.RegexValidator; - // valueEditor.RequiredValidator; + //// valueEditor.RegexValidator; + //// valueEditor.RequiredValidator; - var validators = valueEditor.Validators; + List validators = valueEditor.Validators; Assert.AreEqual(2, validators.Count); - var validator = validators[0]; + IValueValidator validator = validators[0]; var v1 = validator as RequiredValidator; Assert.IsNotNull(v1); Assert.AreEqual("Required", v1.ValidationName); @@ -245,19 +244,19 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("\\d*", v2.Configuration); // this is not part of the manifest - var preValues = editor.GetConfigurationEditor().DefaultConfiguration; + IDictionary preValues = editor.GetConfigurationEditor().DefaultConfiguration; Assert.IsEmpty(preValues); - var preValueEditor = editor.GetConfigurationEditor(); + IConfigurationEditor preValueEditor = editor.GetConfigurationEditor(); Assert.IsNotNull(preValueEditor); Assert.IsNotNull(preValueEditor.Fields); Assert.AreEqual(2, preValueEditor.Fields.Count); - var f = preValueEditor.Fields[0]; + ConfigurationField f = preValueEditor.Fields[0]; Assert.AreEqual("key1", f.Key); Assert.AreEqual("Some config 1", f.Name); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html"), f.View); - var fvalidators = f.Validators; + List fvalidators = f.Validators; Assert.IsNotNull(fvalidators); Assert.AreEqual(1, fvalidators.Count); var fv = fvalidators[0] as RequiredValidator; @@ -294,27 +293,27 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(3, manifest.ParameterEditors.Length); Assert.IsTrue(manifest.ParameterEditors.All(x => (x.Type & EditorType.MacroParameter) > 0)); - var editor = manifest.ParameterEditors[1]; + IDataEditor editor = manifest.ParameterEditors[1]; Assert.AreEqual("parameter2", editor.Alias); Assert.AreEqual("Another parameter", editor.Name); - var config = editor.DefaultConfiguration; + IDictionary config = editor.DefaultConfiguration; Assert.AreEqual(1, config.Count); Assert.IsTrue(config.ContainsKey("key1")); Assert.AreEqual("some config val", config["key1"]); - var valueEditor = editor.GetValueEditor(); + IDataValueEditor valueEditor = editor.GetValueEditor(); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html"), valueEditor.View); editor = manifest.ParameterEditors[2]; Assert.Throws(() => { - var _ = editor.GetValueEditor(); + IDataValueEditor valueEditor = editor.GetValueEditor(); }); } @@ -353,20 +352,20 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 } ] }"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.GridEditors.Length); - var editor = manifest.GridEditors[0]; + GridEditor editor = manifest.GridEditors[0]; Assert.AreEqual("small-hero", editor.Alias); Assert.AreEqual("Small Hero", editor.Name); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPlugin/small-hero/editortemplate.html"), editor.View); Assert.AreEqual(_ioHelper.ResolveUrl("/Views/Partials/Grid/Editors/SmallHero.cshtml"), editor.Render); Assert.AreEqual("icon-presentation", editor.Icon); - var config = editor.Config; + IDictionary config = editor.Config; Assert.AreEqual(2, config.Count); Assert.IsTrue(config.ContainsKey("image")); - var c = config["image"]; + object c = config["image"]; Assert.IsInstanceOf(c); // FIXME: is this what we want? Assert.IsTrue(config.ContainsKey("link")); c = config["link"]; @@ -394,11 +393,11 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.ContentApps.Length); Assert.IsInstanceOf(manifest.ContentApps[0]); - var app0 = (ManifestContentAppDefinition) manifest.ContentApps[0]; + var app0 = (ManifestContentAppDefinition)manifest.ContentApps[0]; Assert.AreEqual("myPackageApp1", app0.Alias); Assert.AreEqual("My App1", app0.Name); Assert.AreEqual("icon-foo", app0.Icon); @@ -431,11 +430,11 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Dashboards.Length); Assert.IsInstanceOf(manifest.Dashboards[0]); - var db0 = manifest.Dashboards[0]; + ManifestDashboard db0 = manifest.Dashboards[0]; Assert.AreEqual("something", db0.Alias); Assert.AreEqual(100, db0.Weight); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/one.html"), db0.View); @@ -448,7 +447,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("foo", db0.AccessRules[1].Value); Assert.IsInstanceOf(manifest.Dashboards[1]); - var db1 = manifest.Dashboards[1]; + ManifestDashboard db1 = manifest.Dashboards[1]; Assert.AreEqual("something.else", db1.Alias); Assert.AreEqual(-1, db1.Weight); Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/two.html"), db1.View); @@ -464,7 +463,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 { ""alias"": ""hello"", ""name"": ""World"" } ]}"; - var manifest = _parser.ParseManifest(json); + PackageManifest manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Sections.Length); Assert.AreEqual("content", manifest.Sections[0].Alias); Assert.AreEqual("hello", manifest.Sections[1].Alias); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/Item.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/Item.cs index 8593d01946..192daee0bf 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/Item.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/Item.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -16,13 +19,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections private int _id; private Guid _key; - protected Item() - { - _propertyChangedInfo = new Dictionary(); - } + protected Item() => _propertyChangedInfo = new Dictionary(); /// - /// Integer Id + /// Gets or sets the integer Id /// [DataMember] public int Id @@ -36,7 +36,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections } /// - /// Guid based Id + /// Gets or sets the Guid based Id /// /// The key is currectly used to store the Unique Id from the /// umbracoNode table, which many of the entities are based on. @@ -66,8 +66,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections public DateTime? DeleteDate { get; set; } /// - /// Gets or sets the WasCancelled flag, which is used to track - /// whether some action against an entity was cancelled through some event. + /// Gets or sets a value indicating whether some action against an entity was cancelled through some event. /// This only exists so we have a way to check if an event was cancelled through /// the new api, which also needs to take effect in the legacy api. /// @@ -86,7 +85,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections protected virtual void OnPropertyChanged(PropertyInfo propertyInfo) { if (_withChanges == false) + { return; + } _propertyChangedInfo[propertyInfo.Name] = true; @@ -96,7 +97,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections public virtual void ResetIdentity() { _hasIdentity = false; - _id = default(int); + _id = default; } /// @@ -111,15 +112,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections /// /// Method to call on entity saved/updated /// - internal virtual void UpdatingEntity() - { - UpdateDate = DateTime.Now; - } + internal virtual void UpdatingEntity() => UpdateDate = DateTime.Now; /// /// Tracks the properties that have changed /// - //private readonly IDictionary _propertyChangedInfo = new Dictionary(); private readonly IDictionary _propertyChangedInfo; /// @@ -127,24 +124,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections /// /// Name of the property to check /// True if Property is dirty, otherwise False - public virtual bool IsPropertyDirty(string propertyName) - { - return _propertyChangedInfo.Any(x => x.Key == propertyName); - } + public virtual bool IsPropertyDirty(string propertyName) => _propertyChangedInfo.Any(x => x.Key == propertyName); - public virtual IEnumerable GetDirtyProperties() - { - return _propertyChangedInfo.Keys; - } + public virtual IEnumerable GetDirtyProperties() => _propertyChangedInfo.Keys; /// /// Indicates whether the current entity is dirty. /// /// True if entity is dirty, otherwise False - public virtual bool IsDirty() - { - return _propertyChangedInfo.Any(); - } + public virtual bool IsDirty() => _propertyChangedInfo.Any(); /// /// Resets dirty properties by clearing the dictionary used to track changes. @@ -153,29 +141,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections /// Please note that resetting the dirty properties could potentially /// obstruct the saving of a new or updated entity. /// - public virtual void ResetDirtyProperties() - { - _propertyChangedInfo.Clear(); - } + public virtual void ResetDirtyProperties() => _propertyChangedInfo.Clear(); /// /// Disables change tracking. /// - public void DisableChangeTracking() - { - _withChanges = false; - } + public void DisableChangeTracking() => _withChanges = false; /// /// Enables change tracking. /// - public void EnableChangeTracking() - { - _withChanges = true; - } + public void EnableChangeTracking() => _withChanges = true; /// - /// Indicates whether the current entity has an identity, eg. Id. + /// Gets or sets a value indicating whether the current entity has an identity, eg. Id. /// public virtual bool HasIdentity { @@ -183,15 +162,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections protected set => _hasIdentity = value; } - public static bool operator ==(Item left, Item right) - { - return ReferenceEquals(left, right); - } + public static bool operator ==(Item left, Item right) => ReferenceEquals(left, right); - public static bool operator !=(Item left, Item right) - { - return !(left == right); - } + public static bool operator !=(Item left, Item right) => !(left == right); /*public virtual bool SameIdentityAs(IEntity other) { @@ -249,9 +222,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections return _hash.Value; }*/ - public object DeepClone() - { - return this.MemberwiseClone(); - } + public object DeepClone() => this.MemberwiseClone(); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/OrderItem.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/OrderItem.cs index 60c57dd1e5..91ccc3cac8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/OrderItem.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/OrderItem.cs @@ -1,7 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections -{ +{ public class OrderItem : Item { public readonly int PartNumber; @@ -10,8 +13,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections private int _quantity = 0; - public OrderItem(int partNumber, string description, - int quantity, double unitPrice) + public OrderItem(int partNumber, string description, int quantity, double unitPrice) { PartNumber = partNumber; Description = description; @@ -21,22 +23,26 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections public int Quantity { - get { return _quantity; } + get => _quantity; + set { if (value < 0) + { throw new ArgumentException("Quantity cannot be negative."); + } _quantity = value; } } - public override string ToString() - { - return string.Format( + public override string ToString() => + string.Format( "{0,9} {1,6} {2,-12} at {3,8:#,###.00} = {4,10:###,###.00}", - PartNumber, _quantity, Description, UnitPrice, + PartNumber, + _quantity, + Description, + UnitPrice, UnitPrice * _quantity); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/PropertyCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/PropertyCollectionTests.cs index 6c76cc29a2..643ad1f64e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/PropertyCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/PropertyCollectionTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/SimpleOrder.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/SimpleOrder.cs index d8c47f45f4..86022f094b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/SimpleOrder.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/Collections/SimpleOrder.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; @@ -10,31 +13,32 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections // The parameterless constructor of the base class creates a // KeyedCollection with an internal dictionary. For this code // example, no other constructors are exposed. - // - public SimpleOrder() : base() { } - - public SimpleOrder(IEnumerable properties) + public SimpleOrder() + : base() { - Reset(properties); } + public SimpleOrder(IEnumerable properties) => Reset(properties); + // This is the only method that absolutely must be overridden, // because without it the KeyedCollection cannot extract the // keys from the items. The input parameter type is the // second generic type argument, in this case OrderItem, and // the return value type is the first generic type argument, // in this case int. - // - protected override int GetKeyForItem(OrderItem item) - { + protected override int GetKeyForItem(OrderItem item) => + // In this example, the key is the part number. - return item.PartNumber; - } + item.PartNumber; internal void Reset(IEnumerable properties) { Clear(); - foreach (var property in properties) Add(property); + foreach (OrderItem property in properties) + { + Add(property); + } + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } @@ -46,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections protected override void RemoveItem(int index) { - var removed = this[index]; + OrderItem removed = this[index]; base.RemoveItem(index); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); } @@ -63,16 +67,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models.Collections OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } - public new bool Contains(int partNumber) - { - return this.Any(x => x.PartNumber == partNumber); - } + public new bool Contains(int partNumber) => this.Any(x => x.PartNumber == partNumber); public event NotifyCollectionChangedEventHandler CollectionChanged; - protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args) - { - CollectionChanged?.Invoke(this, args); - } + protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args) => CollectionChanged?.Invoke(this, args); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs index eb46a2b919..556e855c83 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using Moq; using NUnit.Framework; @@ -15,11 +18,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_Reset_Clears_SavedPublishedState() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.PublishedState = PublishedState.Publishing; Assert.IsFalse(content.Published); @@ -31,15 +34,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_OnlyIfActuallyChanged_Content() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // if you assign a content property with its value it is not dirty // if you assign it with another value then back, it is dirty - content.ResetDirtyProperties(false); Assert.IsFalse(content.IsPropertyDirty("Published")); content.Published = true; @@ -56,16 +58,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_OnlyIfActuallyChanged_User() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - var prop = content.Properties.First(); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + IProperty prop = content.Properties.First(); // if you assign a user property with its value it is not dirty // if you assign it with another value then back, it is dirty - prop.SetValue("A"); content.ResetDirtyProperties(false); Assert.IsFalse(prop.IsDirty()); @@ -83,15 +84,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_UpdateDate() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - var prop = content.Properties.First(); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + IProperty prop = content.Properties.First(); content.ResetDirtyProperties(false); - var d = content.UpdateDate; + DateTime d = content.UpdateDate; prop.SetValue("A"); Assert.IsTrue(content.IsAnyUserPropertyDirty()); Assert.IsFalse(content.IsEntityDirty()); @@ -109,11 +110,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_WasDirty_ContentProperty() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); Assert.IsFalse(content.WasDirty()); @@ -139,11 +140,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_WasDirty_ContentSortOrder() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); Assert.IsFalse(content.WasDirty()); @@ -169,12 +170,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void DirtyProperty_WasDirty_UserProperty() { - var contentTypeService = Mock.Of(); - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + IContentTypeService contentTypeService = Mock.Of(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - var prop = content.Properties.First(); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + IProperty prop = content.Properties.First(); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); Assert.IsFalse(content.WasDirty()); @@ -189,13 +190,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models prop.SetValue("b"); content.ResetDirtyProperties(true); // what PersistUpdatedItem does Assert.IsFalse(content.IsDirty()); - //Assert.IsFalse(content.WasDirty()); // not impacted by user properties + //// Assert.IsFalse(content.WasDirty()); // not impacted by user properties Assert.IsTrue(content.WasDirty()); // now it is! prop.SetValue("a"); prop.SetValue("b"); content.ResetDirtyProperties(); // what PersistUpdatedItem does Assert.IsFalse(content.IsDirty()); - //Assert.IsFalse(content.WasDirty()); // not impacted by user properties + //// Assert.IsFalse(content.WasDirty()); // not impacted by user properties Assert.IsTrue(content.WasDirty()); // now it is! } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs index 36bf5418b3..bdf1591301 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; @@ -11,7 +15,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Release_Date_Less_Than_Expire_Date() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); Assert.IsFalse(schedule.Add(now, now)); } @@ -19,7 +23,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Cannot_Add_Duplicate_Dates_Invariant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, null); Assert.Throws(() => schedule.Add(null, now)); @@ -28,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Cannot_Add_Duplicate_Dates_Variant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, null); schedule.Add("en-US", now, null); @@ -39,10 +43,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Remove_Invariant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, null); - var invariantSched = schedule.GetSchedule(string.Empty); + IEnumerable invariantSched = schedule.GetSchedule(string.Empty); schedule.Remove(invariantSched.First()); Assert.AreEqual(0, schedule.FullSchedule.Count()); } @@ -50,15 +54,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Remove_Variant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, null); schedule.Add("en-US", now, null); - var invariantSched = schedule.GetSchedule(string.Empty); + IEnumerable invariantSched = schedule.GetSchedule(string.Empty); schedule.Remove(invariantSched.First()); Assert.AreEqual(0, schedule.GetSchedule(string.Empty).Count()); Assert.AreEqual(1, schedule.FullSchedule.Count()); - var variantSched = schedule.GetSchedule("en-US"); + IEnumerable variantSched = schedule.GetSchedule("en-US"); schedule.Remove(variantSched.First()); Assert.AreEqual(0, schedule.GetSchedule("en-US").Count()); Assert.AreEqual(0, schedule.FullSchedule.Count()); @@ -67,7 +71,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Clear_Start_Invariant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, now.AddDays(1)); @@ -81,7 +85,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Clear_End_Variant() { - var now = DateTime.Now; + DateTime now = DateTime.Now; var schedule = new ContentScheduleCollection(); schedule.Add(now, now.AddDays(1)); schedule.Add("en-US", now, now.AddDays(1)); @@ -102,6 +106,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(1, schedule.GetSchedule("en-US", ContentScheduleAction.Release).Count()); Assert.AreEqual(2, schedule.FullSchedule.Count()); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs index 6b226e7e59..d59dafcda0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -25,18 +28,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [TestFixture] public class ContentTests { - private IContentTypeService _contentTypeService = Mock.Of(); + private readonly IContentTypeService _contentTypeService = Mock.Of(); [Test] public void Variant_Culture_Names_Track_Dirty_Changes() { - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .WithContentVariation(ContentVariation.Culture) .Build(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = new ContentBuilder() + Content content = new ContentBuilder() .WithId(1) .WithVersionId(1) .WithName("content") @@ -45,33 +48,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models const string langFr = "fr-FR"; - Assert.IsFalse(content.IsPropertyDirty("CultureInfos")); //hasn't been changed + Assert.IsFalse(content.IsPropertyDirty("CultureInfos")); // hasn't been changed - Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date + Thread.Sleep(500); // The "Date" wont be dirty if the test runs too fast since it will be the same date content.SetCultureName("name-fr", langFr); - Assert.IsTrue(content.IsPropertyDirty("CultureInfos")); //now it will be changed since the collection has changed - var frCultureName = content.CultureInfos[langFr]; + Assert.IsTrue(content.IsPropertyDirty("CultureInfos")); // now it will be changed since the collection has changed + ContentCultureInfos frCultureName = content.CultureInfos[langFr]; Assert.IsTrue(frCultureName.IsPropertyDirty("Date")); content.ResetDirtyProperties(); - Assert.IsFalse(content.IsPropertyDirty("CultureInfos")); //it's been reset + Assert.IsFalse(content.IsPropertyDirty("CultureInfos")); // it's been reset Assert.IsTrue(content.WasPropertyDirty("CultureInfos")); - Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date + Thread.Sleep(500); // The "Date" wont be dirty if the test runs too fast since it will be the same date content.SetCultureName("name-fr", langFr); Assert.IsTrue(frCultureName.IsPropertyDirty("Date")); - Assert.IsTrue(content.IsPropertyDirty("CultureInfos")); //it's true now since we've updated a name + Assert.IsTrue(content.IsPropertyDirty("CultureInfos")); // it's true now since we've updated a name } [Test] public void Variant_Published_Culture_Names_Track_Dirty_Changes() { - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .WithContentVariation(ContentVariation.Culture) .Build(); - var content = new ContentBuilder() + Content content = new ContentBuilder() .WithId(1) .WithVersionId(1) .WithName("content") @@ -82,38 +85,38 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models content.ChangeContentType(contentType); - Assert.IsFalse(content.IsPropertyDirty("PublishCultureInfos")); //hasn't been changed + Assert.IsFalse(content.IsPropertyDirty("PublishCultureInfos")); // hasn't been changed - Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date + Thread.Sleep(500); // The "Date" wont be dirty if the test runs too fast since it will be the same date content.SetCultureName("name-fr", langFr); - content.PublishCulture(CultureImpact.Explicit(langFr, false)); //we've set the name, now we're publishing it - Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); //now it will be changed since the collection has changed - var frCultureName = content.PublishCultureInfos[langFr]; + content.PublishCulture(CultureImpact.Explicit(langFr, false)); // we've set the name, now we're publishing it + Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); // now it will be changed since the collection has changed + ContentCultureInfos frCultureName = content.PublishCultureInfos[langFr]; Assert.IsTrue(frCultureName.IsPropertyDirty("Date")); content.ResetDirtyProperties(); - Assert.IsFalse(content.IsPropertyDirty("PublishCultureInfos")); //it's been reset + Assert.IsFalse(content.IsPropertyDirty("PublishCultureInfos")); // it's been reset Assert.IsTrue(content.WasPropertyDirty("PublishCultureInfos")); - Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date + Thread.Sleep(500); // The "Date" wont be dirty if the test runs too fast since it will be the same date content.SetCultureName("name-fr", langFr); - content.PublishCulture(CultureImpact.Explicit(langFr, false)); //we've set the name, now we're publishing it + content.PublishCulture(CultureImpact.Explicit(langFr, false)); // we've set the name, now we're publishing it Assert.IsTrue(frCultureName.IsPropertyDirty("Date")); - Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); //it's true now since we've updated a name + Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); // it's true now since we've updated a name } [Test] public void Get_Non_Grouped_Properties() { - var contentType = ContentTypeBuilder.CreateSimpleContentType(); + ContentType contentType = ContentTypeBuilder.CreateSimpleContentType(); // Add non-grouped properties - var pt1 = new PropertyTypeBuilder() + PropertyType pt1 = new PropertyTypeBuilder() .WithAlias("nonGrouped1") .WithName("Non Grouped 1") .Build(); - var pt2 = new PropertyTypeBuilder() + PropertyType pt2 = new PropertyTypeBuilder() .WithAlias("nonGrouped2") .WithName("Non Grouped 2") .Build(); @@ -124,9 +127,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models contentType.ResetDirtyProperties(false); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateSimpleContent(contentType); + Content content = ContentBuilder.CreateSimpleContent(contentType); - var nonGrouped = content.GetNonGroupedProperties(); + IEnumerable nonGrouped = content.GetNonGroupedProperties(); Assert.AreEqual(2, nonGrouped.Count()); Assert.AreEqual(5, content.Properties.Count()); @@ -135,15 +138,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void All_Dirty_Properties_Get_Reset() { - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); - foreach (var prop in content.Properties) + foreach (IProperty prop in content.Properties) { Assert.IsFalse(prop.IsDirty()); } @@ -153,10 +156,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Verify_Mocked_Content() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -168,10 +171,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_Property_Value() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.Properties["title"].SetValue("This is the new title"); @@ -186,10 +189,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Set_Property_Value_As_String() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.SetValue("title", "This is the new title"); @@ -204,15 +207,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Clone_Content_With_Reset_Identity() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.Id = 10; content.Key = new Guid("29181B97-CB8F-403F-86DE-5FEB497F4800"); // Act - var clone = content.DeepCloneWithResetIdentities(); + IContent clone = content.DeepCloneWithResetIdentities(); // Assert Assert.AreNotSame(clone, content); @@ -225,7 +228,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private static IProfilingLogger GetTestProfilingLogger() { - var logger = NullLoggerFactory.Instance.CreateLogger(); + ILogger logger = NullLoggerFactory.Instance.CreateLogger(); var profiler = new TestProfiler(); return new ProfilingLogger(logger, profiler); } @@ -235,14 +238,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Deep_Clone_Perf_Test() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - var i = 200; - foreach (var property in content.Properties) + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + int i = 200; + foreach (IProperty property in content.Properties) { property.Id = ++i; } + content.Id = 10; content.CreateDate = DateTime.Now; content.CreatorId = 22; @@ -250,7 +254,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models content.Level = 3; content.Path = "-1,4,10"; content.ContentSchedule.Add(DateTime.Now, DateTime.Now.AddDays(1)); - //content.ChangePublishedState(PublishedState.Published); + //// content.ChangePublishedState(PublishedState.Published); content.SortOrder = 5; content.TemplateId = 88; content.Trashed = false; @@ -260,13 +264,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models var runtimeCache = new ObjectCacheAppCache(); runtimeCache.Insert(content.Id.ToString(CultureInfo.InvariantCulture), () => content); - var proflog = GetTestProfilingLogger(); + IProfilingLogger proflog = GetTestProfilingLogger(); using (proflog.DebugDuration("STARTING PERF TEST WITH RUNTIME CACHE")) { for (int j = 0; j < 1000; j++) { - var clone = runtimeCache.Get(content.Id.ToString(CultureInfo.InvariantCulture)); + object clone = runtimeCache.Get(content.Id.ToString(CultureInfo.InvariantCulture)); } } @@ -283,12 +287,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Deep_Clone() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); content.SetCultureName("World", "es-ES"); @@ -297,11 +301,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // should not try to clone something that's not Published or Unpublished // (and in fact it will not work) // but we cannot directly set the state to Published - hence this trick - //content.ChangePublishedState(PublishedState.Publishing); + // content.ChangePublishedState(PublishedState.Publishing); content.ResetDirtyProperties(false); // => .Published - var i = 200; - foreach (var property in content.Properties) + int i = 200; + foreach (IProperty property in content.Properties) { property.Id = ++i; } @@ -347,7 +351,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.WriterId, content.WriterId); Assert.AreNotSame(clone.Properties, content.Properties); Assert.AreEqual(clone.Properties.Count(), content.Properties.Count()); - for (var index = 0; index < content.Properties.Count; index++) + for (int index = 0; index < content.Properties.Count; index++) { Assert.AreNotSame(clone.Properties[index], content.Properties[index]); Assert.AreEqual(clone.Properties[index], content.Properties[index]); @@ -355,7 +359,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.PublishCultureInfos, content.PublishCultureInfos); Assert.AreEqual(clone.PublishCultureInfos.Count, content.PublishCultureInfos.Count); - foreach (var key in content.PublishCultureInfos.Keys) + foreach (string key in content.PublishCultureInfos.Keys) { Assert.AreNotSame(clone.PublishCultureInfos[key], content.PublishCultureInfos[key]); Assert.AreEqual(clone.PublishCultureInfos[key], content.PublishCultureInfos[key]); @@ -363,28 +367,27 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.CultureInfos, content.CultureInfos); Assert.AreEqual(clone.CultureInfos.Count, content.CultureInfos.Count); - foreach (var key in content.CultureInfos.Keys) + foreach (string key in content.CultureInfos.Keys) { Assert.AreNotSame(clone.CultureInfos[key], content.CultureInfos[key]); Assert.AreEqual(clone.CultureInfos[key], content.CultureInfos[key]); } // This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + System.Reflection.PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (System.Reflection.PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(content, null)); } // Need to ensure the event handlers are wired - var asDirty = (ICanBeDirty)clone; Assert.IsFalse(asDirty.IsPropertyDirty("Properties")); - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("blah") .Build(); - var newProperty = new PropertyBuilder() + IProperty newProperty = new PropertyBuilder() .WithId(1) .WithPropertyType(propertyType) .Build(); @@ -398,19 +401,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Remember_Dirty_Properties() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); content.SetCultureName("World", "es-ES"); content.PublishCulture(CultureImpact.All); - var i = 200; - foreach (var property in content.Properties) + int i = 200; + foreach (IProperty property in content.Properties) { property.Id = ++i; } @@ -445,14 +448,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.IsTrue(content.WasPropertyDirty(nameof(Content.Trashed))); Assert.IsTrue(content.WasPropertyDirty(nameof(Content.UpdateDate))); Assert.IsTrue(content.WasPropertyDirty(nameof(Content.WriterId))); - foreach (var prop in content.Properties) + foreach (IProperty prop in content.Properties) { Assert.IsTrue(prop.WasDirty()); Assert.IsTrue(prop.WasPropertyDirty("Id")); } Assert.IsTrue(content.WasPropertyDirty("CultureInfos")); - foreach (var culture in content.CultureInfos) + foreach (ContentCultureInfos culture in content.CultureInfos) { Assert.IsTrue(culture.WasDirty()); Assert.IsTrue(culture.WasPropertyDirty("Name")); @@ -460,7 +463,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models } Assert.IsTrue(content.WasPropertyDirty("PublishCultureInfos")); - foreach (var culture in content.PublishCultureInfos) + foreach (ContentCultureInfos culture in content.PublishCultureInfos) { Assert.IsTrue(culture.WasDirty()); Assert.IsTrue(culture.WasPropertyDirty("Name")); @@ -472,13 +475,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Serialize_Without_Error() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - var i = 200; - foreach (var property in content.Properties) + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + int i = 200; + foreach (IProperty property in content.Properties) { property.Id = ++i; } @@ -490,14 +493,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models content.Level = 3; content.Path = "-1,4,10"; content.ContentSchedule.Add(DateTime.Now, DateTime.Now.AddDays(1)); - //content.ChangePublishedState(PublishedState.Publishing); + //// content.ChangePublishedState(PublishedState.Publishing); content.SortOrder = 5; content.TemplateId = 88; content.Trashed = false; content.UpdateDate = DateTime.Now; content.WriterId = 23; - var json = JsonConvert.SerializeObject(content); + string json = JsonConvert.SerializeObject(content); Debug.Print(json); } @@ -526,10 +529,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_Property_Value_Through_Anonymous_Object() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.PropertyValues(new { title = "This is the new title" }); @@ -546,10 +549,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Verify_Dirty_Property_On_Content() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ResetDirtyProperties(); @@ -564,7 +567,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Add_PropertyGroup_On_ContentType() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act contentType.PropertyGroups.Add(new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 }); @@ -577,7 +580,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Remove_PropertyGroup_From_ContentType() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act @@ -585,17 +588,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // Assert Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(1)); - //Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True); + //// Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True); } [Test] public void Can_Add_PropertyType_To_Group_On_ContentType() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("subtitle") .WithName("Subtitle") .Build(); @@ -609,13 +612,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Add_New_Property_To_New_PropertyType() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("subtitle") .WithName("Subtitle") .Build(); @@ -633,13 +636,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Add_New_Property_To_New_PropertyType_In_New_PropertyGroup() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("subtitle") .WithName("Subtitle") .Build(); @@ -660,13 +663,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Update_PropertyType_Through_Content_Properties() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - note that the PropertyType's properties like SortOrder is not updated through the Content object - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("title") .WithName("Title") .Build(); @@ -682,18 +685,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_ContentType_On_Content() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); // Assert Assert.That(content.Properties.Contains("author"), Is.True); - //Note: There was 4 properties, after changing ContentType 1 has been added (no properties are deleted) + + // Note: There were 4 properties, after changing ContentType 1 has been added (no properties are deleted). Assert.That(content.Properties.Count, Is.EqualTo(5)); } @@ -701,11 +705,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_ContentType_On_Content_And_Set_Property_Value() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); @@ -720,11 +724,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_ContentType_On_Content_And_Still_Get_Old_Properties() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); @@ -742,29 +746,30 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Change_ContentType_On_Content_And_Clear_Old_PropertyTypes() { throw new NotImplementedException(); - //Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - //// Arrange - //var contentType = ContentTypeBuilder.CreateTextPageContentType(); - //var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); - //var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + //// Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - //// Act - //content.ChangeContentType(simpleContentType, true); + ////// Arrange + //// var contentType = ContentTypeBuilder.CreateTextPageContentType(); + //// var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + //// var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); - //// Assert - //Assert.That(content.Properties.Contains("author"), Is.True); - //Assert.That(content.Properties.Contains("keywords"), Is.False); - //Assert.That(content.Properties.Contains("description"), Is.False); + ////// Act + //// content.ChangeContentType(simpleContentType, true); + + ////// Assert + //// Assert.That(content.Properties.Contains("author"), Is.True); + //// Assert.That(content.Properties.Contains("keywords"), Is.False); + //// Assert.That(content.Properties.Contains("description"), Is.False); } [Test] public void Can_Verify_Content_Is_Published() { - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(); content.PublishedState = PublishedState.Publishing; @@ -797,7 +802,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Adding_PropertyGroup_To_ContentType_Results_In_Dirty_Entity() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act @@ -807,19 +812,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // Assert Assert.That(contentType.IsDirty(), Is.True); Assert.That(contentType.PropertyGroups.Any(x => x.Name == "Test Group"), Is.True); - //Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True); + //// Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True); } [Test] public void After_Committing_Changes_Was_Dirty_Is_True() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); - contentType.ResetDirtyProperties(); //reset + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); + contentType.ResetDirtyProperties(); // reset // Act contentType.Alias = "newAlias"; - contentType.ResetDirtyProperties(); //this would be like committing the entity + contentType.ResetDirtyProperties(); // this would be like committing the entity // Assert Assert.That(contentType.IsDirty(), Is.False); @@ -831,11 +836,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void After_Committing_Changes_Was_Dirty_Is_True_On_Changed_Property() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); - contentType.ResetDirtyProperties(); //reset + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); + contentType.ResetDirtyProperties(); // reset Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = ContentBuilder.CreateTextpageContent(contentType, "test", -1); + Content content = ContentBuilder.CreateTextpageContent(contentType, "test", -1); content.ResetDirtyProperties(); // Act @@ -848,13 +853,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.That(content.Properties[0].IsDirty(), Is.True); Assert.That(content.Properties["title"].IsDirty(), Is.True); - content.ResetDirtyProperties(); //this would be like committing the entity + content.ResetDirtyProperties(); // this would be like committing the entity // Assert Assert.That(content.WasDirty(), Is.True); Assert.That(content.Properties[0].WasDirty(), Is.True); - Assert.That(content.WasPropertyDirty("title"), Is.True); Assert.That(content.Properties["title"].IsDirty(), Is.False); Assert.That(content.Properties["title"].WasDirty(), Is.True); @@ -864,7 +868,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void If_Not_Committed_Was_Dirty_Is_False() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act contentType.Alias = "newAlias"; @@ -878,7 +882,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Detect_That_A_Property_Is_Removed() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); Assert.That(contentType.WasPropertyDirty("HasPropertyTypeBeenRemoved"), Is.False); // Act @@ -892,11 +896,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Adding_PropertyType_To_PropertyGroup_On_ContentType_Results_In_Dirty_Entity() { // Arrange - var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("subtitle") .WithName("Subtitle") .Build(); @@ -912,18 +916,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Compose_Composite_ContentType_Collection() { // Arrange - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); - var propertyType = new PropertyTypeBuilder() + ContentType simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("coauthor") .WithName("Co-author") .Build(); - var simple2ContentType = ContentTypeBuilder.CreateSimpleContentType("anotherSimple", "Another Simple Page", + ContentType simple2ContentType = ContentTypeBuilder.CreateSimpleContentType( + "anotherSimple", + "Another Simple Page", propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType })); // Act - var added = simpleContentType.AddContentType(simple2ContentType); - var compositionPropertyGroups = simpleContentType.CompositionPropertyGroups; - var compositionPropertyTypes = simpleContentType.CompositionPropertyTypes; + bool added = simpleContentType.AddContentType(simple2ContentType); + IEnumerable compositionPropertyGroups = simpleContentType.CompositionPropertyGroups; + IEnumerable compositionPropertyTypes = simpleContentType.CompositionPropertyTypes; // Assert Assert.That(added, Is.True); @@ -935,20 +941,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Compose_Nested_Composite_ContentType_Collection() { // Arrange - var metaContentType = ContentTypeBuilder.CreateMetaContentType(); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); - var propertyType = new PropertyTypeBuilder() + ContentType metaContentType = ContentTypeBuilder.CreateMetaContentType(); + ContentType simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("coauthor") .WithName("Co-author") .Build(); - var simple2ContentType = ContentTypeBuilder.CreateSimpleContentType("anotherSimple", "Another Simple Page", + ContentType simple2ContentType = ContentTypeBuilder.CreateSimpleContentType( + "anotherSimple", + "Another Simple Page", propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType })); // Act - var addedMeta = simple2ContentType.AddContentType(metaContentType); - var added = simpleContentType.AddContentType(simple2ContentType); - var compositionPropertyGroups = simpleContentType.CompositionPropertyGroups; - var compositionPropertyTypes = simpleContentType.CompositionPropertyTypes; + bool addedMeta = simple2ContentType.AddContentType(metaContentType); + bool added = simpleContentType.AddContentType(simple2ContentType); + IEnumerable compositionPropertyGroups = simpleContentType.CompositionPropertyGroups; + IEnumerable compositionPropertyTypes = simpleContentType.CompositionPropertyTypes; // Assert Assert.That(addedMeta, Is.True); @@ -961,35 +969,39 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Avoid_Circular_Dependencies_In_Composition() { - var textPage = ContentTypeBuilder.CreateTextPageContentType(); - var parent = ContentTypeBuilder.CreateSimpleContentType("parent", "Parent", null, randomizeAliases: true); - var meta = ContentTypeBuilder.CreateMetaContentType(); - var propertyType1 = new PropertyTypeBuilder() + ContentType textPage = ContentTypeBuilder.CreateTextPageContentType(); + ContentType parent = ContentTypeBuilder.CreateSimpleContentType("parent", "Parent", null, randomizeAliases: true); + ContentType meta = ContentTypeBuilder.CreateMetaContentType(); + PropertyType propertyType1 = new PropertyTypeBuilder() .WithAlias("coauthor") .WithName("Co-author") .Build(); - var mixin1 = ContentTypeBuilder.CreateSimpleContentType("mixin1", "Mixin1", + ContentType mixin1 = ContentTypeBuilder.CreateSimpleContentType( + "mixin1", + "Mixin1", propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType1 })); - var propertyType2 = new PropertyTypeBuilder() + PropertyType propertyType2 = new PropertyTypeBuilder() .WithAlias("author") .WithName("Author") .Build(); - var mixin2 = ContentTypeBuilder.CreateSimpleContentType("mixin2", "Mixin2", + ContentType mixin2 = ContentTypeBuilder.CreateSimpleContentType( + "mixin2", + "Mixin2", propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType2 })); // Act - var addedMetaMixin2 = mixin2.AddContentType(meta); - var addedMixin2 = mixin1.AddContentType(mixin2); - var addedMeta = parent.AddContentType(meta); + bool addedMetaMixin2 = mixin2.AddContentType(meta); + bool addedMixin2 = mixin1.AddContentType(mixin2); + bool addedMeta = parent.AddContentType(meta); - var addedMixin1 = parent.AddContentType(mixin1); + bool addedMixin1 = parent.AddContentType(mixin1); - var addedMixin1Textpage = textPage.AddContentType(mixin1); - var addedTextpageParent = parent.AddContentType(textPage); + bool addedMixin1Textpage = textPage.AddContentType(mixin1); + bool addedTextpageParent = parent.AddContentType(textPage); - var aliases = textPage.CompositionAliases(); - var propertyTypes = textPage.CompositionPropertyTypes; - var propertyGroups = textPage.CompositionPropertyGroups; + IEnumerable aliases = textPage.CompositionAliases(); + IEnumerable propertyTypes = textPage.CompositionPropertyTypes; + IEnumerable propertyGroups = textPage.CompositionPropertyGroups; // Assert Assert.That(mixin2.ContentTypeCompositionExists("meta"), Is.True); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs index c571a79785..3970fb9f53 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs @@ -1,6 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using System.Linq; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -17,10 +21,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")] public void Cannot_Add_Duplicate_Property_Aliases() { - var contentType = BuildContentType(); + ContentType contentType = BuildContentType(); var propertyTypeBuilder = new PropertyTypeBuilder(); - var additionalPropertyType = propertyTypeBuilder + PropertyType additionalPropertyType = propertyTypeBuilder .WithAlias("title") .Build(); @@ -32,16 +36,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")] public void Cannot_Update_Duplicate_Property_Aliases() { - var contentType = BuildContentType(); + ContentType contentType = BuildContentType(); var propertyTypeBuilder = new PropertyTypeBuilder(); - var additionalPropertyType = propertyTypeBuilder + PropertyType additionalPropertyType = propertyTypeBuilder .WithAlias("title") .Build(); contentType.PropertyTypeCollection.Add(additionalPropertyType); - var toUpdate = contentType.PropertyTypeCollection["myPropertyType2"]; + IPropertyType toUpdate = contentType.PropertyTypeCollection["myPropertyType2"]; Assert.Throws(() => toUpdate.Alias = "myPropertyType"); } @@ -49,7 +53,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Deep_Clone_Content_Type_Sort() { - var contentType = BuildContentTypeSort(); + ContentTypeSort contentType = BuildContentTypeSort(); var clone = (ContentTypeSort)contentType.DeepClone(); Assert.AreNotSame(clone, contentType); Assert.AreEqual(clone, contentType); @@ -71,7 +75,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Deep_Clone_Content_Type_With_Reset_Identities() { - var contentType = BuildContentType(); + ContentType contentType = BuildContentType(); var clone = (ContentType)contentType.DeepCloneWithResetIdentities("newAlias"); @@ -79,22 +83,26 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotEqual("newAlias", contentType.Alias); Assert.IsFalse(clone.HasIdentity); - foreach (var propertyGroup in clone.PropertyGroups) + foreach (PropertyGroup propertyGroup in clone.PropertyGroups) { Assert.IsFalse(propertyGroup.HasIdentity); - foreach (var propertyType in propertyGroup.PropertyTypes) + foreach (IPropertyType propertyType in propertyGroup.PropertyTypes) + { Assert.IsFalse(propertyType.HasIdentity); + } } - foreach (var propertyType in clone.PropertyTypes.Where(x => x.HasIdentity)) + foreach (IPropertyType propertyType in clone.PropertyTypes.Where(x => x.HasIdentity)) + { Assert.IsFalse(propertyType.HasIdentity); - } + } + } [Test] public void Can_Deep_Clone_Content_Type() { // Arrange - var contentType = BuildContentType(); + ContentType contentType = BuildContentType(); // Act var clone = (ContentType)contentType.DeepClone(); @@ -109,6 +117,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.AllowedTemplates.ElementAt(index), contentType.AllowedTemplates.ElementAt(index)); Assert.AreEqual(clone.AllowedTemplates.ElementAt(index), contentType.AllowedTemplates.ElementAt(index)); } + Assert.AreNotSame(clone.PropertyGroups, contentType.PropertyGroups); Assert.AreEqual(clone.PropertyGroups.Count, contentType.PropertyGroups.Count); for (var index = 0; index < contentType.PropertyGroups.Count; index++) @@ -116,6 +125,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]); Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]); } + Assert.AreNotSame(clone.PropertyTypes, contentType.PropertyTypes); Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count()); Assert.AreEqual(0, clone.NoGroupPropertyTypes.Count()); @@ -140,19 +150,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.Icon, contentType.Icon); Assert.AreEqual(clone.IsContainer, contentType.IsContainer); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null)); + } - //need to ensure the event handlers are wired - + // Need to ensure the event handlers are wired var asDirty = (ICanBeDirty)clone; Assert.IsFalse(asDirty.IsPropertyDirty("PropertyTypes")); var propertyTypeBuilder = new PropertyTypeBuilder(); - var additionalPropertyType = propertyTypeBuilder + PropertyType additionalPropertyType = propertyTypeBuilder .WithAlias("blah") .Build(); @@ -167,7 +178,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Serialize_Content_Type_Without_Error() { // Arrange - var contentType = BuildContentType(); + ContentType contentType = BuildContentType(); var json = JsonConvert.SerializeObject(contentType); Debug.Print(json); @@ -183,7 +194,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Deep_Clone_Media_Type() { // Arrange - var contentType = BuildMediaType(); + MediaType contentType = BuildMediaType(); // Act var clone = (MediaType)contentType.DeepClone(); @@ -198,12 +209,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]); Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]); } + Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count()); for (var index = 0; index < contentType.PropertyTypes.Count(); index++) { Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index)); Assert.AreEqual(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index)); } + Assert.AreEqual(clone.CreateDate, contentType.CreateDate); Assert.AreEqual(clone.CreatorId, contentType.CreatorId); Assert.AreEqual(clone.Key, contentType.Key); @@ -216,17 +229,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.Icon, contentType.Icon); Assert.AreEqual(clone.IsContainer, contentType.IsContainer); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null)); + } } [Test] public void Can_Serialize_Media_Type_Without_Error() { // Arrange - var contentType = BuildMediaType(); + MediaType contentType = BuildMediaType(); var json = JsonConvert.SerializeObject(contentType); Debug.Print(json); @@ -242,7 +257,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Deep_Clone_Member_Type() { // Arrange - var contentType = BuildMemberType(); + MemberType contentType = BuildMemberType(); // Act var clone = (MemberType)contentType.DeepClone(); @@ -257,12 +272,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.PropertyGroups[index], contentType.PropertyGroups[index]); Assert.AreEqual(clone.PropertyGroups[index], contentType.PropertyGroups[index]); } + Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count()); for (var index = 0; index < contentType.PropertyTypes.Count(); index++) { Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index)); Assert.AreEqual(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index)); } + Assert.AreEqual(clone.CreateDate, contentType.CreateDate); Assert.AreEqual(clone.CreatorId, contentType.CreatorId); Assert.AreEqual(clone.Key, contentType.Key); @@ -276,16 +293,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.IsContainer, contentType.IsContainer); // This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(contentType, null)); + } } [Test] public void Can_Serialize_Member_Type_Without_Error() { // Arrange - var contentType = BuildMemberType(); + MemberType contentType = BuildMemberType(); var json = JsonConvert.SerializeObject(contentType); Debug.Print(json); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs index 753c0e2b4d..f72a28b0f3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs @@ -1,4 +1,7 @@ -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Moq; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,26 +17,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Mock.Of(x => x.Published == true), new[] { "en-US", "fr-FR" }, "en-US"); - Assert.AreEqual("en-US", result); //default culture is being saved so use it + Assert.AreEqual("en-US", result); // default culture is being saved so use it result = CultureImpact.GetCultureForInvariantErrors( Mock.Of(x => x.Published == false), new[] { "fr-FR" }, "en-US"); - Assert.AreEqual("fr-FR", result); //default culture not being saved with not published version, use the first culture being saved + Assert.AreEqual("fr-FR", result); // default culture not being saved with not published version, use the first culture being saved result = CultureImpact.GetCultureForInvariantErrors( Mock.Of(x => x.Published == true), new[] { "fr-FR" }, "en-US"); - Assert.AreEqual(null, result); //default culture not being saved with published version, use null - + Assert.AreEqual(null, result); // default culture not being saved with published version, use null } [Test] public void All_Cultures() { - var impact = CultureImpact.All; + CultureImpact impact = CultureImpact.All; Assert.AreEqual(impact.Culture, "*"); @@ -48,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Invariant_Culture() { - var impact = CultureImpact.Invariant; + CultureImpact impact = CultureImpact.Invariant; Assert.AreEqual(impact.Culture, null); @@ -93,7 +95,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void TryCreate_Explicit_Default_Culture() { - var success = CultureImpact.TryCreate("en-US", true, ContentVariation.Culture, false, out var impact); + var success = CultureImpact.TryCreate("en-US", true, ContentVariation.Culture, false, out CultureImpact impact); Assert.IsTrue(success); Assert.AreEqual(impact.Culture, "en-US"); @@ -109,7 +111,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void TryCreate_Explicit_NonDefault_Culture() { - var success = CultureImpact.TryCreate("en-US", false, ContentVariation.Culture, false, out var impact); + var success = CultureImpact.TryCreate("en-US", false, ContentVariation.Culture, false, out CultureImpact impact); Assert.IsTrue(success); Assert.AreEqual(impact.Culture, "en-US"); @@ -125,7 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void TryCreate_AllCultures_For_Invariant() { - var success = CultureImpact.TryCreate("*", false, ContentVariation.Nothing, false, out var impact); + var success = CultureImpact.TryCreate("*", false, ContentVariation.Nothing, false, out CultureImpact impact); Assert.IsTrue(success); Assert.AreEqual(impact.Culture, null); @@ -136,7 +138,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void TryCreate_AllCultures_For_Variant() { - var success = CultureImpact.TryCreate("*", false, ContentVariation.Culture, false, out var impact); + var success = CultureImpact.TryCreate("*", false, ContentVariation.Culture, false, out CultureImpact impact); Assert.IsTrue(success); Assert.AreEqual(impact.Culture, "*"); @@ -147,14 +149,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void TryCreate_Invariant_For_Variant() { - var success = CultureImpact.TryCreate(null, false, ContentVariation.Culture, false, out var impact); + var success = CultureImpact.TryCreate(null, false, ContentVariation.Culture, false, out CultureImpact impact); Assert.IsFalse(success); } [Test] public void TryCreate_Invariant_For_Invariant() { - var success = CultureImpact.TryCreate(null, false, ContentVariation.Nothing, false, out var impact); + var success = CultureImpact.TryCreate(null, false, ContentVariation.Nothing, false, out CultureImpact impact); Assert.IsTrue(success); Assert.AreSame(CultureImpact.Invariant, impact); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs index fcad67c221..6dc251d9f8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Collections; using System.Collections.Generic; using System.Linq; @@ -149,74 +151,76 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models MyTest1 = new object[] { new Test1(), "hello", - //not cloneable so this property will get skipped + + // Not cloneable so this property will get skipped. new Test2() } }; var clone = (Test3)test1.DeepClone(); - //it skipped this property so these will now be the same + // It skipped this property so these will now be the same. Assert.AreSame(clone.MyTest1, test1.MyTest1); - } public class Test1 : BaseCloneable { public string Name { get; set; } + public int Age { get; set; } public Test1 MyTest1 { get; set; } - public Test2 MyTest2 { get; set; } + public Test2 MyTest2 { get; set; } } public class Test2 { public string Name { get; set; } + public Test1 MyTest1 { get; set; } } public class Test3 : BaseCloneable { public string Name { get; set; } - public object[] MyTest1 { get; set; } + public object[] MyTest1 { get; set; } } public class Test4 : BaseCloneable { public string Name { get; set; } - public Test1[] MyTest1 { get; set; } + public Test1[] MyTest1 { get; set; } } public class Test5 : BaseCloneable { public string Name { get; set; } - public IEnumerable MyTest1 { get; set; } + public IEnumerable MyTest1 { get; set; } } public class Test6 : BaseCloneable { public string Name { get; set; } - public IEnumerable MyTest1 { get; set; } + public IEnumerable MyTest1 { get; set; } } public class Test7 : BaseCloneable { public string Name { get; set; } - public List MyTest1 { get; set; } + public List MyTest1 { get; set; } } public class Test8 : BaseCloneable { public string Name { get; set; } - public ICollection MyTest1 { get; set; } + public ICollection MyTest1 { get; set; } } public abstract class BaseCloneable : IDeepCloneable diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs index 54a935c891..4994c12f84 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs @@ -1,4 +1,8 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Linq; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -12,15 +16,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private DictionaryItemBuilder _builder = new DictionaryItemBuilder(); [SetUp] - public void SetUp() - { - _builder = new DictionaryItemBuilder(); - } + public void SetUp() => _builder = new DictionaryItemBuilder(); [Test] public void Can_Deep_Clone() { - var item = _builder + DictionaryItem item = _builder .WithRandomTranslations(2) .Build(); @@ -41,19 +42,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.Translations.ElementAt(i), item.Translations.ElementAt(i)); } - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); } - } [Test] public void Can_Serialize_Without_Error() { - var item = _builder + DictionaryItem item = _builder .WithRandomTranslations(2) .Build(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs index 957acf293e..073a168e23 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs @@ -1,5 +1,9 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using System.Linq; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,15 +18,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private DictionaryTranslationBuilder _builder = new DictionaryTranslationBuilder(); [SetUp] - public void SetUp() - { - _builder = new DictionaryTranslationBuilder(); - } + public void SetUp() => _builder = new DictionaryTranslationBuilder(); [Test] public void Can_Deep_Clone() { - var item = BuildDictionaryTranslation(); + IDictionaryTranslation item = BuildDictionaryTranslation(); var clone = (DictionaryTranslation)item.DeepClone(); @@ -33,35 +34,36 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.Key, item.Key); Assert.AreEqual(clone.UpdateDate, item.UpdateDate); Assert.AreNotSame(clone.Language, item.Language); - //This is null because we are ignoring it from cloning due to caching/cloning issues - we don't really want + + // This is null because we are ignoring it from cloning due to caching/cloning issues - we don't really want // this entity attached to this item but we're stuck with it for now Assert.IsNull(clone.Language); Assert.AreEqual(clone.LanguageId, item.LanguageId); Assert.AreEqual(clone.Value, item.Value); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps.Where(x => x.Name != "Language")) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps.Where(x => x.Name != "Language")) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); + } } [Test] public void Can_Serialize_Without_Error() { - var item = BuildDictionaryTranslation(); + IDictionaryTranslation item = BuildDictionaryTranslation(); var json = JsonConvert.SerializeObject(item); Debug.Print(json); } - private IDictionaryTranslation BuildDictionaryTranslation() - { - return _builder + private IDictionaryTranslation BuildDictionaryTranslation() => + _builder .AddLanguage() .WithCultureInfo("en-AU") .Done() .WithValue("colour") - .Build(); - } + .Build(); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs index 1829720aad..ec3ed57bd6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs @@ -1,6 +1,10 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using Newtonsoft.Json; using NUnit.Framework; +using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -12,15 +16,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private DocumentEntitySlimBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new DocumentEntitySlimBuilder(); - } + public void SetUp() => _builder = new DocumentEntitySlimBuilder(); [Test] public void Can_Serialize_Without_Error() { - var item = _builder + DocumentEntitySlim item = _builder .WithId(3) .WithCreatorId(4) .WithName("Test") diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs index 5b1fc2d56b..5523f57680 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs @@ -1,4 +1,8 @@ -using Newtonsoft.Json; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Reflection; +using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; @@ -12,19 +16,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private LanguageBuilder _builder = new LanguageBuilder(); [SetUp] - public void SetUp() - { - _builder = new LanguageBuilder(); - } + public void SetUp() => _builder = new LanguageBuilder(); [Test] public void Can_Deep_Clone() { - var item = _builder + ILanguage item = _builder .WithId(1) .Build(); - var clone = (Language) item.DeepClone(); + var clone = (Language)item.DeepClone(); Assert.AreNotSame(clone, item); Assert.AreEqual(clone, item); Assert.AreEqual(clone.CreateDate, item.CreateDate); @@ -34,9 +35,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.Key, item.Key); Assert.AreEqual(clone.UpdateDate, item.UpdateDate); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); } @@ -45,7 +46,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var item = _builder.Build(); + ILanguage item = _builder.Build(); Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs index 9d22387cd6..d7964e45b2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; +using System.Reflection; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -14,15 +18,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private MacroBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new MacroBuilder(); - } + public void SetUp() => _builder = new MacroBuilder(); [Test] public void Can_Deep_Clone() { - var macro = _builder + Macro macro = _builder .WithId(1) .WithUseInEditor(true) .WithCacheDuration(3) @@ -58,13 +59,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreNotSame(clone.AddedProperties, macro.AddedProperties); Assert.AreNotSame(clone.RemovedProperties, macro.RemovedProperties); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(macro, null)); + } - //need to ensure the event handlers are wired - + // Need to ensure the event handlers are wired. var asDirty = (ICanBeDirty)clone; Assert.IsFalse(asDirty.IsPropertyDirty("Properties")); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs index 47138a5fb4..165a42b225 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,16 +18,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private MemberGroupBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new MemberGroupBuilder(); - } + public void SetUp() => _builder = new MemberGroupBuilder(); [Test] public void Can_Deep_Clone() { // Arrange - var group = BuildMemberGroup(); + MemberGroup group = BuildMemberGroup(); // Act var clone = (MemberGroup)group.DeepClone(); @@ -40,24 +41,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.UpdateDate, group.UpdateDate); Assert.AreEqual(clone.Name, group.Name); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(group, null)); + } } [Test] public void Can_Serialize_Without_Error() { - var group = BuildMemberGroup(); + MemberGroup group = BuildMemberGroup(); var json = JsonConvert.SerializeObject(group); Debug.Print(json); } - private MemberGroup BuildMemberGroup() - { - return _builder + private MemberGroup BuildMemberGroup() => + _builder .WithId(6) .WithKey(Guid.NewGuid()) .WithName("Test Group") @@ -69,6 +71,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithKeyValue("test2", "hello") .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs index 58f88affa1..8ca253c224 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs @@ -1,5 +1,9 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using System.Linq; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,16 +18,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private MemberBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new MemberBuilder(); - } + public void SetUp() => _builder = new MemberBuilder(); [Test] public void Can_Deep_Clone() { // Arrange - var member = BuildMember(); + Member member = BuildMember(); // Act var clone = (Member)member.DeepClone(); @@ -66,24 +67,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // this can be the same, it is immutable Assert.AreSame(clone.ContentType, member.ContentType); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(member, null)); + } } [Test] public void Can_Serialize_Without_Error() { - var member = BuildMember(); + Member member = BuildMember(); var json = JsonConvert.SerializeObject(member); Debug.Print(json); } - private Member BuildMember() - { - return _builder + private Member BuildMember() => + _builder .AddMemberType() .WithId(99) .WithAlias("memberType") @@ -117,7 +119,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithEmail("email@email.com") .WithFailedPasswordAttempts(22) .WithIsApproved(true) - .WithIsLockedOut(true) + .WithIsLockedOut(true) .WithTrashed(false) .AddMemberGroups() .WithValue("Group 1") @@ -134,6 +136,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithKeyValue("author", "John Doe") .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs index 08e025a6b1..647684ff2f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs @@ -1,5 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Diagnostics; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,15 +17,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private PropertyGroupBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new PropertyGroupBuilder(); - } + public void SetUp() => _builder = new PropertyGroupBuilder(); [Test] public void Can_Deep_Clone() { - var pg = BuildPropertyGroup(); + PropertyGroup pg = BuildPropertyGroup(); var clone = (PropertyGroup)pg.DeepClone(); @@ -43,9 +43,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.PropertyTypes[i], pg.PropertyTypes[i]); } - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(pg, null)); } @@ -54,15 +54,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var pg = BuildPropertyGroup(); + PropertyGroup pg = BuildPropertyGroup(); var json = JsonConvert.SerializeObject(pg); Debug.Print(json); } - private PropertyGroup BuildPropertyGroup() - { - return _builder + private PropertyGroup BuildPropertyGroup() => + _builder .WithId(77) .WithName("Group1") .AddPropertyType() @@ -71,15 +70,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithName("Test") .WithDescription("testing") .WithPropertyGroupId(11) - .WithMandatory(true) + .WithMandatory(true) .WithValidationRegExp("xxxx") .Done() .AddPropertyType() .WithId(4) .WithAlias("test2") - .WithName("Test2") + .WithName("Test2") .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs index ce87174d7c..99188759af 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs @@ -1,27 +1,27 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Linq; +using System.Reflection; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models -{ +{ [TestFixture] public class PropertyTests { private PropertyBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new PropertyBuilder(); - } + public void SetUp() => _builder = new PropertyBuilder(); [Test] public void Can_Deep_Clone() { - var property = BuildProperty(); + IProperty property = BuildProperty(); property.SetValue("hello"); property.PublishValues(); @@ -37,16 +37,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models } // This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(property, null)); } } - private IProperty BuildProperty() - { - return _builder + private IProperty BuildProperty() => + _builder .WithId(4) .AddPropertyType() .WithId(3) @@ -61,6 +60,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithValidationRegExp("xxxx") .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs index 6fa061b1d2..cce3f43db0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs @@ -1,8 +1,11 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; -using Newtonsoft.Json; using System.Linq; using System.Reflection; +using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; @@ -16,15 +19,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private PropertyTypeBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new PropertyTypeBuilder(); - } + public void SetUp() => _builder = new PropertyTypeBuilder(); [Test] public void Can_Deep_Clone() { - var pt = BuildPropertyType(); + PropertyType pt = BuildPropertyType(); var clone = (PropertyType)pt.DeepClone(); @@ -45,9 +45,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.ValidationRegExp, pt.ValidationRegExp); Assert.AreEqual(clone.ValueStorageType, pt.ValueStorageType); - //This double verifies by reflection (don't test properties marked with [DoNotClone] - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps.Where(p => p.GetCustomAttribute(false) == null)) + // This double verifies by reflection (don't test properties marked with [DoNotClone] + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps.Where(p => p.GetCustomAttribute(false) == null)) { var expected = propertyInfo.GetValue(pt, null); var actual = propertyInfo.GetValue(clone, null); @@ -64,15 +64,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var pt = BuildPropertyType(); + PropertyType pt = BuildPropertyType(); var json = JsonConvert.SerializeObject(pt); Debug.Print(json); } - private PropertyType BuildPropertyType() - { - return _builder + private PropertyType BuildPropertyType() => + _builder .WithId(3) .WithPropertyEditorAlias("TestPropertyEditor") .WithAlias("test") @@ -84,6 +83,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithMandatory(true) .WithValidationRegExp("xxxx") .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs index fa7e540533..66fce7f93f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -14,17 +18,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private RelationBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new RelationBuilder(); - } + public void SetUp() => _builder = new RelationBuilder(); [Test] public void Can_Deep_Clone() { - var relation = BuildRelation(); + Relation relation = BuildRelation(); - var clone = (Relation) relation.DeepClone(); + var clone = (Relation)relation.DeepClone(); Assert.AreNotSame(clone, relation); Assert.AreEqual(clone, relation); @@ -39,9 +40,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.RelationTypeId, relation.RelationTypeId); Assert.AreEqual(clone.UpdateDate, relation.UpdateDate); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(relation, null)); } @@ -50,15 +51,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var relation = BuildRelation(); + Relation relation = BuildRelation(); var json = JsonConvert.SerializeObject(relation); Debug.Print(json); } - private Relation BuildRelation() - { - return _builder + private Relation BuildRelation() => + _builder .BetweenIds(9, 8) .WithId(4) .WithComment("test comment") @@ -74,6 +74,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithChildObjectType(Guid.NewGuid()) .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs index 2d5b88d945..d29f89283d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; @@ -13,21 +17,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private RelationTypeBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new RelationTypeBuilder(); - } + public void SetUp() => _builder = new RelationTypeBuilder(); [Test] public void Can_Deep_Clone() { - var item = _builder + IRelationType item = _builder .WithId(1) .WithParentObjectType(Guid.NewGuid()) .WithChildObjectType(Guid.NewGuid()) .Build(); - var clone = (RelationType) item.DeepClone(); + var clone = (RelationType)item.DeepClone(); Assert.AreNotSame(clone, item); Assert.AreEqual(clone, item); @@ -41,9 +42,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.CreateDate, item.CreateDate); Assert.AreEqual(clone.UpdateDate, item.UpdateDate); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); } @@ -52,7 +53,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var item = _builder.Build(); + IRelationType item = _builder.Build(); Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs index f744fee829..a2d9ed18f8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Newtonsoft.Json; @@ -14,17 +18,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private StylesheetBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new StylesheetBuilder(); - } + public void SetUp() => _builder = new StylesheetBuilder(); [Test] public void Can_Create_Stylesheet() { // Arrange // Act - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"body { color:#000; } .bold {font-weight:bold;}") .Build(); @@ -38,7 +39,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Add_Property() { // Arrange - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"body { color:#000; } .bold {font-weight:bold;}") .Build(); @@ -50,14 +51,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(1, stylesheet.Properties.Count()); Assert.AreEqual("Test", stylesheet.Properties.Single().Name); Assert.AreEqual("p", stylesheet.Properties.Single().Alias); - Assert.AreEqual("font-weight:bold;"+Environment.NewLine+"font-family:Arial;", stylesheet.Properties.Single().Value); + Assert.AreEqual("font-weight:bold;" + Environment.NewLine + "font-family:Arial;", stylesheet.Properties.Single().Value); } [Test] public void Can_Remove_Property() { // Arrange - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"body { color:#000; } /**umb_name:Hello*/p{font-size:2em;} .bold {font-weight:bold;}") .Build(); @@ -75,13 +76,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Can_Update_Property() { // Arrange - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"body { color:#000; } /**umb_name:Hello*/p{font-size:2em;} .bold {font-weight:bold;}") .Build(); // Act - var prop = stylesheet.Properties.Single(); + IStylesheetProperty prop = stylesheet.Properties.Single(); prop.Alias = "li"; prop.Value = "font-size:5em;"; @@ -91,20 +92,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // Assert Assert.AreEqual("li", prop.Alias); Assert.AreEqual("font-size:5em;", prop.Value); - Assert.AreEqual("body { color:#000; } /**umb_name:Hello*/" +Environment.NewLine+ "li {" +Environment.NewLine+ "\tfont-size:5em;" +Environment.NewLine+ "} .bold {font-weight:bold;}", stylesheet.Content); + Assert.AreEqual("body { color:#000; } /**umb_name:Hello*/" + Environment.NewLine + "li {" + Environment.NewLine + "\tfont-size:5em;" + Environment.NewLine + "} .bold {font-weight:bold;}", stylesheet.Content); } [Test] public void Can_Get_Properties_From_Css() { // Arrange - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"body { color:#000; } .bold {font-weight:bold;} /**umb_name:Hello */ p { font-size: 1em; } /**umb_name:testing123*/ li:first-child {padding:0px;}") .Build(); // Act - var properties = stylesheet.Properties; + IEnumerable properties = stylesheet.Properties; // Assert Assert.AreEqual(2, properties.Count()); @@ -116,12 +117,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual("li:first-child", properties.Last().Alias); } - [Test] public void Can_Serialize_Without_Error() { // Arrange - var stylesheet = _builder + Stylesheet stylesheet = _builder .WithPath("/css/styles.css") .WithContent(@"@media screen and (min-width: 600px) and (min-width: 900px) { .class { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs index d1c731184e..04a49456b6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -16,15 +19,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private TemplateBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new TemplateBuilder(); - } + public void SetUp() => _builder = new TemplateBuilder(); [Test] public void Can_Deep_Clone() { - var template = BuildTemplate(); + ITemplate template = BuildTemplate(); var clone = (Template)template.DeepClone(); @@ -42,15 +42,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.UpdateDate, template.UpdateDate); // clone.Content should be null but getting it would lazy-load - var type = clone.GetType(); - var contentField = type.BaseType.GetField("_content", BindingFlags.Instance | BindingFlags.NonPublic); + Type type = clone.GetType(); + FieldInfo contentField = type.BaseType.GetField("_content", BindingFlags.Instance | BindingFlags.NonPublic); var value = contentField.GetValue(clone); Assert.IsNull(value); // this double verifies by reflection // need to exclude content else it would lazy-load - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps.Where(x => x.Name != "Content")) + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps.Where(x => x.Name != "Content")) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(template, null)); } @@ -59,15 +59,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void Can_Serialize_Without_Error() { - var template = BuildTemplate(); + ITemplate template = BuildTemplate(); var json = JsonConvert.SerializeObject(template); Debug.Print(json); } - private ITemplate BuildTemplate() - { - return _builder + private ITemplate BuildTemplate() => + _builder .WithId(3) .WithAlias("test") .WithName("Test") @@ -77,6 +76,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithContent("blah") .AsMasterTemplate("master", 88) .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs index faf96a6457..426f698969 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Moq; @@ -7,6 +10,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; +using User = Umbraco.Core.Models.Membership.User; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { @@ -16,10 +20,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private UserBuilder _userBuilder; [SetUp] - public void SetUp() - { - _userBuilder = new UserBuilder(); - } + public void SetUp() => _userBuilder = new UserBuilder(); [TestCase(-1, "-1", "-1,1,2,3,4,5", true)] // below root start node [TestCase(2, "-1,1,2", "-1,1,2,3,4,5", true)] // below start node @@ -32,11 +33,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models public void Determines_Path_Based_Access_To_Content(int startNodeId, string startNodePath, string contentPath, bool outcome) { - var user = _userBuilder + User user = _userBuilder .WithStartContentIds(new[] { startNodeId }) .Build(); - var content = Mock.Of(c => c.Path == contentPath && c.Id == 5); + IContent content = Mock.Of(c => c.Path == contentPath && c.Id == 5); var esmock = new Mock(); esmock @@ -80,7 +81,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models // 6 // 7 // 8 - var paths = new Dictionary { { 1, "-1,1" }, @@ -106,10 +106,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models var expectedA = expected.Split(comma, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).OrderBy(x => x).ToArray(); var ok = combinedA.Length == expectedA.Length; - if (ok) ok = expectedA.Where((t, i) => t != combinedA[i]).Any() == false; + if (ok) + { + ok = expectedA.Where((t, i) => t != combinedA[i]).Any() == false; + } if (ok == false) + { Assert.Fail("Expected \"" + string.Join(",", expectedA) + "\" but got \"" + string.Join(",", combinedA) + "\"."); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs index e4b9f89067..9f0613f9d6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs @@ -1,5 +1,9 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using System.Linq; +using System.Reflection; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models.Membership; @@ -14,15 +18,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private UserBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new UserBuilder(); - } + public void SetUp() => _builder = new UserBuilder(); [Test] public void Can_Deep_Clone() { - var item = BuildUser(); + User item = BuildUser(); var clone = (User)item.DeepClone(); @@ -31,24 +32,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.AreEqual(clone.AllowedSections.Count(), item.AllowedSections.Count()); - //Verify normal properties with reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // Verify normal properties with reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) + { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); + } } [Test] public void Can_Serialize_Without_Error() { - var item = BuildUser(); + User item = BuildUser(); var json = JsonConvert.SerializeObject(item); Debug.Print(json); } - private User BuildUser() - { - return _builder + private User BuildUser() => + _builder .WithId(3) .WithLogin("username", "test pass") .WithName("Test") @@ -61,6 +63,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models .WithStartContentIds(new[] { 3 }) .WithStartMediaIds(new[] { 8 }) .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs index 81c868656e..f92ba1ddeb 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; @@ -22,110 +25,112 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void ValidateVariationTests() { - // All tests: // 1. if exact is set to true: culture cannot be null when the ContentVariation.Culture flag is set // 2. if wildcards is set to false: fail when "*" is passed in as either culture or segment. // 3. ContentVariation flag is ignored when wildcards are used. // 4. Empty string is considered the same as null + AssertForNovariation(); + AssertForCultureVariation(); + AssertForSegmentVariation(); + AssertForCultureAndSegmentVariation(); + } - #region Nothing - + private static void AssertForNovariation() + { Assert4A(ContentVariation.Nothing, null, null, true); - Assert4A(ContentVariation.Nothing, null, "", true); + Assert4A(ContentVariation.Nothing, null, string.Empty, true); Assert4B(ContentVariation.Nothing, null, "*", true, false, false, true); Assert4A(ContentVariation.Nothing, null, "segment", false); - Assert4A(ContentVariation.Nothing, "", null, true); - Assert4A(ContentVariation.Nothing, "", "", true); - Assert4B(ContentVariation.Nothing, "", "*", true, false, false, true); - Assert4A(ContentVariation.Nothing, "", "segment", false); + Assert4A(ContentVariation.Nothing, string.Empty, null, true); + Assert4A(ContentVariation.Nothing, string.Empty, string.Empty, true); + Assert4B(ContentVariation.Nothing, string.Empty, "*", true, false, false, true); + Assert4A(ContentVariation.Nothing, string.Empty, "segment", false); Assert4B(ContentVariation.Nothing, "*", null, true, false, false, true); - Assert4B(ContentVariation.Nothing, "*", "", true, false, false, true); + Assert4B(ContentVariation.Nothing, "*", string.Empty, true, false, false, true); Assert4B(ContentVariation.Nothing, "*", "*", true, false, false, true); Assert4A(ContentVariation.Nothing, "*", "segment", false); Assert4A(ContentVariation.Nothing, "culture", null, false); - Assert4A(ContentVariation.Nothing, "culture", "", false); + Assert4A(ContentVariation.Nothing, "culture", string.Empty, false); Assert4A(ContentVariation.Nothing, "culture", "*", false); Assert4A(ContentVariation.Nothing, "culture", "segment", false); + } - #endregion - - #region Culture - + private static void AssertForCultureVariation() + { Assert4B(ContentVariation.Culture, null, null, false, true, false, true); - Assert4B(ContentVariation.Culture, null, "", false, true, false, true); + Assert4B(ContentVariation.Culture, null, string.Empty, false, true, false, true); Assert4B(ContentVariation.Culture, null, "*", false, false, false, true); Assert4A(ContentVariation.Culture, null, "segment", false); - Assert4B(ContentVariation.Culture, "", null, false, true, false, true); - Assert4B(ContentVariation.Culture, "", "", false, true, false, true); - Assert4B(ContentVariation.Culture, "", "*", false, false, false, true); - Assert4A(ContentVariation.Culture, "", "segment", false); + Assert4B(ContentVariation.Culture, string.Empty, null, false, true, false, true); + Assert4B(ContentVariation.Culture, string.Empty, string.Empty, false, true, false, true); + Assert4B(ContentVariation.Culture, string.Empty, "*", false, false, false, true); + Assert4A(ContentVariation.Culture, string.Empty, "segment", false); Assert4B(ContentVariation.Culture, "*", null, true, false, false, true); - Assert4B(ContentVariation.Culture, "*", "", true, false, false, true); + Assert4B(ContentVariation.Culture, "*", string.Empty, true, false, false, true); Assert4B(ContentVariation.Culture, "*", "*", true, false, false, true); Assert4A(ContentVariation.Culture, "*", "segment", false); Assert4A(ContentVariation.Culture, "culture", null, true); - Assert4A(ContentVariation.Culture, "culture", "", true); + Assert4A(ContentVariation.Culture, "culture", string.Empty, true); Assert4B(ContentVariation.Culture, "culture", "*", true, false, false, true); Assert4A(ContentVariation.Culture, "culture", "segment", false); + } - #endregion - - #region Segment - + private static void AssertForSegmentVariation() + { Assert4B(ContentVariation.Segment, null, null, true, true, true, true); - Assert4B(ContentVariation.Segment, null, "", true, true, true, true); + Assert4B(ContentVariation.Segment, null, string.Empty, true, true, true, true); Assert4B(ContentVariation.Segment, null, "*", true, false, false, true); Assert4A(ContentVariation.Segment, null, "segment", true); - Assert4B(ContentVariation.Segment, "", null, true, true, true, true); - Assert4B(ContentVariation.Segment, "", "", true, true, true, true); - Assert4B(ContentVariation.Segment, "", "*", true, false, false, true); - Assert4A(ContentVariation.Segment, "", "segment", true); + Assert4B(ContentVariation.Segment, string.Empty, null, true, true, true, true); + Assert4B(ContentVariation.Segment, string.Empty, string.Empty, true, true, true, true); + Assert4B(ContentVariation.Segment, string.Empty, "*", true, false, false, true); + Assert4A(ContentVariation.Segment, string.Empty, "segment", true); Assert4B(ContentVariation.Segment, "*", null, true, false, false, true); - Assert4B(ContentVariation.Segment, "*", "", true, false, false, true); + Assert4B(ContentVariation.Segment, "*", string.Empty, true, false, false, true); Assert4B(ContentVariation.Segment, "*", "*", true, false, false, true); Assert4B(ContentVariation.Segment, "*", "segment", true, false, false, true); Assert4A(ContentVariation.Segment, "culture", null, false); - Assert4A(ContentVariation.Segment, "culture", "", false); + Assert4A(ContentVariation.Segment, "culture", string.Empty, false); Assert4A(ContentVariation.Segment, "culture", "*", false); Assert4A(ContentVariation.Segment, "culture", "segment", false); + } - #endregion - - #region CultureAndSegment - + private static void AssertForCultureAndSegmentVariation() + { Assert4B(ContentVariation.CultureAndSegment, null, null, false, true, false, true); - Assert4B(ContentVariation.CultureAndSegment, null, "", false, true, false, true); + Assert4B(ContentVariation.CultureAndSegment, null, string.Empty, false, true, false, true); Assert4B(ContentVariation.CultureAndSegment, null, "*", false, false, false, true); Assert4B(ContentVariation.CultureAndSegment, null, "segment", false, true, false, true); - Assert4B(ContentVariation.CultureAndSegment, "", null, false, true, false, true); - Assert4B(ContentVariation.CultureAndSegment, "", "", false, true, false, true); - Assert4B(ContentVariation.CultureAndSegment, "", "*", false, false, false, true); - Assert4B(ContentVariation.CultureAndSegment, "", "segment", false, true, false, true); + Assert4B(ContentVariation.CultureAndSegment, string.Empty, null, false, true, false, true); + Assert4B(ContentVariation.CultureAndSegment, string.Empty, string.Empty, false, true, false, true); + Assert4B(ContentVariation.CultureAndSegment, string.Empty, "*", false, false, false, true); + Assert4B(ContentVariation.CultureAndSegment, string.Empty, "segment", false, true, false, true); Assert4B(ContentVariation.CultureAndSegment, "*", null, true, false, false, true); - Assert4B(ContentVariation.CultureAndSegment, "*", "", true, false, false, true); + Assert4B(ContentVariation.CultureAndSegment, "*", string.Empty, true, false, false, true); Assert4B(ContentVariation.CultureAndSegment, "*", "*", true, false, false, true); Assert4B(ContentVariation.CultureAndSegment, "*", "segment", true, false, false, true); Assert4B(ContentVariation.CultureAndSegment, "culture", null, true, true, true, true); - Assert4B(ContentVariation.CultureAndSegment, "culture", "", true, true, true, true); + Assert4B(ContentVariation.CultureAndSegment, "culture", string.Empty, true, true, true, true); Assert4B(ContentVariation.CultureAndSegment, "culture", "*", true, false, false, true); Assert4B(ContentVariation.CultureAndSegment, "culture", "segment", true, true, true, true); - - #endregion } /// /// Asserts the result of /// - /// - /// - /// /// Validate using Exact + Wildcards flags /// Validate using non Exact + no Wildcard flags /// Validate using Exact + no Wildcard flags /// Validate using non Exact + Wildcard flags - private static void Assert4B(ContentVariation variation, string culture, string segment, - bool exactAndWildcards, bool nonExactAndNoWildcards, bool exactAndNoWildcards, bool nonExactAndWildcards) + private static void Assert4B( + ContentVariation variation, + string culture, + string segment, + bool exactAndWildcards, + bool nonExactAndNoWildcards, + bool exactAndNoWildcards, + bool nonExactAndWildcards) { Assert.AreEqual(exactAndWildcards, variation.ValidateVariation(culture, segment, true, true, false)); Assert.AreEqual(nonExactAndNoWildcards, variation.ValidateVariation(culture, segment, false, false, false)); @@ -137,14 +142,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models /// Asserts the result of /// where expectedResult matches all combinations of Exact + Wildcard /// - /// - /// - /// - /// - private static void Assert4A(ContentVariation variation, string culture, string segment, bool expectedResult) - { + private static void Assert4A(ContentVariation variation, string culture, string segment, bool expectedResult) => Assert4B(variation, culture, segment, expectedResult, expectedResult, expectedResult, expectedResult); - } [Test] public void PropertyTests() @@ -245,10 +244,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void ContentNames() { - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .Build(); - var content = CreateContent(contentType); + Content content = CreateContent(contentType); const string langFr = "fr-FR"; const string langUk = "en-UK"; @@ -288,15 +287,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { const string langFr = "fr-FR"; - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("prop") .Build(); - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .Build(); contentType.AddPropertyType(propertyType); - var content = CreateContent(contentType); + Content content = CreateContent(contentType); // can set value // and get edited value, published is null @@ -378,7 +377,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.IsNull(content.GetValue("prop")); Assert.IsNull(content.GetValue("prop", published: true)); - var other = CreateContent(contentType, 2, "other"); + Content other = CreateContent(contentType, 2, "other"); Assert.Throws(() => other.SetValue("prop", "o")); // don't even try other.SetValue("prop", "o1", langFr); @@ -401,24 +400,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void ContentPublishValuesWithMixedPropertyTypeVariations() { - var propertyValidationService = GetPropertyValidationService(); + PropertyValidationService propertyValidationService = GetPropertyValidationService(); const string langFr = "fr-FR"; // content type varies by Culture // prop1 varies by Culture // prop2 is invariant - - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .Build(); contentType.Variations |= ContentVariation.Culture; - var variantPropType = new PropertyTypeBuilder() + PropertyType variantPropType = new PropertyTypeBuilder() .WithAlias("prop1") .WithVariations(ContentVariation.Culture) .WithMandatory(true) .Build(); - var invariantPropType = new PropertyTypeBuilder() + PropertyType invariantPropType = new PropertyTypeBuilder() .WithAlias("prop2") .WithVariations(ContentVariation.Nothing) .WithMandatory(true) @@ -426,24 +424,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models contentType.AddPropertyType(variantPropType); contentType.AddPropertyType(invariantPropType); - var content = CreateContent(contentType); + Content content = CreateContent(contentType); content.SetCultureName("hello", langFr); - //for this test we'll make the french culture the default one - this is needed for publishing invariant property values + // for this test we'll make the french culture the default one - this is needed for publishing invariant property values var langFrImpact = CultureImpact.Explicit(langFr, true); Assert.IsTrue(content.PublishCulture(langFrImpact)); // succeeds because names are ok (not validating properties here) - Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFrImpact));// fails because prop1 is mandatory + Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFrImpact)); // fails because prop1 is mandatory content.SetValue("prop1", "a", langFr); Assert.IsTrue(content.PublishCulture(langFrImpact)); // succeeds because names are ok (not validating properties here) - // fails because prop2 is mandatory and invariant and the item isn't published. + + // Fails because prop2 is mandatory and invariant and the item isn't published. // Invariant is validated against the default language except when there isn't a published version, in that case it's always validated. Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFrImpact)); content.SetValue("prop2", "x"); Assert.IsTrue(content.PublishCulture(langFrImpact)); // still ok... - Assert.IsTrue(propertyValidationService.IsPropertyDataValid(content, out _, langFrImpact));// now it's ok + Assert.IsTrue(propertyValidationService.IsPropertyDataValid(content, out _, langFrImpact)); // now it's ok Assert.AreEqual("a", content.GetValue("prop1", langFr, published: true)); Assert.AreEqual("x", content.GetValue("prop2", published: true)); @@ -456,15 +455,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models const string langUk = "en-UK"; const string langEs = "es-ES"; - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("prop") .Build(); - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .Build(); contentType.AddPropertyType(propertyType); - var content = CreateContent(contentType); + Content content = CreateContent(contentType); // change - now we vary by culture contentType.Variations |= ContentVariation.Culture; @@ -515,16 +514,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models [Test] public void IsDirtyTests() { - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("prop") .Build(); var prop = new Property(propertyType); - var contentType = new ContentTypeBuilder() + IContentType contentType = new ContentTypeBuilder() .WithAlias("contentType") .Build(); contentType.AddPropertyType(propertyType); - var content = CreateContent(contentType); + Content content = CreateContent(contentType); prop.SetValue("a"); Assert.AreEqual("a", prop.GetValue()); @@ -538,13 +537,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models Assert.IsTrue(content.IsDirty()); Assert.IsTrue(content.IsAnyUserPropertyDirty()); - // how can we tell which variation was dirty? + //// how can we tell which variation was dirty? } [Test] public void ValidationTests() { - var propertyType = new PropertyTypeBuilder() + PropertyType propertyType = new PropertyTypeBuilder() .WithAlias("prop") .WithSupportsPublishing(true) .Build(); @@ -554,7 +553,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models prop.SetValue("a"); Assert.AreEqual("a", prop.GetValue()); Assert.IsNull(prop.GetValue(published: true)); - var propertyValidationService = GetPropertyValidationService(); + PropertyValidationService propertyValidationService = GetPropertyValidationService(); Assert.IsTrue(propertyValidationService.IsPropertyValid(prop)); @@ -568,23 +567,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models prop.PublishValues(); } - private static Content CreateContent(IContentType contentType, int id = 1, string name = "content") - { - return new ContentBuilder() + private static Content CreateContent(IContentType contentType, int id = 1, string name = "content") => + new ContentBuilder() .WithId(id) .WithVersionId(1) .WithName(name) .WithContentType(contentType) .Build(); - } private static PropertyValidationService GetPropertyValidationService() { - var ioHelper = Mock.Of(); - var dataTypeService = Mock.Of(); - var localizedTextService = Mock.Of(); - var localizationService = Mock.Of(); - var shortStringHelper = Mock.Of(); + IIOHelper ioHelper = Mock.Of(); + IDataTypeService dataTypeService = Mock.Of(); + ILocalizedTextService localizedTextService = Mock.Of(); + ILocalizationService localizationService = Mock.Of(); + IShortStringHelper shortStringHelper = Mock.Of(); + IJsonSerializer jsonSerializer = Mock.Of(); var textBoxEditor = new TextboxPropertyEditor( NullLoggerFactory.Instance, @@ -592,8 +590,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models localizationService, ioHelper, shortStringHelper, - localizedTextService - ); + localizedTextService, + jsonSerializer); var serializer = new ConfigurationEditorJsonSerializer(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs index 48f26f210c..a5025b6ec5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs @@ -1,8 +1,10 @@ -using System.IO; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.IO; using System.Linq; -using Moq; using NUnit.Framework; -using Umbraco.Core.Hosting; using Umbraco.Core.Packaging; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Packaging @@ -14,7 +16,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Packaging private static FileInfo GetTestPackagePath(string packageName) { - var testPackagesDirName = Path.Combine("Umbraco.Core","Packaging","Packages"); + var testPackagesDirName = Path.Combine("Umbraco.Core", "Packaging", "Packages"); var testDir = TestContext.CurrentContext.TestDirectory.Split("bin")[0]; var path = Path.Combine(testDir, testPackagesDirName, packageName); return new FileInfo(path); @@ -27,7 +29,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Packaging var sut = new PackageExtraction(); // Act - var result = sut.ReadFilesFromArchive(GetTestPackagePath(PackageFileName), new[] { "Package.xml" }); + IEnumerable result = sut.ReadFilesFromArchive(GetTestPackagePath(PackageFileName), new[] { "Package.xml" }); // Assert Assert.AreEqual(1, result.Count()); @@ -40,7 +42,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Packaging var sut = new PackageExtraction(); // Act - var result = sut.FindMissingFiles(GetTestPackagePath(PackageFileName), new[] { "DoesNotExists.XYZ" }); + IEnumerable result = sut.FindMissingFiles(GetTestPackagePath(PackageFileName), new[] { "DoesNotExists.XYZ" }); // Assert Assert.AreEqual(1, result.Count()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs index bc54a7b999..438d2053e8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs @@ -1,8 +1,11 @@ -using Newtonsoft.Json; -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.Compose; @@ -15,15 +18,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore, - }; - private const string _contentGuid1 = "036ce82586a64dfba2d523a99ed80f58"; - private const string _contentGuid2 = "48288c21a38a40ef82deb3eda90a58f6"; - private const string _settingsGuid1 = "ffd35c4e2eea4900abfa5611b67b2492"; - private const string _subContentGuid1 = "4c44ce6b3a5c4f5f8f15e3dc24819a9e"; - private const string _subContentGuid2 = "a062c06d6b0b44ac892b35d90309c7f8"; - private const string _subSettingsGuid1 = "4d998d980ffa4eee8afdc23c4abd6d29"; + private const string ContentGuid1 = "036ce82586a64dfba2d523a99ed80f58"; + private const string ContentGuid2 = "48288c21a38a40ef82deb3eda90a58f6"; + private const string SettingsGuid1 = "ffd35c4e2eea4900abfa5611b67b2492"; + private const string SubContentGuid1 = "4c44ce6b3a5c4f5f8f15e3dc24819a9e"; + private const string SubContentGuid2 = "a062c06d6b0b44ac892b35d90309c7f8"; + private const string SubSettingsGuid1 = "4d998d980ffa4eee8afdc23c4abd6d29"; [Test] public void Cannot_Have_Null_Udi() @@ -38,14 +40,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { var guids = Enumerable.Range(0, 3).Select(x => Guid.NewGuid()).ToList(); var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; var json = GetBlockListJson(null); - var expected = ReplaceGuids(json, guids, _contentGuid1, _contentGuid2, _settingsGuid1); + var expected = ReplaceGuids(json, guids, ContentGuid1, ContentGuid2, SettingsGuid1); var component = new BlockEditorComponent(); - var result = component.ReplaceBlockListUdis(json, guidFactory); + var result = component.ReplaceBlockListUdis(json, GuidFactory); var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); @@ -60,9 +62,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; - var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var innerJson = GetBlockListJson(null, SubContentGuid1, SubContentGuid2, SubSettingsGuid1); // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -72,12 +74,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var json = GetBlockListJson(innerJsonEscaped); var component = new BlockEditorComponent(); - var result = component.ReplaceBlockListUdis(json, guidFactory); + var result = component.ReplaceBlockListUdis(json, GuidFactory); // the expected result is that the subFeatures data is no longer escaped - var expected = ReplaceGuids(GetBlockListJson(innerJson), guids, - _contentGuid1, _contentGuid2, _settingsGuid1, - _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var expected = ReplaceGuids( + GetBlockListJson(innerJson), + guids, + ContentGuid1, + ContentGuid2, + SettingsGuid1, + SubContentGuid1, + SubContentGuid2, + SubSettingsGuid1); var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); @@ -91,20 +99,26 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; // nested blocks without property value escaping used in the conversion - var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var innerJson = GetBlockListJson(null, SubContentGuid1, SubContentGuid2, SubSettingsGuid1); // get the json with the subFeatures as unescaped var json = GetBlockListJson(innerJson); - var expected = ReplaceGuids(GetBlockListJson(innerJson), guids, - _contentGuid1, _contentGuid2, _settingsGuid1, - _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var expected = ReplaceGuids( + GetBlockListJson(innerJson), + guids, + ContentGuid1, + ContentGuid2, + SettingsGuid1, + SubContentGuid1, + SubContentGuid2, + SubSettingsGuid1); var component = new BlockEditorComponent(); - var result = component.ReplaceBlockListUdis(json, guidFactory); + var result = component.ReplaceBlockListUdis(json, GuidFactory); var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); @@ -118,9 +132,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; - var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var innerJson = GetBlockListJson(null, SubContentGuid1, SubContentGuid2, SubSettingsGuid1); // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -132,12 +146,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var json = GetBlockListJson(complexEditorJsonEscaped); var component = new BlockEditorComponent(); - var result = component.ReplaceBlockListUdis(json, guidFactory); + var result = component.ReplaceBlockListUdis(json, GuidFactory); // the expected result is that the subFeatures data is no longer escaped - var expected = ReplaceGuids(GetBlockListJson(GetGridJson(innerJson)), guids, - _contentGuid1, _contentGuid2, _settingsGuid1, - _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + var expected = ReplaceGuids( + GetBlockListJson(GetGridJson(innerJson)), + guids, + ContentGuid1, + ContentGuid2, + SettingsGuid1, + SubContentGuid1, + SubContentGuid2, + SubSettingsGuid1); var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); @@ -146,10 +166,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors Assert.AreEqual(expectedJson, resultJson); } - private string GetBlockListJson(string subFeatures, - string contentGuid1 = _contentGuid1, - string contentGuid2 = _contentGuid2, - string settingsGuid1 = _settingsGuid1) + private string GetBlockListJson( + string subFeatures, + string contentGuid1 = ContentGuid1, + string contentGuid2 = ContentGuid2, + string settingsGuid1 = SettingsGuid1) { return @"{ ""layout"": @@ -254,8 +275,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var old = oldGuids[i]; json = json.Replace(old, newGuids[i].ToString("N")); } + return json; } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs index eb77ad2e1c..b232647d89 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs @@ -1,9 +1,9 @@ -using Moq; -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using Moq; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models.Blocks; @@ -18,50 +18,49 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [TestFixture] public class BlockListPropertyValueConverterTests { - private readonly Guid ContentKey1 = Guid.NewGuid(); - private readonly Guid ContentKey2 = Guid.NewGuid(); + private readonly Guid _contentKey1 = Guid.NewGuid(); + private readonly Guid _contentKey2 = Guid.NewGuid(); private const string ContentAlias1 = "Test1"; private const string ContentAlias2 = "Test2"; - private readonly Guid SettingKey1 = Guid.NewGuid(); - private readonly Guid SettingKey2 = Guid.NewGuid(); + private readonly Guid _settingKey1 = Guid.NewGuid(); + private readonly Guid _settingKey2 = Guid.NewGuid(); private const string SettingAlias1 = "Setting1"; private const string SettingAlias2 = "Setting2"; /// /// Setup mocks for IPublishedSnapshotAccessor /// - /// private IPublishedSnapshotAccessor GetPublishedSnapshotAccessor() { - var test1ContentType = Mock.Of(x => + IPublishedContentType test1ContentType = Mock.Of(x => x.IsElement == true - && x.Key == ContentKey1 + && x.Key == _contentKey1 && x.Alias == ContentAlias1); - var test2ContentType = Mock.Of(x => + IPublishedContentType test2ContentType = Mock.Of(x => x.IsElement == true - && x.Key == ContentKey2 + && x.Key == _contentKey2 && x.Alias == ContentAlias2); - var test3ContentType = Mock.Of(x => + IPublishedContentType test3ContentType = Mock.Of(x => x.IsElement == true - && x.Key == SettingKey1 + && x.Key == _settingKey1 && x.Alias == SettingAlias1); - var test4ContentType = Mock.Of(x => + IPublishedContentType test4ContentType = Mock.Of(x => x.IsElement == true - && x.Key == SettingKey2 + && x.Key == _settingKey2 && x.Alias == SettingAlias2); var contentCache = new Mock(); - contentCache.Setup(x => x.GetContentType(ContentKey1)).Returns(test1ContentType); - contentCache.Setup(x => x.GetContentType(ContentKey2)).Returns(test2ContentType); - contentCache.Setup(x => x.GetContentType(SettingKey1)).Returns(test3ContentType); - contentCache.Setup(x => x.GetContentType(SettingKey2)).Returns(test4ContentType); - var publishedSnapshot = Mock.Of(x => x.Content == contentCache.Object); - var publishedSnapshotAccessor = Mock.Of(x => x.PublishedSnapshot == publishedSnapshot); + contentCache.Setup(x => x.GetContentType(_contentKey1)).Returns(test1ContentType); + contentCache.Setup(x => x.GetContentType(_contentKey2)).Returns(test2ContentType); + contentCache.Setup(x => x.GetContentType(_settingKey1)).Returns(test3ContentType); + contentCache.Setup(x => x.GetContentType(_settingKey2)).Returns(test4ContentType); + IPublishedSnapshot publishedSnapshot = Mock.Of(x => x.Content == contentCache.Object); + IPublishedSnapshotAccessor publishedSnapshotAccessor = Mock.Of(x => x.PublishedSnapshot == publishedSnapshot); return publishedSnapshotAccessor; } private BlockListPropertyValueConverter CreateConverter() { - var publishedSnapshotAccessor = GetPublishedSnapshotAccessor(); + IPublishedSnapshotAccessor publishedSnapshotAccessor = GetPublishedSnapshotAccessor(); var publishedModelFactory = new NoopPublishedModelFactory(); var editor = new BlockListPropertyValueConverter( Mock.Of(), @@ -71,34 +70,36 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors private BlockListConfiguration ConfigForMany() => new BlockListConfiguration { - Blocks = new[] { - new BlockListConfiguration.BlockConfiguration - { - ContentElementTypeKey = ContentKey1, - SettingsElementTypeKey = SettingKey2 - }, - new BlockListConfiguration.BlockConfiguration - { - ContentElementTypeKey = ContentKey2, - SettingsElementTypeKey = SettingKey1 - } + Blocks = new[] + { + new BlockListConfiguration.BlockConfiguration + { + ContentElementTypeKey = _contentKey1, + SettingsElementTypeKey = _settingKey2 + }, + new BlockListConfiguration.BlockConfiguration + { + ContentElementTypeKey = _contentKey2, + SettingsElementTypeKey = _settingKey1 } + } }; private BlockListConfiguration ConfigForSingle() => new BlockListConfiguration { - Blocks = new[] { - new BlockListConfiguration.BlockConfiguration - { - ContentElementTypeKey = ContentKey1 - } + Blocks = new[] + { + new BlockListConfiguration.BlockConfiguration + { + ContentElementTypeKey = _contentKey1 } + } }; private IPublishedPropertyType GetPropertyType(BlockListConfiguration config) { var dataType = new PublishedDataType(1, "test", new Lazy(() => config)); - var propertyType = Mock.Of(x => + IPublishedPropertyType propertyType = Mock.Of(x => x.EditorAlias == Constants.PropertyEditors.Aliases.BlockList && x.DataType == dataType); return propertyType; @@ -107,7 +108,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Is_Converter_For() { - var editor = CreateConverter(); + BlockListPropertyValueConverter editor = CreateConverter(); Assert.IsTrue(editor.IsConverter(Mock.Of(x => x.EditorAlias == Constants.PropertyEditors.Aliases.BlockList))); Assert.IsFalse(editor.IsConverter(Mock.Of(x => x.EditorAlias == Constants.PropertyEditors.Aliases.NestedContent))); } @@ -115,13 +116,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Get_Value_Type_Multiple() { - var editor = CreateConverter(); - var config = ConfigForMany(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForMany(); var dataType = new PublishedDataType(1, "test", new Lazy(() => config)); - var propType = Mock.Of(x => x.DataType == dataType); + IPublishedPropertyType propType = Mock.Of(x => x.DataType == dataType); - var valueType = editor.GetPropertyValueType(propType); + Type valueType = editor.GetPropertyValueType(propType); // the result is always block list model Assert.AreEqual(typeof(BlockListModel), valueType); @@ -130,13 +131,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Get_Value_Type_Single() { - var editor = CreateConverter(); - var config = ConfigForSingle(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForSingle(); var dataType = new PublishedDataType(1, "test", new Lazy(() => config)); - var propType = Mock.Of(x => x.DataType == dataType); + IPublishedPropertyType propType = Mock.Of(x => x.DataType == dataType); - var valueType = editor.GetPropertyValueType(propType); + Type valueType = editor.GetPropertyValueType(propType); // the result is always block list model Assert.AreEqual(typeof(BlockListModel), valueType); @@ -145,10 +146,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Convert_Null_Empty() { - var editor = CreateConverter(); - var config = ConfigForMany(); - var propertyType = GetPropertyType(config); - var publishedElement = Mock.Of(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForMany(); + IPublishedPropertyType propertyType = GetPropertyType(config); + IPublishedElement publishedElement = Mock.Of(); string json = null; var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel; @@ -166,12 +167,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Convert_Valid_Empty_Json() { - var editor = CreateConverter(); - var config = ConfigForMany(); - var propertyType = GetPropertyType(config); - var publishedElement = Mock.Of(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForMany(); + IPublishedPropertyType propertyType = GetPropertyType(config); + IPublishedElement publishedElement = Mock.Of(); - var json = "{}"; + string json = "{}"; var converted = editor.ConvertIntermediateToObject(publishedElement, propertyType, PropertyCacheLevel.None, json, false) as BlockListModel; Assert.IsNotNull(converted); @@ -237,7 +238,7 @@ data: []}"; }, contentData: [ { - 'contentTypeKey': '" + ContentKey1 + @"', + 'contentTypeKey': '" + _contentKey1 + @"', 'key': '1304E1DD-0000-4396-84FE-8A399231CB3D' } ] @@ -252,12 +253,12 @@ data: []}"; [Test] public void Convert_Valid_Json() { - var editor = CreateConverter(); - var config = ConfigForMany(); - var propertyType = GetPropertyType(config); - var publishedElement = Mock.Of(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForMany(); + IPublishedPropertyType propertyType = GetPropertyType(config); + IPublishedElement publishedElement = Mock.Of(); - var json = @" + string json = @" { layout: { '" + Constants.PropertyEditors.Aliases.BlockList + @"': [ @@ -268,7 +269,7 @@ data: []}"; }, contentData: [ { - 'contentTypeKey': '" + ContentKey1 + @"', + 'contentTypeKey': '" + _contentKey1 + @"', 'udi': 'umb://element/1304E1DDAC87439684FE8A399231CB3D' } ] @@ -277,7 +278,7 @@ data: []}"; Assert.IsNotNull(converted); Assert.AreEqual(1, converted.Count); - var item0 = converted[0].Content; + IPublishedElement item0 = converted[0].Content; Assert.AreEqual(Guid.Parse("1304E1DD-AC87-4396-84FE-8A399231CB3D"), item0.Key); Assert.AreEqual("Test1", item0.ContentType.Alias); Assert.IsNull(converted[0].Settings); @@ -287,12 +288,12 @@ data: []}"; [Test] public void Get_Data_From_Layout_Item() { - var editor = CreateConverter(); - var config = ConfigForMany(); - var propertyType = GetPropertyType(config); - var publishedElement = Mock.Of(); + BlockListPropertyValueConverter editor = CreateConverter(); + BlockListConfiguration config = ConfigForMany(); + IPublishedPropertyType propertyType = GetPropertyType(config); + IPublishedElement publishedElement = Mock.Of(); - var json = @" + string json = @" { layout: { '" + Constants.PropertyEditors.Aliases.BlockList + @"': [ @@ -308,29 +309,29 @@ data: []}"; }, contentData: [ { - 'contentTypeKey': '" + ContentKey1 + @"', + 'contentTypeKey': '" + _contentKey1 + @"', 'udi': 'umb://element/1304E1DDAC87439684FE8A399231CB3D' }, { - 'contentTypeKey': '" + ContentKey2 + @"', + 'contentTypeKey': '" + _contentKey2 + @"', 'udi': 'umb://element/E05A034704424AB3A520E048E6197E79' }, { - 'contentTypeKey': '" + ContentKey2 + @"', + 'contentTypeKey': '" + _contentKey2 + @"', 'udi': 'umb://element/0A4A416E547D464FABCC6F345C17809A' } ], settingsData: [ { - 'contentTypeKey': '" + SettingKey1 + @"', + 'contentTypeKey': '" + _settingKey1 + @"', 'udi': 'umb://element/63027539B0DB45E7B70459762D4E83DD' }, { - 'contentTypeKey': '" + SettingKey2 + @"', + 'contentTypeKey': '" + _settingKey2 + @"', 'udi': 'umb://element/1F613E26CE274898908A561437AF5100' }, { - 'contentTypeKey': '" + SettingKey2 + @"', + 'contentTypeKey': '" + _settingKey2 + @"', 'udi': 'umb://element/BCF4BA3DA40C496C93EC58FAC85F18B9' } ], @@ -341,42 +342,42 @@ data: []}"; Assert.IsNotNull(converted); Assert.AreEqual(2, converted.Count); - var item0 = converted[0]; + BlockListItem item0 = converted[0]; Assert.AreEqual(Guid.Parse("1304E1DD-AC87-4396-84FE-8A399231CB3D"), item0.Content.Key); Assert.AreEqual("Test1", item0.Content.ContentType.Alias); Assert.AreEqual(Guid.Parse("1F613E26CE274898908A561437AF5100"), item0.Settings.Key); Assert.AreEqual("Setting2", item0.Settings.ContentType.Alias); - var item1 = converted[1]; + BlockListItem item1 = converted[1]; Assert.AreEqual(Guid.Parse("0A4A416E-547D-464F-ABCC-6F345C17809A"), item1.Content.Key); Assert.AreEqual("Test2", item1.Content.ContentType.Alias); Assert.AreEqual(Guid.Parse("63027539B0DB45E7B70459762D4E83DD"), item1.Settings.Key); Assert.AreEqual("Setting1", item1.Settings.ContentType.Alias); - } [Test] public void Data_Item_Removed_If_Removed_From_Config() { - var editor = CreateConverter(); + BlockListPropertyValueConverter editor = CreateConverter(); // The data below expects that ContentKey1 + ContentKey2 + SettingsKey1 + SettingsKey2 exist but only ContentKey2 exists so // the data should all be filtered. var config = new BlockListConfiguration { - Blocks = new[] { + Blocks = new[] + { new BlockListConfiguration.BlockConfiguration { - ContentElementTypeKey = ContentKey2, + ContentElementTypeKey = _contentKey2, SettingsElementTypeKey = null } } }; - var propertyType = GetPropertyType(config); - var publishedElement = Mock.Of(); + IPublishedPropertyType propertyType = GetPropertyType(config); + IPublishedElement publishedElement = Mock.Of(); - var json = @" + string json = @" { layout: { '" + Constants.PropertyEditors.Aliases.BlockList + @"': [ @@ -392,29 +393,29 @@ data: []}"; }, contentData: [ { - 'contentTypeKey': '" + ContentKey1 + @"', + 'contentTypeKey': '" + _contentKey1 + @"', 'udi': 'umb://element/1304E1DDAC87439684FE8A399231CB3D' }, { - 'contentTypeKey': '" + ContentKey2 + @"', + 'contentTypeKey': '" + _contentKey2 + @"', 'udi': 'umb://element/E05A034704424AB3A520E048E6197E79' }, { - 'contentTypeKey': '" + ContentKey2 + @"', + 'contentTypeKey': '" + _contentKey2 + @"', 'udi': 'umb://element/0A4A416E547D464FABCC6F345C17809A' } ], settingsData: [ { - 'contentTypeKey': '" + SettingKey1 + @"', + 'contentTypeKey': '" + _settingKey1 + @"', 'udi': 'umb://element/63027539B0DB45E7B70459762D4E83DD' }, { - 'contentTypeKey': '" + SettingKey2 + @"', + 'contentTypeKey': '" + _settingKey2 + @"', 'udi': 'umb://element/1F613E26CE274898908A561437AF5100' }, { - 'contentTypeKey': '" + SettingKey2 + @"', + 'contentTypeKey': '" + _settingKey2 + @"', 'udi': 'umb://element/BCF4BA3DA40C496C93EC58FAC85F18B9' } ], @@ -425,12 +426,10 @@ data: []}"; Assert.IsNotNull(converted); Assert.AreEqual(1, converted.Count); - var item0 = converted[0]; + BlockListItem item0 = converted[0]; Assert.AreEqual(Guid.Parse("0A4A416E-547D-464F-ABCC-6F345C17809A"), item0.Content.Key); Assert.AreEqual("Test2", item0.Content.ContentType.Alias); Assert.IsNull(item0.Settings); - } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs index 14aa628f88..1264e24e58 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs @@ -1,14 +1,18 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; -using NUnit.Framework; using Newtonsoft.Json.Linq; +using NUnit.Framework; using Umbraco.Core.IO; -using NUnit.Framework.Internal; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors @@ -16,13 +20,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [TestFixture] public class ColorListValidatorTest { - private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + private readonly ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; [Test] public void Only_Tests_On_JArray() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + "hello", + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(0, result.Count()); } @@ -30,7 +45,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray("hello", "world"), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(0, result.Count()); } @@ -38,12 +64,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Validates_Color_Vals() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate(new JArray( - JObject.FromObject(new { value = "CC0000" }), - JObject.FromObject(new { value = "zxcvzxcvxzcv" }), - JObject.FromObject(new { value = "ABC" }), - JObject.FromObject(new { value = "1234567" })), - null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray( + JObject.FromObject(new { value = "CC0000" }), + JObject.FromObject(new { value = "zxcvzxcvxzcv" }), + JObject.FromObject(new { value = "ABC" }), + JObject.FromObject(new { value = "1234567" })), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs index 6db561dfe9..f78a72b42a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ConvertersTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Configuration; @@ -45,7 +48,6 @@ namespace Umbraco.Tests.Published }, Mock.Of()); register.AddTransient(f => factory); - var cacheMock = new Mock(); var cacheContent = new Dictionary(); cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => @@ -62,11 +64,24 @@ namespace Umbraco.Tests.Published var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); - var dataType1 = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), + var dataType1 = new DataType( + new VoidEditor( + NullLoggerFactory.Instance, + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), serializer) { Id = 1 }; - var dataType2 = new DataType(new VoidEditor("2", NullLoggerFactory.Instance, Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of()), + var dataType2 = new DataType( + new VoidEditor( + "2", + NullLoggerFactory.Instance, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), serializer) { Id = 2 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new[] { dataType1, dataType2 }); @@ -87,10 +102,16 @@ namespace Umbraco.Tests.Published IPublishedContentType contentType2 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1003, "content2", t => CreatePropertyTypes(t, 2)); - var element1 = new PublishedElement(elementType1, Guid.NewGuid(), - new Dictionary { { "prop1", "val1" } }, false); - var element2 = new PublishedElement(elementType2, Guid.NewGuid(), - new Dictionary { { "prop2", "1003" } }, false); + var element1 = new PublishedElement( + elementType1, + Guid.NewGuid(), + new Dictionary { { "prop1", "val1" } }, + false); + var element2 = new PublishedElement( + elementType2, + Guid.NewGuid(), + new Dictionary { { "prop2", "1003" } }, + false); var cnt1 = new SolidPublishedContent(contentType1) { Id = 1003, @@ -115,9 +136,11 @@ namespace Umbraco.Tests.Published // can get the actual property Clr type // ie ModelType gets properly mapped by IPublishedContentModelFactory // must test ModelClrType with special equals 'cos they are not ref-equals - Assert.IsTrue(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("content1")), + Assert.IsTrue(ModelType.Equals( + typeof(IEnumerable<>).MakeGenericType(ModelType.For("content1")), contentType2.GetPropertyType("prop2").ModelClrType)); - Assert.AreEqual(typeof(IEnumerable), + Assert.AreEqual( + typeof(IEnumerable), contentType2.GetPropertyType("prop2").ClrType); // can create a model for an element @@ -133,9 +156,9 @@ namespace Umbraco.Tests.Published // and get direct property Assert.IsInstanceOf( model2.Value(Mock.Of(), "prop2")); - Assert.AreEqual(1, - ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value(Mock.Of(), - "prop2")).Length); + Assert.AreEqual( + 1, + ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value(Mock.Of(), "prop2")).Length); // and get model property Assert.IsInstanceOf>(mmodel2.Prop2); @@ -174,15 +197,21 @@ namespace Umbraco.Tests.Published public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Elements; - public override object ConvertSourceToIntermediate(IPublishedElement owner, - IPublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToIntermediate( + IPublishedElement owner, + IPublishedPropertyType propertyType, + object source, + bool preview) { var s = source as string; return s?.Split(',').Select(int.Parse).ToArray() ?? Array.Empty(); } - public override object ConvertIntermediateToObject(IPublishedElement owner, - IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, + public override object ConvertIntermediateToObject( + IPublishedElement owner, + IPublishedPropertyType propertyType, + PropertyCacheLevel referenceCacheLevel, + object inter, bool preview) => ((int[])inter).Select(x => (PublishedSnapshotTestObjects.TestContentModel1)_publishedSnapshotAccessor.PublishedSnapshot.Content .GetById(x)).ToArray(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs index 0fa864ae06..d29ba45531 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs @@ -1,39 +1,45 @@ -using Moq; -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; using static Umbraco.Core.Models.Property; -using Umbraco.Core.Serialization; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { [TestFixture] public class DataValueReferenceFactoryCollectionTests { - IDataTypeService DataTypeService { get; } = Mock.Of(); + private IDataTypeService DataTypeService { get; } = Mock.Of(); + private IIOHelper IOHelper { get; } = Mock.Of(); - ILocalizedTextService LocalizedTextService { get; } = Mock.Of(); - ILocalizationService LocalizationService { get; } = Mock.Of(); - IShortStringHelper ShortStringHelper { get; } = Mock.Of(); + + private ILocalizedTextService LocalizedTextService { get; } = Mock.Of(); + + private ILocalizationService LocalizationService { get; } = Mock.Of(); + + private IShortStringHelper ShortStringHelper { get; } = Mock.Of(); + + private IJsonSerializer JsonSerializer { get; } = new JsonNetSerializer(); [Test] public void GetAllReferences_All_Variants_With_IDataValueReferenceFactory() { var collection = new DataValueReferenceFactoryCollection(new TestDataValueReferenceFactory().Yield()); - // label does not implement IDataValueReference var labelEditor = new LabelPropertyEditor( NullLoggerFactory.Instance, @@ -41,8 +47,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors DataTypeService, LocalizedTextService, LocalizationService, - ShortStringHelper - ); + ShortStringHelper, + JsonSerializer); var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(labelEditor.Yield())); var trackedUdi1 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); @@ -72,13 +78,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors Segment = "A", EditedValue = trackedUdi3 }, + // Ignored (no culture) new PropertyValue { Segment = "A", EditedValue = trackedUdi4 }, - // duplicate + + // Duplicate new PropertyValue { Culture = "en-US", @@ -91,7 +99,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { property }; - var result = collection.GetAllReferences(properties, propertyEditors); + IEnumerable result = collection.GetAllReferences(properties, propertyEditors); Assert.AreEqual(2, result.Count()); Assert.AreEqual(trackedUdi2, result.ElementAt(0).Udi.ToString()); @@ -110,8 +118,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors LocalizationService, IOHelper, ShortStringHelper, - LocalizedTextService - ); + LocalizedTextService, + JsonSerializer); var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(mediaPicker.Yield())); var trackedUdi1 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); @@ -141,13 +149,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors Segment = "A", EditedValue = trackedUdi3 }, + // Ignored (no culture) new PropertyValue { Segment = "A", EditedValue = trackedUdi4 }, - // duplicate + + // Duplicate new PropertyValue { Culture = "en-US", @@ -160,7 +170,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { property }; - var result = collection.GetAllReferences(properties, propertyEditors); + IEnumerable result = collection.GetAllReferences(properties, propertyEditors); Assert.AreEqual(2, result.Count()); Assert.AreEqual(trackedUdi2, result.ElementAt(0).Udi.ToString()); @@ -179,8 +189,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors LocalizationService, IOHelper, ShortStringHelper, - LocalizedTextService - ); + LocalizedTextService, + JsonSerializer); var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(mediaPicker.Yield())); var trackedUdi1 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); @@ -198,12 +208,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { EditedValue = trackedUdi1 }, + // Ignored (has culture) new PropertyValue { Culture = "en-US", EditedValue = trackedUdi2 }, + // Ignored (has culture) new PropertyValue { @@ -216,7 +228,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors Segment = "A", EditedValue = trackedUdi4 }, - // duplicate + + // Duplicate new PropertyValue { Segment = "B", @@ -228,7 +241,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { property }; - var result = collection.GetAllReferences(properties, propertyEditors); + IEnumerable result = collection.GetAllReferences(properties, propertyEditors); Assert.AreEqual(2, result.Count()); Assert.AreEqual(trackedUdi1, result.ElementAt(0).Udi.ToString()); @@ -245,14 +258,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { public IEnumerable GetReferences(object value) { - // This is the same as the media picker, it will just try to parse the value directly as a UDI - + // This is the same as the media picker, it will just try to parse the value directly as a UDI. var asString = value is string str ? str : value?.ToString(); - if (string.IsNullOrEmpty(asString)) yield break; + if (string.IsNullOrEmpty(asString)) + { + yield break; + } - if (UdiParser.TryParse(asString, out var udi)) + if (UdiParser.TryParse(asString, out Udi udi)) + { yield return new UmbracoEntityReference(udi); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs index 44c53382d9..230be138ce 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs @@ -1,14 +1,18 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; -using NUnit.Framework; using Newtonsoft.Json.Linq; +using NUnit.Framework; using Umbraco.Core.IO; -using Umbraco.Core.Logging; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors @@ -16,12 +20,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [TestFixture] public class EnsureUniqueValuesValidatorTest { - private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + private readonly ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + [Test] public void Only_Tests_On_JArray() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + "hello", + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(0, result.Count()); } @@ -29,7 +45,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray("hello", "world"), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(0, result.Count()); } @@ -37,7 +64,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Allows_Unique_Values() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" })), null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray( + JObject.FromObject(new { value = "hello" }), + JObject.FromObject(new { value = "world" })), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(0, result.Count()); } @@ -45,8 +85,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Does_Not_Allow_Multiple_Values() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "hello" })), - null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray( + JObject.FromObject(new { value = "hello" }), + JObject.FromObject(new { value = "hello" })), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(1, result.Count()); } @@ -54,12 +106,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void Validates_Multiple_Duplicate_Values() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray( - JObject.FromObject(new { value = "hello" }), - JObject.FromObject(new { value = "hello" }), - JObject.FromObject(new { value = "world" }), - JObject.FromObject(new { value = "world" })), - null, new ColorPickerPropertyEditor(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); + IEnumerable result = + validator.Validate( + new JArray( + JObject.FromObject(new { value = "hello" }), + JObject.FromObject(new { value = "hello" }), + JObject.FromObject(new { value = "world" }), + JObject.FromObject(new { value = "world" })), + null, + new ColorPickerPropertyEditor( + _loggerFactory, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs index 5b3e3f1ff6..0b069d9662 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs @@ -1,11 +1,13 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; @@ -30,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void DropDownMultipleValueEditor_Format_Data_For_Cache() { var serializer = new ConfigurationEditorJsonSerializer(); - var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Configuration = new ValueListConfiguration { @@ -46,14 +48,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var dataTypeServiceMock = new Mock(); dataTypeServiceMock - .Setup(x=>x.GetDataType(It.IsAny())) + .Setup(x => x.GetDataType(It.IsAny())) .Returns(dataType); var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 1,Value 2,Value 3"); - var valueEditor = dataType.Editor.GetValueEditor(); - ((DataValueEditor) valueEditor).Configuration = dataType.Configuration; + IDataValueEditor valueEditor = dataType.Editor.GetValueEditor(); + ((DataValueEditor)valueEditor).Configuration = dataType.Configuration; var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeServiceMock.Object); Assert.AreEqual("Value 1,Value 2,Value 3", result); @@ -63,7 +65,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors public void DropDownValueEditor_Format_Data_For_Cache() { var serializer = new ConfigurationEditorJsonSerializer(); - var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Configuration = new ValueListConfiguration { @@ -78,9 +80,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors }; var dataTypeServiceMock = new Mock(); - dataTypeServiceMock - .Setup(x=>x.GetDataType(It.IsAny())) - .Returns(dataType); + dataTypeServiceMock + .Setup(x => x.GetDataType(It.IsAny())) + .Returns(dataType); var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 2"); @@ -97,17 +99,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors // (that should be fixed with proper injection) var textService = new Mock(); textService.Setup(x => x.Localize(It.IsAny(), It.IsAny(), It.IsAny>())).Returns("blah"); - //var appContext = new ApplicationContext( - // new DatabaseContext(TestObjects.GetIDatabaseFactoryMock(), logger, Mock.Of(), Mock.Of()), - // new ServiceContext( - // localizedTextService: textService.Object - // ), - // Mock.Of(), - // new ProfilingLogger(logger, Mock.Of())) - //{ - // //IsReady = true - //}; - //Current.ApplicationContext = appContext; + + //// var appContext = new ApplicationContext( + //// new DatabaseContext(TestObjects.GetIDatabaseFactoryMock(), logger, Mock.Of(), Mock.Of()), + //// new ServiceContext( + //// localizedTextService: textService.Object + //// ), + //// Mock.Of(), + //// new ProfilingLogger(logger, Mock.Of())) + //// { + //// //IsReady = true + //// }; + //// Current.ApplicationContext = appContext; var configuration = new ValueListConfiguration { @@ -121,7 +124,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var editor = new ValueListConfigurationEditor(Mock.Of(), Mock.Of()); - var result = editor.ToConfigurationEditor(configuration); + Dictionary result = editor.ToConfigurationEditor(configuration); // 'result' is meant to be serialized, is built with anonymous objects // so we cannot really test what's in it - but by serializing it diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs index 930f1b623f..022e19c18e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs @@ -1,15 +1,13 @@ -using Newtonsoft.Json; -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Newtonsoft.Json; +using NUnit.Framework; using Umbraco.Web.Compose; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { - [TestFixture] public class NestedContentPropertyComponentTests { @@ -24,9 +22,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void No_Nesting() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; var json = @"[ {""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1"",""ncContentTypeAlias"":""nested"",""text"":""woot""}, @@ -37,7 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors .Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString()); var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, false, guidFactory); + var result = component.CreateNestedContentKeys(json, false, GuidFactory); Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString()); } @@ -45,9 +43,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void One_Level_Nesting_Unescaped() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; var json = @"[{ ""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"", @@ -81,7 +79,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors .Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString()); var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, false, guidFactory); + var result = component.CreateNestedContentKeys(json, false, GuidFactory); Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString()); } @@ -89,9 +87,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void One_Level_Nesting_Escaped() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -129,7 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors .Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString()); var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, false, guidFactory); + var result = component.CreateNestedContentKeys(json, false, GuidFactory); Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString()); } @@ -137,9 +135,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Nested_In_Complex_Editor_Escaped() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -212,7 +210,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors }] }"; - var json = @"[{ ""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"", ""name"": ""Item 1"", @@ -234,18 +231,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors .Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString()); var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, false, guidFactory); + var result = component.CreateNestedContentKeys(json, false, GuidFactory); Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString()); } - [Test] public void No_Nesting_Generates_Keys_For_Missing_Items() { - var guids = new[] { Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; var json = @"[ {""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1 my key wont change"",""ncContentTypeAlias"":""nested"",""text"":""woot""}, @@ -253,7 +249,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors ]"; var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, true, guidFactory); + var result = component.CreateNestedContentKeys(json, true, GuidFactory); // Ensure the new GUID is put in a key into the JSON Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString())); @@ -265,9 +261,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void One_Level_Nesting_Escaped_Generates_Keys_For_Missing_Items() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -296,7 +292,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors ]"; var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, true, guidFactory); + var result = component.CreateNestedContentKeys(json, true, GuidFactory); // Ensure the new GUID is put in a key into the JSON for each item Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString())); @@ -307,9 +303,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Nested_In_Complex_Editor_Escaped_Generates_Keys_For_Missing_Items() { - var guids = new[] { Guid.NewGuid(), Guid.NewGuid() }; + Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid() }; var guidCounter = 0; - Func guidFactory = () => guids[guidCounter++]; + Guid GuidFactory() => guids[guidCounter++]; // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing // and this is how to do that, the result will also include quotes around it. @@ -381,7 +377,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors }] }"; - var json = @"[{ ""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"", ""name"": ""Item 1"", @@ -396,7 +391,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors ]"; var component = new NestedContentPropertyComponent(); - var result = component.CreateNestedContentKeys(json, true, guidFactory); + var result = component.CreateNestedContentKeys(json, true, GuidFactory); // Ensure the new GUID is put in a key into the JSON for each item Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString())); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs index be72eff1e7..94e68af881 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Moq; @@ -9,8 +12,6 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors @@ -21,15 +22,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors // see notes in the converter // only ONE date format is expected here - //[TestCase("2012-11-10", true)] - //[TestCase("2012/11/10", true)] - //[TestCase("10/11/2012", true)] - //[TestCase("11/10/2012", false)] - //[TestCase("Sat 10, Nov 2012", true)] - //[TestCase("Saturday 10, Nov 2012", true)] - //[TestCase("Sat 10, November 2012", true)] - //[TestCase("Saturday 10, November 2012", true)] - //[TestCase("2012-11-10 13:14:15", true)] + // [TestCase("2012-11-10", true)] + // [TestCase("2012/11/10", true)] + // [TestCase("10/11/2012", true)] + // [TestCase("11/10/2012", false)] + // [TestCase("Sat 10, Nov 2012", true)] + // [TestCase("Saturday 10, Nov 2012", true)] + // [TestCase("Sat 10, November 2012", true)] + // [TestCase("Saturday 10, November 2012", true)] + // [TestCase("2012-11-10 13:14:15", true)] [TestCase("2012-11-10 13:14:15", true)] [TestCase("2012-11-10T13:14:15", true)] [TestCase("", false)] @@ -40,9 +41,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var result = converter.ConvertSourceToIntermediate(null, null, date, false); // does not use type for conversion if (expected) - Assert.AreEqual(dateTime.Date, ((DateTime) result).Date); + { + Assert.AreEqual(dateTime.Date, ((DateTime)result).Date); + } else + { Assert.AreNotEqual(dateTime.Date, ((DateTime)result).Date); + } } [TestCase("TRUE", true)] @@ -96,10 +101,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors }))); var publishedPropType = new PublishedPropertyType( - new PublishedContentType(Guid.NewGuid(),1234, "test", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing), + new PublishedContentType(Guid.NewGuid(), 1234, "test", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing), new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar) { DataTypeId = 123 }, new PropertyValueConverterCollection(Enumerable.Empty()), - Mock.Of(), mockPublishedContentTypeFactory.Object); + Mock.Of(), + mockPublishedContentTypeFactory.Object); var converter = new FlexibleDropdownPropertyValueConverter(); var inter = converter.ConvertSourceToIntermediate(null, publishedPropType, value, false); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs index 4fe391d1e9..a351439c90 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -1,10 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Strings; @@ -24,23 +24,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(value); - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.String); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.String); - var result = valueEditor.ToEditor(prop); + object result = valueEditor.ToEditor(prop); Assert.AreEqual(isOk, !(result is string)); - } [TestCase("STRING", "hello", "hello")] [TestCase("TEXT", "hello", "hello")] [TestCase("INT", "123", 123)] - [TestCase("INT", "", null)] //test empty string for int - [TestCase("DATETIME", "", null)] //test empty string for date + [TestCase("INT", "", null)] // test empty string for int + [TestCase("DATETIME", "", null)] // test empty string for date public void Value_Editor_Can_Convert_To_Clr_Type(string valueType, string val, object expected) { - var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); - var result = valueEditor.TryConvertValueToCrlType(val); + Attempt result = valueEditor.TryConvertValueToCrlType(val); Assert.IsTrue(result.Success); Assert.AreEqual(expected, result.Result); } @@ -50,9 +49,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var result = valueEditor.TryConvertValueToCrlType("12.34"); + Attempt result = valueEditor.TryConvertValueToCrlType("12.34"); Assert.IsTrue(result.Success); Assert.AreEqual(12.34M, result.Result); } @@ -60,9 +59,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Other_Separator() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var result = valueEditor.TryConvertValueToCrlType("12,34"); + Attempt result = valueEditor.TryConvertValueToCrlType("12,34"); Assert.IsTrue(result.Success); Assert.AreEqual(12.34M, result.Result); } @@ -70,9 +69,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Empty_String() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var result = valueEditor.TryConvertValueToCrlType(string.Empty); + Attempt result = valueEditor.TryConvertValueToCrlType(string.Empty); Assert.IsTrue(result.Success); Assert.IsNull(result.Result); } @@ -80,9 +79,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Date_Clr_Type() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); - var result = valueEditor.TryConvertValueToCrlType("2010-02-05"); + Attempt result = valueEditor.TryConvertValueToCrlType("2010-02-05"); Assert.IsTrue(result.Success); Assert.AreEqual(new DateTime(2010, 2, 5), result.Result); } @@ -90,54 +89,54 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [TestCase(ValueTypes.String, "hello", "hello")] [TestCase(ValueTypes.Text, "hello", "hello")] [TestCase(ValueTypes.Integer, 123, "123")] - [TestCase(ValueTypes.Integer, "", "")] //test empty string for int - [TestCase(ValueTypes.DateTime, "", "")] //test empty string for date + [TestCase(ValueTypes.Integer, "", "")] // test empty string for int + [TestCase(ValueTypes.DateTime, "", "")] // test empty string for date public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected) { var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(val); - var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); - var result = valueEditor.ToEditor(prop); + object result = valueEditor.ToEditor(prop); Assert.AreEqual(expected, result); } [Test] public void Value_Editor_Can_Serialize_Decimal_Value() { - var value = 12.34M; - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + decimal value = 12.34M; + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(value); - var result = valueEditor.ToEditor(prop); + object result = valueEditor.ToEditor(prop); Assert.AreEqual("12.34", result); } [Test] public void Value_Editor_Can_Serialize_Decimal_Value_With_Empty_String() { - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(string.Empty); - var result = valueEditor.ToEditor(prop); + object result = valueEditor.ToEditor(prop); Assert.AreEqual(string.Empty, result); } [Test] public void Value_Editor_Can_Serialize_Date_Value() { - var now = DateTime.Now; - var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); + DateTime now = DateTime.Now; + DataValueEditor valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Date)); prop.SetValue(now); - var result = valueEditor.ToEditor(prop); + object result = valueEditor.ToEditor(prop); Assert.AreEqual(now.ToIsoString(), result); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs index a46662c3a1..352a1f45cd 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -1,11 +1,13 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -20,8 +22,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [TestFixture] public class ConvertersTests { - #region SimpleConverter1 - [Test] public void SimpleConverter1Test() { @@ -32,8 +32,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType( + new VoidEditor( + Mock.Of(), + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -44,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); } - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + IPublishedContentType elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); @@ -93,10 +99,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published => ((int)inter).ToString(); } - #endregion - - #region SimpleConverter2 - [Test] public void SimpleConverter2Test() { @@ -107,7 +109,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); var publishedSnapshotAccessorMock = new Mock(); publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); - var publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; + IPublishedSnapshotAccessor publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] { @@ -116,8 +118,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType( + new VoidEditor( + Mock.Of(), + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -128,11 +136,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); } - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + IPublishedContentType elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - var cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); + IPublishedContentType cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); var cnt1 = new SolidPublishedContent(cntType1) { Id = 1234 }; cacheContent[cnt1.Id] = cnt1; @@ -157,10 +165,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); public Type GetPropertyValueType(IPublishedPropertyType propertyType) - // the first version would be the "generic" version, but say we want to be more precise + + // The first version would be the "generic" version, but say we want to be more precise // and return: whatever Clr type is generated for content type with alias "cnt1" -- which // we cannot really typeof() at the moment because it has not been generated, hence ModelType. - // => typeof (IPublishedContent); + // => typeof(IPublishedContent); => ModelType.For("cnt1"); public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) @@ -175,7 +184,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) => ((int)inter).ToString(); } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs index 9b4f377247..456cfeb170 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using NUnit.Framework; @@ -27,7 +30,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [Test] public void TypeToStringTests() { - var type = typeof(int); + Type type = typeof(int); Assert.AreEqual("System.Int32", type.ToString()); Assert.AreEqual("System.Int32[]", type.MakeArrayType().ToString()); Assert.AreEqual("System.Collections.Generic.IEnumerable`1[System.Int32[]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).ToString()); @@ -36,10 +39,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [Test] public void TypeFullNameTests() { - var type = typeof(int); + Type type = typeof(int); Assert.AreEqual("System.Int32", type.FullName); Assert.AreEqual("System.Int32[]", type.MakeArrayType().FullName); - // note the inner assembly qualified name + + // Note the inner assembly qualified name Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32[], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).FullName); } @@ -48,17 +52,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published { var map = new Dictionary { - { "alias1", typeof (PublishedSnapshotTestObjects.TestElementModel1) }, - { "alias2", typeof (PublishedSnapshotTestObjects.TestElementModel2) }, + { "alias1", typeof(PublishedSnapshotTestObjects.TestElementModel1) }, + { "alias2", typeof(PublishedSnapshotTestObjects.TestElementModel2) }, }; - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", + Assert.AreEqual( + "Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", ModelType.Map(ModelType.For("alias1"), map).ToString()); - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", + Assert.AreEqual( + "Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", + Assert.AreEqual( + "System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", + Assert.AreEqual( + "System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index 67c294f5a9..102dd6388e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -27,14 +30,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published { private (IPublishedContentType, IPublishedContentType) CreateContentTypes() { - var logger = Mock.Of>(); - var loggerFactory = NullLoggerFactory.Instance; - var profiler = Mock.Of(); + ILogger logger = Mock.Of>(); + NullLoggerFactory loggerFactory = NullLoggerFactory.Instance; + IProfiler profiler = Mock.Of(); var proflog = new ProfilingLogger(logger, profiler); - var localizationService = Mock.Of(); + ILocalizationService localizationService = Mock.Of(); PropertyEditorCollection editors = null; - var editor = new NestedContentPropertyEditor(loggerFactory, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); + var editor = new NestedContentPropertyEditor(loggerFactory, new Lazy(() => editors), Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()); editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor })); var serializer = new ConfigurationEditorJsonSerializer(); @@ -67,14 +70,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published } }; - var dataType3 = new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType3 = new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 3 }; // mocked dataservice returns nested content preValues var dataTypeServiceMock = new Mock(); - dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2, dataType3}); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new[] { dataType1, dataType2, dataType3 }); var publishedModelFactory = new Mock(); @@ -93,7 +96,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published .Returns((IPublishedElement element) => { if (element.ContentType.Alias.InvariantEquals("contentN1")) + { return new TestElementModel(element); + } + return element; }); @@ -101,11 +107,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published publishedModelFactory .Setup(x => x.CreateModelList(It.IsAny())) .Returns((string alias) => - { - return alias == "contentN1" + alias == "contentN1" ? (IList)new List() - : (IList)new List(); - }); + : (IList)new List()); var contentCache = new Mock(); var publishedSnapshot = new Mock(); @@ -145,16 +149,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return factory.CreatePropertyType(contentType, "propertyN1", 3); } - var contentType1 = factory.CreateContentType(Guid.NewGuid(), 1, "content1", CreatePropertyTypes1); - var contentType2 = factory.CreateContentType(Guid.NewGuid(), 2, "content2", CreatePropertyTypes2); - var contentTypeN1 = factory.CreateContentType(Guid.NewGuid(), 2, "contentN1", CreatePropertyTypesN1, isElement: true); + IPublishedContentType contentType1 = factory.CreateContentType(Guid.NewGuid(), 1, "content1", CreatePropertyTypes1); + IPublishedContentType contentType2 = factory.CreateContentType(Guid.NewGuid(), 2, "content2", CreatePropertyTypes2); + IPublishedContentType contentTypeN1 = factory.CreateContentType(Guid.NewGuid(), 2, "contentN1", CreatePropertyTypesN1, isElement: true); // mocked content cache returns content types contentCache .Setup(x => x.GetContentType(It.IsAny())) .Returns((string alias) => { - if (alias.InvariantEquals("contentN1")) return contentTypeN1; + if (alias.InvariantEquals("contentN1")) + { + return contentTypeN1; + } + return null; }); @@ -164,7 +172,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [Test] public void SingleNestedTest() { - (var contentType1, _) = CreateContentTypes(); + (IPublishedContentType contentType1, _) = CreateContentTypes(); // nested single converter returns the proper value clr type TestModel, and cache level Assert.AreEqual(typeof(TestElementModel), contentType1.GetPropertyType("property1").ClrType); @@ -177,12 +185,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published Key = key, Properties = new[] { - new TestPublishedProperty(contentType1.GetPropertyType("property1"), $@"[ + new TestPublishedProperty( + contentType1.GetPropertyType("property1"), $@"[ {{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }} ]") } }; - var value = content.Value(Mock.Of(),"property1"); + var value = content.Value(Mock.Of(), "property1"); // nested single converter returns proper TestModel value Assert.IsInstanceOf(value); @@ -194,7 +203,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [Test] public void ManyNestedTest() { - (_, var contentType2) = CreateContentTypes(); + (_, IPublishedContentType contentType2) = CreateContentTypes(); // nested many converter returns the proper value clr type IEnumerable, and cache level Assert.AreEqual(typeof(IEnumerable), contentType2.GetPropertyType("property2").ClrType); @@ -214,7 +223,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published ]") } }; - var value = content.Value(Mock.Of(), ("property2")); + var value = content.Value(Mock.Of(), "property2"); // nested many converter returns proper IEnumerable value Assert.IsInstanceOf>(value); @@ -230,12 +239,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published { public TestElementModel(IPublishedElement content) : base(content) - { } + { + } - public string PropValue => this.Value(Mock.Of(),"propertyN1"); + public string PropValue => this.Value(Mock.Of(), "propertyN1"); } - class TestPublishedProperty : PublishedPropertyBase + public class TestPublishedProperty : PublishedPropertyBase { private readonly bool _preview; private readonly object _sourceValue; @@ -260,14 +270,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published private object InterValue => PropertyType.ConvertSourceToInter(null, _sourceValue, false); - internal void SetOwner(IPublishedElement owner) - { - _owner = owner; - } + internal void SetOwner(IPublishedElement owner) => _owner = owner; public override bool HasValue(string culture = null, string segment = null) => _hasValue; + public override object GetSourceValue(string culture = null, string segment = null) => _sourceValue; + public override object GetValue(string culture = null, string segment = null) => PropertyType.ConvertInterToObject(_owner, ReferenceCacheLevel, InterValue, _preview); + public override object GetXPathValue(string culture = null, string segment = null) => throw new InvalidOperationException("This method won't be implemented."); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs index b412ab1153..d020fb01d5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -1,11 +1,13 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -32,14 +34,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); - var serializer = new ConfigurationEditorJsonSerializer(); + var configurationEditorJsonSerializer = new ConfigurationEditorJsonSerializer(); + var jsonSerializer = new JsonNetSerializer(); var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType( + new VoidEditor( + NullLoggerFactory.Instance, + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + jsonSerializer), configurationEditorJsonSerializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) @@ -47,7 +55,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", dataType.Id); } - var setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); + IPublishedContentType setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); // PublishedElementPropertyBase.GetCacheLevels: // @@ -61,7 +69,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published // anything else is not > None, use Content // // for standalone elements, it's only None or Content - var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); @@ -70,7 +77,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published // source is always converted once and cached per content // inter conversion depends on the specified cache level - Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(interConverts, converter.InterConverts); @@ -108,8 +114,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published [TestCase(PropertyCacheLevel.Snapshot, PropertyCacheLevel.Elements, 1, 0, 0, 0, 0)] [TestCase(PropertyCacheLevel.Snapshot, PropertyCacheLevel.Snapshot, 1, 0, 0, 0, 0)] - public void CachePublishedSnapshotTest(PropertyCacheLevel referenceCacheLevel, PropertyCacheLevel converterCacheLevel, int interConverts, - int elementsCount1, int snapshotCount1, int elementsCount2, int snapshotCount2) + public void CachePublishedSnapshotTest( + PropertyCacheLevel referenceCacheLevel, + PropertyCacheLevel converterCacheLevel, + int interConverts, + int elementsCount1, + int snapshotCount1, + int elementsCount2, + int snapshotCount2) { var converter = new CacheConverter1(converterCacheLevel); @@ -118,10 +130,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); - var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType( + new VoidEditor( + NullLoggerFactory.Instance, + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), new ConfigurationEditorJsonSerializer()) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -132,7 +149,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", 1); } - var setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); + IPublishedContentType setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); var elementsCache = new FastDictionaryAppCache(); var snapshotCache = new FastDictionaryAppCache(); @@ -147,7 +164,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published // pretend we're creating this set as a value for a property // referenceCacheLevel is the cache level for this fictious property // converterCacheLevel is the cache level specified by the converter - var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false, referenceCacheLevel, publishedSnapshotAccessor.Object); Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); @@ -164,7 +180,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published Assert.AreEqual(elementsCount2, elementsCache.Count); Assert.AreEqual(snapshotCount2, snapshotCache.Count); - var oldSnapshotCache = snapshotCache; + FastDictionaryAppCache oldSnapshotCache = snapshotCache; snapshotCache.Clear(); Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); @@ -176,7 +192,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published Assert.AreEqual((interConverts == 1 ? 1 : 3) + snapshotCache.Count, converter.InterConverts); - var oldElementsCache = elementsCache; + FastDictionaryAppCache oldElementsCache = elementsCache; elementsCache.Clear(); Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); @@ -199,10 +215,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); - var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType( + new VoidEditor( + NullLoggerFactory.Instance, + dataTypeServiceMock.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + new JsonNetSerializer()), + new ConfigurationEditorJsonSerializer()) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -213,7 +235,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", 1); } - var setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); + IPublishedContentType setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); Assert.Throws(() => { @@ -225,16 +247,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published { private readonly PropertyCacheLevel _cacheLevel; - public CacheConverter1(PropertyCacheLevel cacheLevel) - { - _cacheLevel = cacheLevel; - } + public CacheConverter1(PropertyCacheLevel cacheLevel) => _cacheLevel = cacheLevel; public int SourceConverts { get; private set; } + public int InterConverts { get; private set; } public bool? IsValue(object value, PropertyValueLevel level) - => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string) value) == false); + => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string)value) == false); public bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); @@ -254,11 +274,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { InterConverts++; - return (int) inter; + return (int)inter; } public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => ((int) inter).ToString(); + => ((int)inter).ToString(); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionTests.cs index 063a8c2621..6950c50cc0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionTests.cs @@ -1,4 +1,8 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Linq; using NUnit.Framework; using Umbraco.Core; @@ -11,9 +15,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void GetBaseTypesIsOk() { // tests that the GetBaseTypes extension method works. - - var type = typeof(Class2); - var types = type.GetBaseTypes(true).ToArray(); + Type type = typeof(Class2); + Type[] types = type.GetBaseTypes(true).ToArray(); Assert.AreEqual(3, types.Length); Assert.Contains(typeof(Class2), types); Assert.Contains(typeof(Class1), types); @@ -25,8 +28,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.Contains(typeof(object), types); } - #region Test Objects - private class Class1 { } @@ -34,7 +35,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core private class Class2 : Class1 { } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionUtilitiesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionUtilitiesTests.cs index 0f48f2cea2..ba397522ae 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionUtilitiesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ReflectionUtilitiesTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -14,28 +17,28 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void EmitCtorEmits() { - var ctor1 = ReflectionUtilities.EmitConstructor>(); + Func ctor1 = ReflectionUtilities.EmitConstructor>(); Assert.IsInstanceOf(ctor1()); - var ctor2 = ReflectionUtilities.EmitConstructor>(declaring: typeof(Class1)); + Func ctor2 = ReflectionUtilities.EmitConstructor>(declaring: typeof(Class1)); Assert.IsInstanceOf(ctor2()); - var ctor3 = ReflectionUtilities.EmitConstructor>(); + Func ctor3 = ReflectionUtilities.EmitConstructor>(); Assert.IsInstanceOf(ctor3(42)); - var ctor4 = ReflectionUtilities.EmitConstructor>(declaring: typeof(Class3)); + Func ctor4 = ReflectionUtilities.EmitConstructor>(declaring: typeof(Class3)); Assert.IsInstanceOf(ctor4(42)); } [Test] public void EmitCtorEmitsFromInfo() { - var ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty(), null); - var ctor1 = ReflectionUtilities.EmitConstructor>(ctorInfo); + ConstructorInfo ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty(), null); + Func ctor1 = ReflectionUtilities.EmitConstructor>(ctorInfo); Assert.IsInstanceOf(ctor1()); ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, new[] { typeof(int) }, null); - var ctor3 = ReflectionUtilities.EmitConstructor>(ctorInfo); + Func ctor3 = ReflectionUtilities.EmitConstructor>(ctorInfo); Assert.IsInstanceOf(ctor3(42)); Assert.Throws(() => ReflectionUtilities.EmitConstructor>(ctorInfo)); @@ -44,67 +47,63 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void EmitCtorEmitsPrivateCtor() { - var ctor = ReflectionUtilities.EmitConstructor>(); + Func ctor = ReflectionUtilities.EmitConstructor>(); Assert.IsInstanceOf(ctor("foo")); } [Test] - public void EmitCtorThrowsIfNotFound() - { + public void EmitCtorThrowsIfNotFound() => Assert.Throws(() => ReflectionUtilities.EmitConstructor>()); - } [Test] public void EmitCtorThrowsIfInvalid() { - var ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty(), null); + ConstructorInfo ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty(), null); Assert.Throws(() => ReflectionUtilities.EmitConstructor>(ctorInfo)); } [Test] - public void EmitCtorReturnsNull() - { + public void EmitCtorReturnsNull() => Assert.IsNull(ReflectionUtilities.EmitConstructor>(false)); - } [Test] public void EmitMethodEmitsInstance() { var class1 = new Class1(); - var method1 = ReflectionUtilities.EmitMethod>("Method1"); + Action method1 = ReflectionUtilities.EmitMethod>("Method1"); method1(class1); - var method2 = ReflectionUtilities.EmitMethod>("Method2"); + Action method2 = ReflectionUtilities.EmitMethod>("Method2"); method2(class1, 42); - var method3 = ReflectionUtilities.EmitMethod>("Method3"); + Func method3 = ReflectionUtilities.EmitMethod>("Method3"); Assert.AreEqual(42, method3(class1)); - var method4 = ReflectionUtilities.EmitMethod>("Method4"); + Func method4 = ReflectionUtilities.EmitMethod>("Method4"); Assert.AreEqual(42, method4(class1, "42")); } [Test] public void EmitMethodEmitsStatic() { - var method1 = ReflectionUtilities.EmitMethod("SMethod1"); + Action method1 = ReflectionUtilities.EmitMethod("SMethod1"); method1(); - var method2 = ReflectionUtilities.EmitMethod>("SMethod2"); + Action method2 = ReflectionUtilities.EmitMethod>("SMethod2"); method2(42); - var method3 = ReflectionUtilities.EmitMethod>("SMethod3"); + Func method3 = ReflectionUtilities.EmitMethod>("SMethod3"); Assert.AreEqual(42, method3()); - var method4 = ReflectionUtilities.EmitMethod>("SMethod4"); + Func method4 = ReflectionUtilities.EmitMethod>("SMethod4"); Assert.AreEqual(42, method4("42")); } [Test] public void EmitMethodEmitsStaticStatic() { - var method = ReflectionUtilities.EmitMethod(typeof (StaticClass1), "Method"); + Action method = ReflectionUtilities.EmitMethod(typeof(StaticClass1), "Method"); method(); } @@ -113,40 +112,40 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var class1 = new Class1(); - var methodInfo = typeof (Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public); - var method1 = ReflectionUtilities.EmitMethod>(methodInfo); + MethodInfo methodInfo = typeof(Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public); + Action method1 = ReflectionUtilities.EmitMethod>(methodInfo); method1(class1); - methodInfo = typeof(Class1).GetMethod("Method2", BindingFlags.Instance | BindingFlags.Public, null, new [] { typeof(int) }, null); - var method2 = ReflectionUtilities.EmitMethod>(methodInfo); + methodInfo = typeof(Class1).GetMethod("Method2", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int) }, null); + Action method2 = ReflectionUtilities.EmitMethod>(methodInfo); method2(class1, 42); methodInfo = typeof(Class1).GetMethod("Method3", BindingFlags.Instance | BindingFlags.Public); - var method3 = ReflectionUtilities.EmitMethod>(methodInfo); + Func method3 = ReflectionUtilities.EmitMethod>(methodInfo); Assert.AreEqual(42, method3(class1)); methodInfo = typeof(Class1).GetMethod("Method4", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); - var method4 = ReflectionUtilities.EmitMethod>(methodInfo); + Func method4 = ReflectionUtilities.EmitMethod>(methodInfo); Assert.AreEqual(42, method4(class1, "42")); methodInfo = typeof(Class1).GetMethod("SMethod1", BindingFlags.Static | BindingFlags.Public); - var smethod1 = ReflectionUtilities.EmitMethod(methodInfo); + Action smethod1 = ReflectionUtilities.EmitMethod(methodInfo); smethod1(); methodInfo = typeof(Class1).GetMethod("SMethod2", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(int) }, null); - var smethod2 = ReflectionUtilities.EmitMethod>(methodInfo); + Action smethod2 = ReflectionUtilities.EmitMethod>(methodInfo); smethod2(42); methodInfo = typeof(Class1).GetMethod("SMethod3", BindingFlags.Static | BindingFlags.Public); - var smethod3 = ReflectionUtilities.EmitMethod>(methodInfo); + Func smethod3 = ReflectionUtilities.EmitMethod>(methodInfo); Assert.AreEqual(42, smethod3()); methodInfo = typeof(Class1).GetMethod("SMethod4", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null); - var smethod4 = ReflectionUtilities.EmitMethod>(methodInfo); + Func smethod4 = ReflectionUtilities.EmitMethod>(methodInfo); Assert.AreEqual(42, smethod4("42")); methodInfo = typeof(StaticClass1).GetMethod("Method", BindingFlags.Static | BindingFlags.Public); - var method = ReflectionUtilities.EmitMethod(methodInfo); + Action method = ReflectionUtilities.EmitMethod(methodInfo); method(); } @@ -155,10 +154,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var class1 = new Class1(); - var method1 = ReflectionUtilities.EmitMethod>("MethodP1"); + Action method1 = ReflectionUtilities.EmitMethod>("MethodP1"); method1(class1); - var method2 = ReflectionUtilities.EmitMethod("SMethodP1"); + Action method2 = ReflectionUtilities.EmitMethod("SMethodP1"); method2(); } @@ -172,7 +171,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void EmitMethodThrowsIfInvalid() { - var methodInfo = typeof(Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public); + MethodInfo methodInfo = typeof(Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public); Assert.Throws(() => ReflectionUtilities.EmitMethod>(methodInfo)); } @@ -188,19 +187,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var class1 = new Class1(); - var getter1 = ReflectionUtilities.EmitPropertyGetter("Value1"); + Func getter1 = ReflectionUtilities.EmitPropertyGetter("Value1"); Assert.AreEqual(42, getter1(class1)); - var getter2 = ReflectionUtilities.EmitPropertyGetter("Value3"); + Func getter2 = ReflectionUtilities.EmitPropertyGetter("Value3"); Assert.AreEqual(42, getter2(class1)); - var setter1 = ReflectionUtilities.EmitPropertySetter("Value2"); + Action setter1 = ReflectionUtilities.EmitPropertySetter("Value2"); setter1(class1, 42); - var setter2 = ReflectionUtilities.EmitPropertySetter("Value3"); + Action setter2 = ReflectionUtilities.EmitPropertySetter("Value3"); setter2(class1, 42); - (var getter3, var setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter("Value3"); + (Func getter3, Action setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter("Value3"); Assert.AreEqual(42, getter3(class1)); setter3(class1, 42); } @@ -210,23 +209,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var class1 = new Class1(); - var propertyInfo = typeof (Class1).GetProperty("Value1"); - var getter1 = ReflectionUtilities.EmitPropertyGetter(propertyInfo); + PropertyInfo propertyInfo = typeof(Class1).GetProperty("Value1"); + Func getter1 = ReflectionUtilities.EmitPropertyGetter(propertyInfo); Assert.AreEqual(42, getter1(class1)); propertyInfo = typeof(Class1).GetProperty("Value3"); - var getter2 = ReflectionUtilities.EmitPropertyGetter(propertyInfo); + Func getter2 = ReflectionUtilities.EmitPropertyGetter(propertyInfo); Assert.AreEqual(42, getter2(class1)); propertyInfo = typeof(Class1).GetProperty("Value2"); - var setter1 = ReflectionUtilities.EmitPropertySetter(propertyInfo); + Action setter1 = ReflectionUtilities.EmitPropertySetter(propertyInfo); setter1(class1, 42); propertyInfo = typeof(Class1).GetProperty("Value3"); - var setter2 = ReflectionUtilities.EmitPropertySetter(propertyInfo); + Action setter2 = ReflectionUtilities.EmitPropertySetter(propertyInfo); setter2(class1, 42); - (var getter3, var setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter(propertyInfo); + (Func getter3, Action setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter(propertyInfo); Assert.AreEqual(42, getter3(class1)); setter3(class1, 42); } @@ -236,7 +235,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var class1 = new Class1(); - var getter1 = ReflectionUtilities.EmitPropertyGetter("ValueP1"); + Func getter1 = ReflectionUtilities.EmitPropertyGetter("ValueP1"); Assert.AreEqual(42, getter1(class1)); } @@ -246,15 +245,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.Throws(() => ReflectionUtilities.EmitPropertyGetter("Zalue1")); Assert.Throws(() => ReflectionUtilities.EmitPropertyGetter("Value2")); - var propertyInfo = typeof(Class1).GetProperty("Value1"); + PropertyInfo propertyInfo = typeof(Class1).GetProperty("Value1"); Assert.Throws(() => ReflectionUtilities.EmitPropertySetter(propertyInfo)); } [Test] - public void EmitPropertyThrowsIfInvalid() - { + public void EmitPropertyThrowsIfInvalid() => Assert.Throws(() => ReflectionUtilities.EmitPropertyGetter("Value1")); - } [Test] public void EmitPropertyReturnsNull() @@ -267,18 +264,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void PropertySetterCanCastUnsafeValue() { // test that we can emit property setters that cast from eg 'object' - - var type4 = typeof(Class4); - var propInt4 = type4.GetProperty("IntValue"); - var propString4 = type4.GetProperty("StringValue"); - var propClassA4 = type4.GetProperty("ClassAValue"); + Type type4 = typeof(Class4); + PropertyInfo propInt4 = type4.GetProperty("IntValue"); + PropertyInfo propString4 = type4.GetProperty("StringValue"); + PropertyInfo propClassA4 = type4.GetProperty("ClassAValue"); var object4 = new Class4(); var object2A = new Class2A(); // works with a string property Assert.IsNotNull(propString4); - var setterString4 = ReflectionUtilities.EmitPropertySetterUnsafe(propString4); + Action setterString4 = ReflectionUtilities.EmitPropertySetterUnsafe(propString4); Assert.IsNotNull(setterString4); setterString4(object4, "foo"); Assert.IsNotNull(object4.StringValue); @@ -289,7 +285,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core // works with a reference property Assert.IsNotNull(propClassA4); - var setterClassA4 = ReflectionUtilities.EmitPropertySetterUnsafe(propClassA4); + Action setterClassA4 = ReflectionUtilities.EmitPropertySetterUnsafe(propClassA4); Assert.IsNotNull(setterClassA4); setterClassA4(object4, object2A); Assert.IsNotNull(object4.ClassAValue); @@ -297,7 +293,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core // works with a boxed value type Assert.IsNotNull(propInt4); - var setterInt4 = ReflectionUtilities.EmitPropertySetterUnsafe(propInt4); + Action setterInt4 = ReflectionUtilities.EmitPropertySetterUnsafe(propInt4); Assert.IsNotNull(setterInt4); setterInt4(object4, 42); @@ -318,14 +314,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void PropertySetterCanCastObject() { // Class5 inherits from Class4 and ClassValue is defined on Class4 - - var type5 = typeof(Class5); - var propClass4 = type5.GetProperty("ClassValue"); + Type type5 = typeof(Class5); + PropertyInfo propClass4 = type5.GetProperty("ClassValue"); var object2 = new Class2(); // can cast the object type from Class5 to Class4 - var setterClass4 = ReflectionUtilities.EmitPropertySetter(propClass4); + Action setterClass4 = ReflectionUtilities.EmitPropertySetter(propClass4); var object4 = new Class5(); setterClass4(object4, object2); @@ -336,13 +331,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void PropertySetterCanCastUnsafeObject() { - var type5 = typeof(Class5); - var propClass4 = type5.GetProperty("ClassValue"); + Type type5 = typeof(Class5); + PropertyInfo propClass4 = type5.GetProperty("ClassValue"); var object2 = new Class2(); // can cast the object type from object to Class4 - var setterClass4 = ReflectionUtilities.EmitPropertySetterUnsafe(propClass4); + Action setterClass4 = ReflectionUtilities.EmitPropertySetterUnsafe(propClass4); var object4 = new Class5(); setterClass4(object4, object2); @@ -353,17 +348,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void PropertyGetterCanCastValue() { - var type4 = typeof(Class4); - var propClassA4 = type4.GetProperty("ClassAValue"); - var propInt4 = type4.GetProperty("IntValue"); + Type type4 = typeof(Class4); + PropertyInfo propClassA4 = type4.GetProperty("ClassAValue"); + PropertyInfo propInt4 = type4.GetProperty("IntValue"); var object2A = new Class2A(); var object4 = new Class4 { ClassAValue = object2A, IntValue = 159 }; // can cast the return type from Class2A to Class2 - var getterClassA4 = ReflectionUtilities.EmitPropertyGetter(propClassA4); + Func getterClassA4 = ReflectionUtilities.EmitPropertyGetter(propClassA4); - var valueClass4A = getterClassA4(object4); + Class2 valueClass4A = getterClassA4(object4); Assert.IsNotNull(valueClass4A); Assert.AreSame(object2A, valueClass4A); @@ -372,9 +367,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core => ReflectionUtilities.EmitPropertyGetter(propClassA4)); // can cast and box the return type from int to object - var getterInt4 = ReflectionUtilities.EmitPropertyGetter(propInt4); + Func getterInt4 = ReflectionUtilities.EmitPropertyGetter(propInt4); - var valueInt4 = getterInt4(object4); + object valueInt4 = getterInt4(object4); Assert.IsTrue(valueInt4 is int); Assert.AreEqual(159, valueInt4); @@ -386,16 +381,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void PropertyGetterCanCastObject() { - var type5 = typeof(Class5); - var propClass4 = type5.GetProperty("ClassValue"); + Type type5 = typeof(Class5); + PropertyInfo propClass4 = type5.GetProperty("ClassValue"); var object2 = new Class2(); var object4 = new Class5 { ClassValue = object2 }; // can cast the object type from Class5 to Class4 - var getterClass4 = ReflectionUtilities.EmitPropertyGetter(propClass4); + Func getterClass4 = ReflectionUtilities.EmitPropertyGetter(propClass4); - var valueClass4 = getterClass4(object4); + Class2 valueClass4 = getterClass4(object4); Assert.IsNotNull(valueClass4); Assert.AreSame(object2, valueClass4); @@ -408,10 +403,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public void EmitPropertyCastGetterEmits() { // test that we can emit property getters that cast the returned value to 'object' - // test simple class - - var type4 = typeof(Class4); + Type type4 = typeof(Class4); var object4 = new Class4 { @@ -421,69 +414,71 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core }; // works with a string property - var propString4 = type4.GetProperty("StringValue"); + PropertyInfo propString4 = type4.GetProperty("StringValue"); Assert.IsNotNull(propString4); - var getterString4 = ReflectionUtilities.EmitPropertyGetter(propString4); + Func getterString4 = ReflectionUtilities.EmitPropertyGetter(propString4); Assert.IsNotNull(getterString4); - var valueString4 = getterString4(object4); + object valueString4 = getterString4(object4); Assert.IsNotNull(valueString4); Assert.AreEqual("foo", valueString4); // works with a reference property - var propClass4 = type4.GetProperty("ClassValue"); + PropertyInfo propClass4 = type4.GetProperty("ClassValue"); Assert.IsNotNull(propClass4); - var getterClass4 = ReflectionUtilities.EmitPropertyGetter(propClass4); + Func getterClass4 = ReflectionUtilities.EmitPropertyGetter(propClass4); Assert.IsNotNull(getterClass4); - var valueClass4 = getterClass4(object4); + object valueClass4 = getterClass4(object4); Assert.IsNotNull(valueClass4); Assert.IsInstanceOf(valueClass4); // works with a value type property - var propInt4 = type4.GetProperty("IntValue"); + PropertyInfo propInt4 = type4.GetProperty("IntValue"); Assert.IsNotNull(propInt4); // ... if explicitly getting a value type - var getterInt4T = ReflectionUtilities.EmitPropertyGetter(propInt4); + Func getterInt4T = ReflectionUtilities.EmitPropertyGetter(propInt4); Assert.IsNotNull(getterInt4T); - var valueInt4T = getterInt4T(object4); + int valueInt4T = getterInt4T(object4); Assert.AreEqual(1, valueInt4T); // ... if using a compiled getter - var valueInt4D = GetIntValue(object4); + object valueInt4D = GetIntValue(object4); Assert.IsNotNull(valueInt4D); Assert.IsTrue(valueInt4D is int); Assert.AreEqual(1, valueInt4D); // ... if getting a non-value type (emit adds a box) - var getterInt4 = ReflectionUtilities.EmitPropertyGetter(propInt4); + Func getterInt4 = ReflectionUtilities.EmitPropertyGetter(propInt4); Assert.IsNotNull(getterInt4); - var valueInt4 = getterInt4(object4); + object valueInt4 = getterInt4(object4); Assert.IsNotNull(valueInt4); Assert.IsTrue(valueInt4 is int); Assert.AreEqual(1, valueInt4); var getters4 = type4 .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy) - .ToDictionary(x => x.Name, x => (object) ReflectionUtilities.EmitPropertyGetter(x)); + .ToDictionary(x => x.Name, x => (object)ReflectionUtilities.EmitPropertyGetter(x)); Console.WriteLine("Getting object4 values..."); - var values4 = getters4.ToDictionary(kvp => kvp.Key, kvp => ((Func) kvp.Value)(object4)); + var values4 = getters4.ToDictionary(kvp => kvp.Key, kvp => ((Func)kvp.Value)(object4)); Console.WriteLine("Writing object4 values..."); - foreach ((var name, var value) in values4) + foreach ((string name, object value) in values4) + { Console.WriteLine($"{name}: {value}"); + } + Assert.AreEqual(4, values4.Count); Assert.AreEqual("foo", values4["StringValue"]); Assert.IsInstanceOf(values4["ClassValue"]); Assert.AreEqual(1, values4["IntValue"]); // test hierarchy - - var type5 = typeof(Class5); + Type type5 = typeof(Class5); var getters5 = type5 .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy) - .ToDictionary(x => x.Name, x => (object) ReflectionUtilities.EmitPropertyGetter(x)); + .ToDictionary(x => x.Name, x => (object)ReflectionUtilities.EmitPropertyGetter(x)); var object5 = new Class5 { @@ -496,11 +491,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core }; Console.WriteLine("Getting object5 values..."); - var values5 = getters5.ToDictionary(kvp => kvp.Key, kvp => ((Func) kvp.Value)(object5)); + var values5 = getters5.ToDictionary(kvp => kvp.Key, kvp => ((Func)kvp.Value)(object5)); Console.WriteLine("Writing object5 values..."); - foreach ((var name, var value) in values5) + foreach ((string name, object value) in values5) + { Console.WriteLine($"{name}: {value}"); + } + Assert.AreEqual(7, values5.Count); Assert.AreEqual("foo", values5["StringValue"]); Assert.IsInstanceOf(values5["ClassValue"]); @@ -510,13 +508,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.AreEqual(1, values5["IntValue2"]); // test object extensions - Console.WriteLine("Getting object5D values..."); - var values5D = ObjectJsonExtensions.ToObjectDictionary(object5); + Dictionary values5D = ObjectJsonExtensions.ToObjectDictionary(object5); Console.WriteLine("Writing object5D values..."); - foreach ((var name, var value) in values5) + foreach ((string name, object value) in values5) + { Console.WriteLine($"{name}: {value}"); + } + Assert.AreEqual(7, values5.Count); Assert.AreEqual("foo", values5D["StringValue"]); Assert.IsInstanceOf(values5D["ClassValue"]); @@ -529,18 +529,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core [Test] public void EmitFieldGetterSetterEmits() { - var getter1 = ReflectionUtilities.EmitFieldGetter("Field1"); - var getter2 = ReflectionUtilities.EmitFieldGetter("Field2"); + Func getter1 = ReflectionUtilities.EmitFieldGetter("Field1"); + Func getter2 = ReflectionUtilities.EmitFieldGetter("Field2"); var c = new Class1(); Assert.AreEqual(33, getter1(c)); Assert.AreEqual(66, getter2(c)); - var setter2 = ReflectionUtilities.EmitFieldSetter("Field2"); + Action setter2 = ReflectionUtilities.EmitFieldSetter("Field2"); setter2(c, 99); Assert.AreEqual(99, getter2(c)); // works on readonly fields! - var (getter3, setter3) = ReflectionUtilities.EmitFieldGetterAndSetter("Field3"); + (Func getter3, Action setter3) = ReflectionUtilities.EmitFieldGetterAndSetter("Field3"); Assert.AreEqual(22, getter3(c)); setter3(c, 44); Assert.AreEqual(44, getter3(c)); @@ -554,8 +554,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core var o = new { a = 1, b = "hello" }; var getters = new Dictionary>(); - foreach (var prop in o.GetType().GetProperties()) + foreach (PropertyInfo prop in o.GetType().GetProperties()) + { getters[prop.Name] = ReflectionUtilities.EmitMethodUnsafe>(prop.GetMethod); + } Assert.AreEqual(2, getters.Count); Assert.IsTrue(getters.ContainsKey("a")); @@ -564,40 +566,46 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core Assert.AreEqual("hello", getters["b"](o)); } - #region IL Code - // these functions can be examined in eg DotPeek to understand IL works // box [mscorlib]System.Int32 public object GetIntValue(Class4 object4) => object4.IntValue; // unbox.any [mscorlib]System.Int32 - public void SetIntValue(Class4 object4, object i) => object4.IntValue = (int) i; + public void SetIntValue(Class4 object4, object i) => object4.IntValue = (int)i; // castclass [mscorlib]System.String - public void SetStringValue(Class4 object4, object s) => object4.StringValue = (string) s; + public void SetStringValue(Class4 object4, object s) => object4.StringValue = (string)s; // conv.i4 - public void SetIntValue(Class4 object4, double d) => object4.IntValue = (int) d; + public void SetIntValue(Class4 object4, double d) => object4.IntValue = (int)d; // unbox.any [mscorlib]System.Double // conv.i4 - public void SetIntValue2(Class4 object4, object d) => object4.IntValue = (int) (double) d; + public void SetIntValue2(Class4 object4, object d) => object4.IntValue = (int)(double)d; public void SetIntValue3(Class4 object4, object v) { if (v is int i) + { object4.IntValue = i; + } else + { object4.IntValue = Convert.ToInt32(v); + } } public void SetIntValue4(Class4 object4, object v) { if (v is int i) + { object4.IntValue = i; + } else - object4.IntValue = (int) Convert.ChangeType(v, typeof(int)); + { + object4.IntValue = (int)Convert.ChangeType(v, typeof(int)); + } } // get field @@ -606,38 +614,69 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core // set field public void SetIntField(Class1 object1, int i) => object1.Field1 = i; - #endregion - - #region Test Objects - public static class StaticClass1 { - public static void Method() { } + public static void Method() + { + } } public class Class1 { - public Class1() { } - public Class1(int i) { } + public Class1() + { + } + + public Class1(int i) + { + } + + public void Method1() + { + } + + public void Method2(int i) + { + } - public void Method1() { } - public void Method2(int i) { } public int Method3() => 42; + public int Method4(string s) => int.Parse(s); public string Method5() => "foo"; - public static void SMethod1() { } - public static void SMethod2(int i) { } + public static void SMethod1() + { + } + + public static void SMethod2(int i) + { + } + public static int SMethod3() => 42; + public static int SMethod4(string s) => int.Parse(s); - private void MethodP1() { } - private static void SMethodP1() { } + private void MethodP1() + { + } + + private static void SMethodP1() + { + } public int Value1 => 42; - public int Value2 { set { } } - public int Value3 { get { return 42; } set { } } + + public int Value2 + { + set { } + } + + public int Value3 + { + get => 42; set { } + } + private int ValueP1 => 42; public int Field1 = 33; @@ -645,22 +684,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core public readonly int Field3 = 22; } - public class Class2 { } + public class Class2 + { + } - public class Class2A : Class2 { } + public class Class2A : Class2 + { + } public class Class3 { - public Class3(int i) { } + public Class3(int i) + { + } - private Class3(string s) { } + private Class3(string s) + { + } } public class Class4 { public int IntValue { get; set; } + public string StringValue { get; set; } - public Class2 ClassValue { get;set; } + + public Class2 ClassValue { get; set; } + public Class2A ClassAValue { get; set; } } @@ -668,10 +718,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { [JsonProperty("intValue2")] public int IntValue2 { get; set; } - public string StringValue2 { get; set; } - public Class2 ClassValue2 { get;set; } - } - #endregion + public string StringValue2 { get; set; } + + public Class2 ClassValue2 { get; set; } + } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/SiteDomainHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/SiteDomainHelperTests.cs index d32340b6b0..2aed3e0216 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/SiteDomainHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/SiteDomainHelperTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using NUnit.Framework; @@ -10,19 +14,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing public class SiteDomainHelperTests { [SetUp] - public void SetUp() - { - SiteDomainHelper.Clear(); // assuming this works! - } + public void SetUp() => SiteDomainHelper.Clear(); // assuming this works! [TearDown] - public void TearDown() - { - SiteDomainHelper.Clear(); // assuming this works! - } + public void TearDown() => SiteDomainHelper.Clear(); // assuming this works! - private static CultureInfo _cultureFr = CultureInfo.GetCultureInfo("fr-fr"); - private static CultureInfo _cultureGb = CultureInfo.GetCultureInfo("en-gb"); + private static readonly CultureInfo s_cultureFr = CultureInfo.GetCultureInfo("fr-fr"); + private static readonly CultureInfo s_cultureGb = CultureInfo.GetCultureInfo("en-gb"); [Test] public void AddSites() @@ -30,14 +28,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.AddSite("site1", "domain1.com", "domain1.net", "domain1.org"); SiteDomainHelper.AddSite("site2", "domain2.com", "domain2.net", "domain2.org"); - var sites = SiteDomainHelper.Sites; + Dictionary sites = SiteDomainHelper.Sites; Assert.AreEqual(2, sites.Count); Assert.Contains("site1", sites.Keys); Assert.Contains("site2", sites.Keys); - var domains = sites["site1"]; + string[] domains = sites["site1"]; Assert.AreEqual(3, domains.Length); Assert.Contains("domain1.com", domains); Assert.Contains("domain1.net", domains); @@ -60,18 +58,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing [TestCase("http://www.domain.com:12/")] [TestCase("https://foo.www.domain.com")] [TestCase("https://foo.www.domain.com:5478/")] - public void AddValidSite(string domain) - { - SiteDomainHelper.AddSite("site1", domain); - } + public void AddValidSite(string domain) => SiteDomainHelper.AddSite("site1", domain); [TestCase("domain.com/foo")] [TestCase("http:/domain.com")] [TestCase("*")] - public void AddInvalidSite(string domain) - { - Assert.Throws(() => SiteDomainHelper.AddSite("site1", domain)); - } + public void AddInvalidSite(string domain) => Assert.Throws(() => SiteDomainHelper.AddSite("site1", domain)); [Test] public void AddRemoveSites() @@ -79,7 +71,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.AddSite("site1", "domain1.com", "domain1.net", "domain1.org"); SiteDomainHelper.AddSite("site2", "domain2.com", "domain2.net", "domain2.org"); - var sites = SiteDomainHelper.Sites; + Dictionary sites = SiteDomainHelper.Sites; SiteDomainHelper.RemoveSite("site1"); SiteDomainHelper.RemoveSite("site3"); @@ -95,13 +87,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.AddSite("site1", "domain1.com", "domain1.net", "domain1.org"); SiteDomainHelper.AddSite("site1", "domain2.com", "domain1.net"); - var sites = SiteDomainHelper.Sites; + Dictionary sites = SiteDomainHelper.Sites; Assert.AreEqual(1, sites.Count); Assert.Contains("site1", sites.Keys); - var domains = sites["site1"]; + string[] domains = sites["site1"]; Assert.AreEqual(2, domains.Count()); Assert.Contains("domain2.com", domains); Assert.Contains("domain1.net", domains); @@ -117,13 +109,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.BindSites("site1", "site2"); - var bindings = SiteDomainHelper.Bindings; + Dictionary> bindings = SiteDomainHelper.Bindings; Assert.AreEqual(2, bindings.Count); Assert.Contains("site1", bindings.Keys); Assert.Contains("site2", bindings.Keys); - var others = bindings["site1"]; + List others = bindings["site1"]; Assert.AreEqual(1, others.Count); Assert.Contains("site2", others); @@ -143,14 +135,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.BindSites("site1", "site2"); SiteDomainHelper.BindSites("site1", "site3"); - var bindings = SiteDomainHelper.Bindings; + Dictionary> bindings = SiteDomainHelper.Bindings; Assert.AreEqual(3, bindings.Count); Assert.Contains("site1", bindings.Keys); Assert.Contains("site2", bindings.Keys); Assert.Contains("site3", bindings.Keys); - var others = bindings["site1"]; + List others = bindings["site1"]; Assert.AreEqual(2, others.Count); Assert.Contains("site2", others); Assert.Contains("site3", others); @@ -166,14 +158,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing Assert.Contains("site2", others); } - private DomainAndUri[] DomainAndUris(Uri current, Domain[] domains) - { - return domains + private DomainAndUri[] DomainAndUris(Uri current, Domain[] domains) => + domains .Where(d => d.IsWildcard == false) .Select(d => new DomainAndUri(d, current)) .OrderByDescending(d => d.Uri.ToString()) .ToArray(); - } [Test] public void MapDomainWithScheme() @@ -189,40 +179,44 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing // this works, but it's purely by chance / arbitrary // don't use the www in tests here! var current = new Uri("https://www.domain1.com/foo/bar"); - var domainAndUris = DomainAndUris(current, new[] - { - new Domain(1, "domain2.com", -1, _cultureFr, false), - new Domain(1, "domain1.com", -1, _cultureGb, false), - }); - var output = helper.MapDomain(domainAndUris, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + Domain[] domains = new[] + { + new Domain(1, "domain2.com", -1, s_cultureFr, false), + new Domain(1, "domain1.com", -1, s_cultureGb, false), + }; + DomainAndUri[] domainAndUris = DomainAndUris(current, domains); + string output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("https://domain1.com/", output); // will pick it all right current = new Uri("https://domain1.com/foo/bar"); - domainAndUris = DomainAndUris(current, new[] - { - new Domain(1, "https://domain1.com", -1, _cultureFr, false), - new Domain(1, "https://domain2.com", -1, _cultureGb, false) - }); - output = helper.MapDomain(domainAndUris, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + domains = new[] + { + new Domain(1, "https://domain1.com", -1, s_cultureFr, false), + new Domain(1, "https://domain2.com", -1, s_cultureGb, false) + }; + domainAndUris = DomainAndUris(current, domains); + output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("https://domain1.com/", output); current = new Uri("https://domain1.com/foo/bar"); - domainAndUris = DomainAndUris(current, new[] - { - new Domain(1, "https://domain1.com", -1, _cultureFr, false), - new Domain(1, "https://domain4.com", -1, _cultureGb, false) - }); - output = helper.MapDomain(domainAndUris, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + domains = new[] + { + new Domain(1, "https://domain1.com", -1, s_cultureFr, false), + new Domain(1, "https://domain4.com", -1, s_cultureGb, false) + }; + domainAndUris = DomainAndUris(current, domains); + output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("https://domain1.com/", output); current = new Uri("https://domain4.com/foo/bar"); - domainAndUris = DomainAndUris(current, new[] + domains = new[] { - new Domain(1, "https://domain1.com", -1, _cultureFr, false), - new Domain(1, "https://domain4.com", -1, _cultureGb, false) - }); - output = helper.MapDomain(domainAndUris, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + new Domain(1, "https://domain1.com", -1, s_cultureFr, false), + new Domain(1, "https://domain4.com", -1, s_cultureGb, false) + }; + domainAndUris = DomainAndUris(current, domains); + output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("https://domain4.com/", output); } @@ -239,36 +233,42 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing // current is a site1 uri, domains contain current // so we'll get current - // var current = new Uri("http://domain1.com/foo/bar"); - var output = helper.MapDomain(new[] + string output = helper.MapDomain( + new[] { - new DomainAndUri(new Domain(1, "domain1.com", -1, _cultureFr, false), current), - new DomainAndUri(new Domain(1, "domain2.com", -1, _cultureGb, false), current), - }, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + new DomainAndUri(new Domain(1, "domain1.com", -1, s_cultureFr, false), current), + new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current), + }, current, + s_cultureFr.Name, + s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("http://domain1.com/", output); // current is a site1 uri, domains do not contain current // so we'll get the corresponding site1 domain - // current = new Uri("http://domain1.com/foo/bar"); - output = helper.MapDomain(new[] + output = helper.MapDomain( + new[] { - new DomainAndUri(new Domain(1, "domain1.net", -1, _cultureFr, false), current), - new DomainAndUri(new Domain(1, "domain2.net", -1, _cultureGb, false), current) - }, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureFr, false), current), + new DomainAndUri(new Domain(1, "domain2.net", -1, s_cultureGb, false), current) + }, current, + s_cultureFr.Name, + s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("http://domain1.net/", output); // current is a site1 uri, domains do not contain current // so we'll get the corresponding site1 domain // order does not matter - // current = new Uri("http://domain1.com/foo/bar"); - output = helper.MapDomain(new[] + output = helper.MapDomain( + new[] { - new DomainAndUri(new Domain(1, "domain2.net", -1, _cultureFr, false), current), - new DomainAndUri(new Domain(1, "domain1.net", -1, _cultureGb, false), current) - }, current, _cultureFr.Name, _cultureFr.Name).Uri.ToString(); + new DomainAndUri(new Domain(1, "domain2.net", -1, s_cultureFr, false), current), + new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureGb, false), current) + }, current, + s_cultureFr.Name, + s_cultureFr.Name).Uri.ToString(); Assert.AreEqual("http://domain1.net/", output); } @@ -289,31 +289,39 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing // - return all domains from same site, or bound sites // current is a site1 uri, domains contains current - // var current = new Uri("http://domain1.com/foo/bar"); - var output = helper.MapDomains(new[] + DomainAndUri[] output = helper.MapDomains( + new[] { - new DomainAndUri(new Domain(1, "domain1.com", -1, _cultureFr, false), current), // no: current + what MapDomain would pick - new DomainAndUri(new Domain(1, "domain2.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain3.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain4.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain1.org", -1, _cultureGb, false), current), // yes: same site (though bogus setup) - }, current, true, _cultureFr.Name, _cultureFr.Name).ToArray(); + new DomainAndUri(new Domain(1, "domain1.com", -1, s_cultureFr, false), current), // no: current + what MapDomain would pick + new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain3.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain4.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain1.org", -1, s_cultureGb, false), current), // yes: same site (though bogus setup) + }, + current, + true, + s_cultureFr.Name, + s_cultureFr.Name).ToArray(); Assert.AreEqual(1, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); // current is a site1 uri, domains does not contain current - // current = new Uri("http://domain1.com/foo/bar"); - output = helper.MapDomains(new[] + output = helper.MapDomains( + new[] { - new DomainAndUri(new Domain(1, "domain1.net", -1, _cultureFr, false), current), // no: what MapDomain would pick - new DomainAndUri(new Domain(1, "domain2.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain3.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain4.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain1.org", -1, _cultureGb, false), current), // yes: same site (though bogus setup) - }, current, true, _cultureFr.Name, _cultureFr.Name).ToArray(); + new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureFr, false), current), // no: what MapDomain would pick + new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain3.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain4.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain1.org", -1, s_cultureGb, false), current), // yes: same site (though bogus setup) + }, + current, + true, + s_cultureFr.Name, + s_cultureFr.Name).ToArray(); Assert.AreEqual(1, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); @@ -322,17 +330,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing SiteDomainHelper.BindSites("site2", "site4"); // current is a site1 uri, domains contains current - // current = new Uri("http://domain1.com/foo/bar"); - output = helper.MapDomains(new[] + output = helper.MapDomains( + new[] { - new DomainAndUri(new Domain(1, "domain1.com", -1, _cultureFr, false), current), // no: current + what MapDomain would pick - new DomainAndUri(new Domain(1, "domain2.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain3.com", -1, _cultureGb, false), current), // yes: bound site - new DomainAndUri(new Domain(1, "domain3.org", -1, _cultureGb, false), current), // yes: bound site - new DomainAndUri(new Domain(1, "domain4.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain1.org", -1, _cultureGb, false), current), // yes: same site (though bogus setup) - }, current, true, _cultureFr.Name, _cultureFr.Name).ToArray(); + new DomainAndUri(new Domain(1, "domain1.com", -1, s_cultureFr, false), current), // no: current + what MapDomain would pick + new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain3.com", -1, s_cultureGb, false), current), // yes: bound site + new DomainAndUri(new Domain(1, "domain3.org", -1, s_cultureGb, false), current), // yes: bound site + new DomainAndUri(new Domain(1, "domain4.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain1.org", -1, s_cultureGb, false), current), // yes: same site (though bogus setup) + }, + current, + true, + s_cultureFr.Name, + s_cultureFr.Name).ToArray(); Assert.AreEqual(3, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); @@ -340,17 +352,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing Assert.Contains("http://domain3.org/", output.Select(d => d.Uri.ToString()).ToArray()); // current is a site1 uri, domains does not contain current - // current = new Uri("http://domain1.com/foo/bar"); - output = helper.MapDomains(new[] + output = helper.MapDomains( + new[] { - new DomainAndUri(new Domain(1, "domain1.net", -1, _cultureFr, false), current), // no: what MapDomain would pick - new DomainAndUri(new Domain(1, "domain2.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain3.com", -1, _cultureGb, false), current), // yes: bound site - new DomainAndUri(new Domain(1, "domain3.org", -1, _cultureGb, false), current), // yes: bound site - new DomainAndUri(new Domain(1, "domain4.com", -1, _cultureGb, false), current), // no: not same site - new DomainAndUri(new Domain(1, "domain1.org", -1, _cultureGb, false), current), // yes: same site (though bogus setup) - }, current, true, _cultureFr.Name, _cultureFr.Name).ToArray(); + new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureFr, false), current), // no: what MapDomain would pick + new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain3.com", -1, s_cultureGb, false), current), // yes: bound site + new DomainAndUri(new Domain(1, "domain3.org", -1, s_cultureGb, false), current), // yes: bound site + new DomainAndUri(new Domain(1, "domain4.com", -1, s_cultureGb, false), current), // no: not same site + new DomainAndUri(new Domain(1, "domain1.org", -1, s_cultureGb, false), current), // yes: same site (though bogus setup) + }, current, + true, + s_cultureFr.Name, + s_cultureFr.Name).ToArray(); Assert.AreEqual(3, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs index e577fc28fa..dee487621f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Moq; using NUnit.Framework; using Umbraco.Core.Configuration.Models; @@ -46,10 +49,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing { // Arrange var sourceUri = new Uri(sourceUrl); - var uriUtility = BuildUriUtility("/"); + UriUtility uriUtility = BuildUriUtility("/"); // Act - var resultUri = uriUtility.UriToUmbraco(sourceUri); + Uri resultUri = uriUtility.UriToUmbraco(sourceUri); // Assert var expectedUri = new Uri(expectedUrl); @@ -70,10 +73,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing // Arrange var sourceUri = new Uri(sourceUrl, UriKind.Relative); var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = trailingSlash }; - var uriUtility = BuildUriUtility("/"); + UriUtility uriUtility = BuildUriUtility("/"); // Act - var resultUri = uriUtility.UriFromUmbraco(sourceUri, requestHandlerSettings); + Uri resultUri = uriUtility.UriFromUmbraco(sourceUri, requestHandlerSettings); // Assert var expectedUri = new Uri(expectedUrl, UriKind.Relative); @@ -90,7 +93,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing public void Uri_To_Absolute(string virtualPath, string sourceUrl, string expectedUrl) { // Arrange - var uriUtility = BuildUriUtility(virtualPath); + UriUtility uriUtility = BuildUriUtility(virtualPath); // Act var resultUrl = uriUtility.ToAbsolute(sourceUrl); @@ -109,7 +112,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing public void Url_To_App_Relative(string virtualPath, string sourceUrl, string expectedUrl) { // Arrange - var uriUtility = BuildUriUtility(virtualPath); + UriUtility uriUtility = BuildUriUtility(virtualPath); // Act var resultUrl = uriUtility.ToAppRelative(sourceUrl); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/WebPathTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/WebPathTests.cs index 6c2e5f3fcb..ec1602e629 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/WebPathTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/WebPathTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using NUnit.Framework; using Umbraco.Core.Routing; @@ -19,21 +22,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing [TestCase("~/umbraco/", "/config/", "/lang/", ExpectedResult = "~/umbraco/config/lang")] [TestCase("~/umbraco/", "config/", "lang/", ExpectedResult = "~/umbraco/config/lang")] [TestCase("~/umbraco", ExpectedResult = "~/umbraco")] - public string Combine(params string[] parts) - { - return WebPath.Combine(parts); - } + public string Combine(params string[] parts) => WebPath.Combine(parts); [Test] - public void Combine_must_handle_empty_array() - { - Assert.AreEqual(string.Empty,WebPath.Combine(Array.Empty())); - } + public void Combine_must_handle_empty_array() => Assert.AreEqual(string.Empty, WebPath.Combine(Array.Empty())); [Test] - public void Combine_must_handle_null() - { - Assert.Throws(() => WebPath.Combine(null)); - } + public void Combine_must_handle_null() => Assert.Throws(() => WebPath.Combine(null)); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs index be3129aab0..60e3915325 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Events; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Scoping @@ -10,7 +14,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Scoping [Test] public void Find_Event_Ing() { - var found = EventNameExtractor.FindEvent(this, new SaveEventArgs("test"), EventNameExtractor.MatchIngNames); + Attempt found = EventNameExtractor.FindEvent(this, new SaveEventArgs("test"), EventNameExtractor.MatchIngNames); Assert.IsTrue(found.Success); Assert.AreEqual("FoundMe", found.Result.Name); } @@ -18,7 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Scoping [Test] public void Find_Event_Non_Ing() { - var found = EventNameExtractor.FindEvent(this, new SaveEventArgs("test"), EventNameExtractor.MatchNonIngNames); + Attempt found = EventNameExtractor.FindEvent(this, new SaveEventArgs("test"), EventNameExtractor.MatchNonIngNames); Assert.IsTrue(found.Success); Assert.AreEqual("FindingMe", found.Result.Name); } @@ -26,7 +30,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Scoping [Test] public void Ambiguous_Match() { - var found = EventNameExtractor.FindEvent(this, new SaveEventArgs(0), EventNameExtractor.MatchIngNames); + Attempt found = EventNameExtractor.FindEvent(this, new SaveEventArgs(0), EventNameExtractor.MatchIngNames); Assert.IsFalse(found.Success); Assert.AreEqual(EventNameExtractorError.Ambiguous, found.Result.Error); } @@ -34,18 +38,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Scoping [Test] public void No_Match() { - var found = EventNameExtractor.FindEvent(this, new SaveEventArgs(0), EventNameExtractor.MatchIngNames); + Attempt found = EventNameExtractor.FindEvent(this, new SaveEventArgs(0), EventNameExtractor.MatchIngNames); Assert.IsFalse(found.Success); Assert.AreEqual(EventNameExtractorError.NoneFound, found.Result.Error); } public static event EventHandler> FindingMe; + public static event EventHandler> FoundMe; - //will lead to ambiguous matches + // will lead to ambiguous matches public static event EventHandler> SavingThis; + public static event EventHandler> SavedThis; + public static event EventHandler> SavingThat; + public static event EventHandler> SavedThat; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/ContentPermissionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/ContentPermissionsTests.cs index 8a7b26c6cf..f4bd63f1f8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/ContentPermissionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/ContentPermissionsTests.cs @@ -1,4 +1,7 @@ -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -16,352 +19,353 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Access_Allowed_By_Path() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); - var content = contentMock.Object; + IContent content = contentMock.Object; var contentServiceMock = new Mock(); contentServiceMock.Setup(x => x.GetById(1234)).Returns(content); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void No_Content_Found() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); - var content = contentMock.Object; + IContent content = contentMock.Object; var contentServiceMock = new Mock(); contentServiceMock.Setup(x => x.GetById(0)).Returns(content); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection(); var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.NotFound, result); } [Test] public void No_Access_By_Path() { - //arrange - var user = CreateUser(id: 9, startContentId: 9876); + // Arrange + IUser user = CreateUser(id: 9, startContentId: 9876); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); - var content = contentMock.Object; + IContent content = contentMock.Object; var contentServiceMock = new Mock(); contentServiceMock.Setup(x => x.GetById(1234)).Returns(content); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection(); var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 9876 && entity.Path == "-1,9876") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } [Test] public void No_Access_By_Permission() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); - var content = contentMock.Object; + IContent content = contentMock.Object; var contentServiceMock = new Mock(); contentServiceMock.Setup(x => x.GetById(1234)).Returns(content); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A", "B", "C" }) + new EntityPermission(9876, 1234, new string[] { "A", "B", "C" }) }; var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } [Test] public void Access_Allowed_By_Permission() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); - var content = contentMock.Object; + IContent content = contentMock.Object; var contentServiceMock = new Mock(); contentServiceMock.Setup(x => x.GetById(1234)).Returns(content); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A", "F", "C" }) + new EntityPermission(9876, 1234, new string[] { "A", "F", "C" }) }; var permissionSet = new EntityPermissionSet(1234, permissions); var userServiceMock = new Mock(); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(1234, user, out IContent foundContent, new[] { 'F' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void Access_To_Root_By_Path() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-1, user, out IContent _); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-1, user, out IContent _); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void Access_To_Recycle_Bin_By_Path() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-20, user, out IContent _); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-20, user, out IContent _); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void No_Access_To_Recycle_Bin_By_Path() { - //arrange - var user = CreateUser(startContentId: 1234); + // Arrange + IUser user = CreateUser(startContentId: 1234); var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 1234 && entity.Path == "-1,1234") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } [Test] public void No_Access_To_Root_By_Path() { - //arrange - var user = CreateUser(startContentId: 1234); + // Arrange + IUser user = CreateUser(startContentId: 1234); var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 1234 && entity.Path == "-1,1234") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } [Test] public void Access_To_Root_By_Permission() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A" }) + new EntityPermission(9876, 1234, new string[] { "A" }) }; var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet); var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; - var userService = userServiceMock.Object; + IContentService contentService = contentServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent, new[] { 'A' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent, new[] { 'A' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void No_Access_To_Root_By_Permission() { - //arrange - var user = CreateUser(withUserGroup: false); + // Arrange + IUser user = CreateUser(withUserGroup: false); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A" }) + new EntityPermission(9876, 1234, new string[] { "A" }) }; var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent, new[] { 'B' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-1, user, out IContent foundContent, new[] { 'B' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } [Test] public void Access_To_Recycle_Bin_By_Permission() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A" }) + new EntityPermission(9876, 1234, new string[] { "A" }) }; var permissionSet = new EntityPermissionSet(-20, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent, new[] { 'A' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent, new[] { 'A' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result); } [Test] public void No_Access_To_Recycle_Bin_By_Permission() { - //arrange - var user = CreateUser(withUserGroup: false); + // Arrange + IUser user = CreateUser(withUserGroup: false); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1234, new string[]{ "A" }) + new EntityPermission(9876, 1234, new string[] { "A" }) }; var permissionSet = new EntityPermissionSet(1234, permissions); userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var contentServiceMock = new Mock(); - var contentService = contentServiceMock.Object; + IContentService contentService = contentServiceMock.Object; var contentPermissions = new ContentPermissions(userService, contentService, entityService); - //act - var result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent, new[] { 'B' }); + // Act + ContentPermissions.ContentAccess result = contentPermissions.CheckPermissions(-20, user, out IContent foundContent, new[] { 'B' }); - //assert + // Assert Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result); } private IUser CreateUser(int id = 0, int? startContentId = null, bool withUserGroup = true) { - var builder = new UserBuilder() + UserBuilder builder = new UserBuilder() .WithId(id) .WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0]); if (withUserGroup) + { builder = builder .AddUserGroup() .WithId(1) .WithName("admin") .WithAlias("admin") .Done(); + } return builder.Build(); } } - } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs index c070657dd5..c41b2b60a0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs @@ -1,4 +1,7 @@ -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -9,16 +12,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [TestFixture] public class LegacyPasswordSecurityTests { - [Test] public void Check_Password_Hashed_Non_KeyedHashAlgorithm() { - var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == "SHA256"); + IPasswordConfiguration passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == "SHA256"); var passwordSecurity = new LegacyPasswordSecurity(); - string salt; var pass = "ThisIsAHashedPassword"; - var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out string salt); var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); @@ -29,12 +30,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Check_Password_Hashed_KeyedHashAlgorithm() { - var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + IPasswordConfiguration passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); var passwordSecurity = new LegacyPasswordSecurity(); - string salt; var pass = "ThisIsAHashedPassword"; - var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out string salt); var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); @@ -45,12 +45,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Check_Password_Legacy_v4_SHA1() { - var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco4PasswordHashAlgorithmName); + IPasswordConfiguration passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco4PasswordHashAlgorithmName); var passwordSecurity = new LegacyPasswordSecurity(); - string salt; var pass = "ThisIsAHashedPassword"; - var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out string salt); var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); @@ -61,7 +60,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Format_Pass_For_Storage_Hashed() { - var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + IPasswordConfiguration passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); var passwordSecurity = new LegacyPasswordSecurity(); var salt = LegacyPasswordSecurity.GenerateSalt(); @@ -75,14 +74,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Get_Stored_Password_Hashed() { - var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + IPasswordConfiguration passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); var passwordSecurity = new LegacyPasswordSecurity(); var salt = LegacyPasswordSecurity.GenerateSalt(); var stored = salt + "ThisIsAHashedPassword"; - string initSalt; - var result = passwordSecurity.ParseStoredHashPassword(passwordConfiguration.HashAlgorithmType, stored, out initSalt); + var result = passwordSecurity.ParseStoredHashPassword(passwordConfiguration.HashAlgorithmType, stored, out string initSalt); Assert.AreEqual("ThisIsAHashedPassword", result); } @@ -99,11 +97,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security var result = LegacyPasswordSecurity.GenerateSalt(); if (i > 0) + { Assert.AreEqual(lastLength, result.Length); + } lastLength = result.Length; } } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/MediaPermissionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/MediaPermissionsTests.cs index c9b0324f06..52c37717d9 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/MediaPermissionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/MediaPermissionsTests.cs @@ -1,4 +1,7 @@ -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -16,148 +19,147 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security [Test] public void Access_Allowed_By_Path() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); - var media = mediaMock.Object; + IMedia media = mediaMock.Object; var mediaServiceMock = new Mock(); mediaServiceMock.Setup(x => x.GetById(1234)).Returns(media); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, 1234, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, 1234, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Granted, result); } [Test] public void Returns_Not_Found_When_No_Media_Found() { - //arrange - var user = CreateUser(id: 9); + // Arrange + IUser user = CreateUser(id: 9); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); - var media = mediaMock.Object; + IMedia media = mediaMock.Object; var mediaServiceMock = new Mock(); mediaServiceMock.Setup(x => x.GetById(0)).Returns(media); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act/assert - var result = mediaPermissions.CheckPermissions(user, 1234, out _); + // Act/assert + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, 1234, out _); Assert.AreEqual(MediaPermissions.MediaAccess.NotFound, result); } [Test] public void No_Access_By_Path() { - //arrange - var user = CreateUser(id: 9, startMediaId: 9876); + // Arrange + IUser user = CreateUser(id: 9, startMediaId: 9876); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); - var media = mediaMock.Object; + IMedia media = mediaMock.Object; var mediaServiceMock = new Mock(); mediaServiceMock.Setup(x => x.GetById(1234)).Returns(media); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 9876 && entity.Path == "-1,9876") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, 1234, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, 1234, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Denied, result); } [Test] public void Access_To_Root_By_Path() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var mediaServiceMock = new Mock(); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, -1, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, -1, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Granted, result); } [Test] public void No_Access_To_Root_By_Path() { - //arrange - var user = CreateUser(startMediaId: 1234); + // Arrange + IUser user = CreateUser(startMediaId: 1234); var mediaServiceMock = new Mock(); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 1234 && entity.Path == "-1,1234") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, -1, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, -1, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Denied, result); } [Test] public void Access_To_Recycle_Bin_By_Path() { - //arrange - var user = CreateUser(); + // Arrange + IUser user = CreateUser(); var mediaServiceMock = new Mock(); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, -21, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, -21, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Granted, result); } [Test] public void No_Access_To_Recycle_Bin_By_Path() { - //arrange - var user = CreateUser(startMediaId: 1234); + // Arrange + IUser user = CreateUser(startMediaId: 1234); var mediaServiceMock = new Mock(); - var mediaService = mediaServiceMock.Object; + IMediaService mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 1234 && entity.Path == "-1,1234") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var mediaPermissions = new MediaPermissions(mediaService, entityService); - //act - var result = mediaPermissions.CheckPermissions(user, -21, out _); + // Act + MediaPermissions.MediaAccess result = mediaPermissions.CheckPermissions(user, -21, out _); - //assert + // Assert Assert.AreEqual(MediaPermissions.MediaAccess.Denied, result); } - private IUser CreateUser(int id = 0, int? startMediaId = null) - { - return new UserBuilder() + private IUser CreateUser(int id = 0, int? startMediaId = null) => + new UserBuilder() .WithId(id) .WithStartMediaIds(startMediaId.HasValue ? new[] { startMediaId.Value } : new int[0]) .AddUserGroup() @@ -166,6 +168,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security .WithAlias("admin") .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs index 171a71b114..af91e78afa 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using Moq; using NUnit.Framework; @@ -7,7 +10,6 @@ using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services { @@ -19,24 +21,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_No_Overlap_By_Content_Type_And_Property_Type_Alias() { - Action addPropType = (alias, ct) => + void AddPropType(string alias, IContentType ct) { var contentCollection = new PropertyTypeCollection(true) { - new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) {Alias = alias, Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88} + new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = alias, Name = "Title", Description = string.Empty, Mandatory = false, SortOrder = 1, DataTypeId = -88 } }; var pg = new PropertyGroup(contentCollection) { Name = "test", SortOrder = 1 }; ct.PropertyGroups.Add(pg); - }; + } - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); - addPropType("title", ct2); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); - addPropType("title", ct3); - var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); - var ct5 = ContentTypeBuilder.CreateBasicContentType("ct5", "CT5", null); - addPropType("blah", ct5); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); + AddPropType("title", ct2); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); + AddPropType("title", ct3); + ContentType ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); + ContentType ct5 = ContentTypeBuilder.CreateBasicContentType("ct5", "CT5", null); + AddPropType("blah", ct5); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -45,7 +47,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3, ct4, ct5 }, new[] { ct2.Alias }, @@ -59,22 +61,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_No_Overlap_By_Property_Type_Alias() { - Action addPropType = ct => + void AddPropType(IContentType ct) { var contentCollection = new PropertyTypeCollection(true) { - new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) {Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88} + new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = string.Empty, Mandatory = false, SortOrder = 1, DataTypeId = -88 } }; var pg = new PropertyGroup(contentCollection) { Name = "test", SortOrder = 1 }; ct.PropertyGroups.Add(pg); - }; + } - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); - addPropType(ct2); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); - addPropType(ct3); - var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); + AddPropType(ct2); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); + AddPropType(ct3); + ContentType ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -82,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3, ct4 }, new string[] { }, @@ -96,22 +98,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_No_Overlap_By_Content_Type() { - Action addPropType = ct => + void AddPropType(IContentType ct) { var contentCollection = new PropertyTypeCollection(true) { - new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) {Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88} + new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = string.Empty, Mandatory = false, SortOrder = 1, DataTypeId = -88 } }; var pg = new PropertyGroup(contentCollection) { Name = "test", SortOrder = 1 }; ct.PropertyGroups.Add(pg); - }; + } - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); - addPropType(ct2); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); - addPropType(ct3); - var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); + AddPropType(ct2); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); + AddPropType(ct3); + ContentType ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -119,10 +121,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3, ct4 }, - new [] {ct2.Alias}) + new[] { ct2.Alias }) .Results.Where(x => x.Allowed).Select(x => x.Composition).ToArray(); Assert.AreEqual(1, availableTypes.Count()); @@ -132,18 +134,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_Not_Itself() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, - new[] {ct1, ct2, ct3}) + new[] { ct1, ct2, ct3 }) .Results.Where(x => x.Allowed).Select(x => x.Composition).ToArray(); Assert.AreEqual(2, availableTypes.Count()); @@ -151,33 +153,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services Assert.AreEqual(ct3.Id, availableTypes.ElementAt(1).Id); } - //This shows that a nested comp is not allowed + // This shows that a nested comp is not allowed [Test] public void GetAvailableCompositeContentTypes_No_Results_If_Already_A_Composition_By_Parent() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); ct1.Id = 1; - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", ct1); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", ct1); ct2.Id = 2; - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct3.Id = 3; var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + System.Collections.Generic.IEnumerable availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3 }).Results; Assert.AreEqual(0, availableTypes.Count()); } - //This shows that a nested comp is not allowed + // This shows that a nested comp is not allowed [Test] public void GetAvailableCompositeContentTypes_No_Results_If_Already_A_Composition() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -186,7 +188,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + System.Collections.Generic.IEnumerable availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3 }).Results; @@ -196,9 +198,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_Do_Not_Include_Other_Composed_Types() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -207,7 +209,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3 }) .Results.Where(x => x.Allowed).Select(x => x.Composition).ToArray(); @@ -219,9 +221,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_Include_Direct_Composed_Types() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -230,7 +232,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3 }) .Results.Where(x => x.Allowed).Select(x => x.Composition).ToArray(); @@ -243,21 +245,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Services [Test] public void GetAvailableCompositeContentTypes_Include_Indirect_Composed_Types() { - var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); - var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); - var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); - var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4"); + ContentType ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + ContentType ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + ContentType ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + ContentType ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; ct4.Id = 4; - ct1.AddContentType(ct3); //ct3 is direct to ct1 - ct3.AddContentType(ct4); //ct4 is indirect to ct1 + ct1.AddContentType(ct3); // ct3 is direct to ct1 + ct3.AddContentType(ct4); // ct4 is indirect to ct1 var service = new Mock(); - var availableTypes = service.Object.GetAvailableCompositeContentTypes( + IContentTypeComposition[] availableTypes = service.Object.GetAvailableCompositeContentTypes( ct1, new[] { ct1, ct2, ct3 }) .Results.Where(x => x.Allowed).Select(x => x.Composition).ToArray(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs index 5be6a58692..9dabbc7f36 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs @@ -1,14 +1,11 @@ -using Microsoft.Extensions.Options; -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; -using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper { @@ -22,7 +19,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("t", "t")] [TestCase("thisis", "Thisis")] [TestCase("ThisIsTheEnd", "This Is The End")] - //[TestCase("WhoIsNumber6InTheVillage", "Who Is Number6In The Village")] // note the issue with Number6In + //// [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6In The Village")] // note the issue with Number6In [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // now fixed since DefaultShortStringHelper is the default public void SpaceCamelCasing(string input, string expected) { @@ -38,7 +35,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // issue is fixed public void CompatibleDefaultReplacement(string input, string expected) { - var output = input.Length < 2 ? input : ShortStringHelper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); Assert.AreEqual(expected, output); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs index 3241285fec..b6380ecfa5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs @@ -1,17 +1,12 @@ -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Text.RegularExpressions; -using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper { @@ -21,16 +16,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper private IShortStringHelper ShortStringHelper { get; set; } [SetUp] - public void SetUp() - { + public void SetUp() => // NOTE pre-filters runs _before_ Recode takes place // so there still may be utf8 chars even though you want ascii - ShortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.FileName, new DefaultShortStringHelperConfig.Config { - //PreFilter = ClearFileChars, // done in IsTerm + // PreFilter = ClearFileChars, // done in IsTerm IsTerm = (c, leading) => (char.IsLetterOrDigit(c) || c == '_') && DefaultShortStringHelper.IsValidFileNameChar(c), StringType = CleanStringType.LowerCase | CleanStringType.Ascii, Separator = '-' @@ -68,18 +61,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper StringType = CleanStringType.Ascii, BreakTermsOnUpper = true })); - } - private static readonly Regex FrenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex s_frenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static string FilterFrenchElisions(string s) - { - return FrenchElisionsRegex.Replace(s, ""); - } + private static string FilterFrenchElisions(string s) => s_frenchElisionsRegex.Replace(s, string.Empty); private static string StripQuotes(string s) { - s = s.ReplaceMany(new Dictionary {{"'", ""}, {"\u8217", ""}}); + s = s.ReplaceMany(new Dictionary { { "'", string.Empty }, { "\u8217", string.Empty } }); return s; } @@ -89,7 +78,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper return s; } - #region Cases [TestCase("foo", "foo")] [TestCase(" foo ", "foo")] [TestCase("Foo", "Foo")] @@ -121,14 +109,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("whatIfWeDoItAgain", "whatIfWeDoItAgain")] [TestCase("WhatIfWEDOITAgain", "WhatIfWEDOITAgain")] [TestCase("WhatIfWe doItAgain", "WhatIfWeDoItAgain")] - #endregion public void CleanStringForSafeAlias(string input, string expected) { var output = ShortStringHelper.CleanStringForSafeAlias(input); Assert.AreEqual(expected, output); } - #region Cases [TestCase("Home Page", "home-page")] [TestCase("Shannon's Home Page!", "shannons-home-page")] [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-h1z-n")] @@ -137,14 +123,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("汉#字*/漢?字", "")] [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-losk")] [TestCase("200 ways to be happy", "200-ways-to-be-happy")] - #endregion public void CleanStringForUrlSegment(string input, string expected) { var output = ShortStringHelper.CleanStringForUrlSegment(input); Assert.AreEqual(expected, output); } - #region Cases [TestCase("ThisIsTheEndMyFriend", "This Is The End My Friend")] [TestCase("ThisIsTHEEndMyFriend", "This Is THE End My Friend")] [TestCase("THISIsTHEEndMyFriend", "THIS Is THE End My Friend")] @@ -153,7 +137,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("ThisIsTHEEndMyFriendXYZ", "This Is THE End My Friend XYZ")] [TestCase("ThisIsTHEEndMyFriendXYZt", "This Is THE End My Friend XY Zt")] [TestCase("UneÉlévationÀPartir", "Une Élévation À Partir")] - #endregion public void SplitPascalCasing(string input, string expected) { var output = ShortStringHelper.SplitPascalCasing(input, ' '); @@ -164,13 +147,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper Assert.AreEqual(expected, output); } - #region Cases [TestCase("sauté dans l'espace", "saute-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] [TestCase("sauté dans l'espace", "sauté-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Utf8 | CleanStringType.LowerCase)] [TestCase("sauté dans l'espace", "SauteDansLEspace", "fr-FR", CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.PascalCase)] [TestCase("he doesn't want", "he-doesnt-want", null, CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] [TestCase("he doesn't want", "heDoesntWant", null, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase)] - #endregion public void CleanStringWithTypeAndCulture(string input, string expected, string culture, CleanStringType stringType) { // picks the proper config per culture @@ -179,7 +160,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper Assert.AreEqual(expected, output); } - #region Cases [TestCase("foo.txt", "foo.txt")] [TestCase("foo", "foo")] [TestCase(".txt", ".txt")] @@ -192,7 +172,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("yop.Straße Zvöskî", "yop.strasse-zvoski")] [TestCase("yop.Straße Zvös--kî", "yop.strasse-zvos-ki")] [TestCase("ma--ma---ma.ma-----ma", "ma-ma-ma.ma-ma")] - #endregion public void CleanStringForSafeFileName(string input, string expected) { var output = ShortStringHelper.CleanStringForSafeFileName(input); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTestsWithoutSetup.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTestsWithoutSetup.cs index 98e00a69ef..f8b6f258e0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTestsWithoutSetup.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTestsWithoutSetup.cs @@ -1,7 +1,9 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using System.Linq; using System.Text; -using Moq; using NUnit.Framework; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; @@ -13,7 +15,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestFixture] public class DefaultShortStringHelperTestsWithoutSetup { - [Test] public void U4_4056() { @@ -115,7 +116,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123 foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings() )); + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings())); Assert.AreEqual("child2", helper.CleanStringForSafeAlias("1child2")); } @@ -126,6 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, + // uppercase letter means new term BreakTermsOnUpper = true, Separator = '*' @@ -136,6 +138,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, + // uppercase letter is part of term BreakTermsOnUpper = false, Separator = '*' @@ -150,6 +153,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, + // non-uppercase letter means cut acronym CutAcronymOnNonUpper = true, Separator = '*' @@ -163,6 +167,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, + // non-uppercase letter means word CutAcronymOnNonUpper = false, Separator = '*' @@ -287,12 +292,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper var bytes = Encoding.UTF8.GetBytes(str); Assert.AreEqual(10, bytes.Length); Assert.AreEqual('a', bytes[0]); - // then next string element is two chars (surrogate pair) or 4 bytes, 21 bits of code point + + // Then next string element is two chars (surrogate pair) or 4 bytes, 21 bits of code point. Assert.AreEqual('z', bytes[5]); - // then next string element is one char and 3 bytes, 16 bits of code point + + // Then next string element is one char and 3 bytes, 16 bits of code point. Assert.AreEqual('t', bytes[9]); - //foreach (var b in bytes) - // Debug.Print("{0:X}", b); + + //// foreach (var b in bytes) + //// Debug.Print("{0:X}", b); Debug.Print("\U00010B70"); } @@ -323,7 +331,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper StringType = CleanStringType.Ascii | CleanStringType.Unchanged, Separator = '*' })); - Assert.AreEqual("", helper.CleanString("中文测试", CleanStringType.Alias)); + Assert.AreEqual(string.Empty, helper.CleanString("中文测试", CleanStringType.Alias)); Assert.AreEqual("leger*ZORG", helper.CleanString("léger 中文测试 ZÔRG", CleanStringType.Alias)); } @@ -370,7 +378,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper // FIXME: "C" can't be an acronym // FIXME: "DBXreview" = acronym?! - Assert.AreEqual("aaa BBB CCc Ddd E FF", helper.CleanString("aaa BBB CCc Ddd E FF", CleanStringType.Alias)); // unchanged Assert.AreEqual("aaa Bbb Ccc Ddd E FF", helper.CleanString("aaa BBB CCc Ddd E FF", CleanStringType.Alias | CleanStringType.CamelCase)); Assert.AreEqual("Aaa Bbb Ccc Ddd E FF", helper.CleanString("aaa BBB CCc Ddd E FF", CleanStringType.Alias | CleanStringType.PascalCase)); @@ -385,7 +392,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper // eg "XmlWriter (pascal) or "htmlReader" (camel) - "SpecialXmlWriter" (pascal) or "specialHtmlReader" (camel) // - Do not capitalize any of the characters of any acronyms, whatever their length, at the beginning of a camel-cased identifier. // eg "xmlWriter" or "dbWriter" (camel) - Assert.AreEqual("aaa BB Ccc", helper.CleanString("aaa BB ccc", CleanStringType.Alias | CleanStringType.CamelCase)); Assert.AreEqual("aa Bb Ccc", helper.CleanString("AA bb ccc", CleanStringType.Alias | CleanStringType.CamelCase)); Assert.AreEqual("aaa Bb Ccc", helper.CleanString("AAA bb ccc", CleanStringType.Alias | CleanStringType.CamelCase)); @@ -426,6 +432,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper // var output = helper.CleanString(input, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase); // Assert.AreEqual(expected, output); // } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/MockShortStringHelper.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/MockShortStringHelper.cs index 442a655805..ac17cb1199 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/MockShortStringHelper.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/MockShortStringHelper.cs @@ -1,69 +1,36 @@ -using Umbraco.Core.Strings; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Strings; namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper { - class MockShortStringHelper : IShortStringHelper + internal class MockShortStringHelper : IShortStringHelper { - public void Freeze() - { - IsFrozen = true; - } + public void Freeze() => IsFrozen = true; public bool IsFrozen { get; private set; } - public string CleanStringForSafeAlias(string text) - { - return "SAFE-ALIAS::" + text; - } + public string CleanStringForSafeAlias(string text) => "SAFE-ALIAS::" + text; - public string CleanStringForSafeAlias(string text, string culture) - { - return "SAFE-ALIAS-CULTURE::" + text; - } + public string CleanStringForSafeAlias(string text, string culture) => "SAFE-ALIAS-CULTURE::" + text; - public string CleanStringForUrlSegment(string text) - { - return "URL-SEGMENT::" + text; - } + public string CleanStringForUrlSegment(string text) => "URL-SEGMENT::" + text; - public string CleanStringForUrlSegment(string text, string culture) - { - return "URL-SEGMENT-CULTURE::" + text; - } + public string CleanStringForUrlSegment(string text, string culture) => "URL-SEGMENT-CULTURE::" + text; - public string CleanStringForSafeFileName(string text) - { - return "SAFE-FILE-NAME::" + text; - } + public string CleanStringForSafeFileName(string text) => "SAFE-FILE-NAME::" + text; - public string CleanStringForSafeFileName(string text, string culture) - { - return "SAFE-FILE-NAME-CULTURE::" + text; - } + public string CleanStringForSafeFileName(string text, string culture) => "SAFE-FILE-NAME-CULTURE::" + text; - public string SplitPascalCasing(string text, char separator) - { - return "SPLIT-PASCAL-CASING::" + text; - } + public string SplitPascalCasing(string text, char separator) => "SPLIT-PASCAL-CASING::" + text; - public string CleanString(string text, CleanStringType stringType) - { - return "CLEAN-STRING-A::" + text; - } + public string CleanString(string text, CleanStringType stringType) => "CLEAN-STRING-A::" + text; - public string CleanString(string text, CleanStringType stringType, char separator) - { - return "CLEAN-STRING-B::" + text; - } + public string CleanString(string text, CleanStringType stringType, char separator) => "CLEAN-STRING-B::" + text; - public string CleanString(string text, CleanStringType stringType, string culture) - { - return "CLEAN-STRING-C::" + text; - } + public string CleanString(string text, CleanStringType stringType, string culture) => "CLEAN-STRING-C::" + text; - public string CleanString(string text, CleanStringType stringType, char separator, string culture) - { - return "CLEAN-STRING-D::" + text; - } + public string CleanString(string text, CleanStringType stringType, char separator, string culture) => "CLEAN-STRING-D::" + text; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringExtensionsTests.cs index 03c84a03b8..19103c2ec6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -19,10 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("hello-world.png", "Hello World")] [TestCase("hello-world .png", "Hello World")] [TestCase("_hello-world __1.png", "Hello World 1")] - public void To_Friendly_Name(string first, string second) - { - Assert.AreEqual(first.ToFriendlyName(), second); - } + public void To_Friendly_Name(string first, string second) => Assert.AreEqual(first.ToFriendlyName(), second); [TestCase("hello", "world", false)] [TestCase("hello", "hello", true)] @@ -45,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("/Test.js function(){return true;}", false)] public void Detect_Is_JavaScript_Path(string input, bool result) { - var output = input.DetectIsJavaScriptPath(Mock.Of()); + Attempt output = input.DetectIsJavaScriptPath(Mock.Of()); Assert.AreEqual(result, output.Success); } @@ -114,6 +114,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase("Hello this is hello my string", "hello", "replaced", "replaced this is replaced my string", StringComparison.CurrentCultureIgnoreCase)] [TestCase("Hello this is my string", "nonexistent", "replaced", "Hello this is my string", StringComparison.CurrentCultureIgnoreCase)] [TestCase("Hellohello this is my string", "hello", "replaced", "replacedreplaced this is my string", StringComparison.CurrentCultureIgnoreCase)] + // Ensure replacing with the same string doesn't cause infinite loop. [TestCase("Hello this is my string", "hello", "hello", "hello this is my string", StringComparison.CurrentCultureIgnoreCase)] public void ReplaceWithStringComparison(string input, string oldString, string newString, string shouldBe, StringComparison stringComparison) @@ -161,7 +162,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [TestCase(" ", true)] [TestCase("\r\n\r\n", true)] [TestCase("\r\n", true)] - [TestCase(@" + [TestCase( + @" Hello ", false)] [TestCase(null, true)] @@ -300,6 +302,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper var output = input.ReplaceMany(toReplace.ToArray(), replacement); Assert.AreEqual(expected, output); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs index cc786413f3..80eaf2df98 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs @@ -1,7 +1,8 @@ -using System.ComponentModel.DataAnnotations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.ComponentModel.DataAnnotations; using NUnit.Framework; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper { @@ -30,8 +31,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper // // since Umbraco is now 4.7.2+, the setting is required for the following tests to pass - //[TestCase("fdsa@fdsa", ExpectedResult = false)] - //[TestCase("fdsa@fdsa.", ExpectedResult = false)] + // [TestCase("fdsa@fdsa", ExpectedResult = false)] + // [TestCase("fdsa@fdsa.", ExpectedResult = false)] public bool Validate_Email_Address(string input) { var foo = new EmailAddressAttribute(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs index 950a103560..8be740a9a0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs @@ -1,4 +1,8 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Strings.Css; @@ -11,33 +15,35 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.ShortStringHelper [Test] public void Replace_Rule() { - var css = @"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}"; - var results = StylesheetHelper.ParseRules(css); + string css = @"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}"; + IEnumerable results = StylesheetHelper.ParseRules(css); - var result = StylesheetHelper.ReplaceRule(css, results.First().Name, new StylesheetRule() + string result = StylesheetHelper.ReplaceRule(css, results.First().Name, new StylesheetRule() { Name = "My new rule", Selector = "p", Styles = "font-size:1em; color:blue;" }); - Assert.AreEqual(@"body {font-family:Arial;}/**umb_name:My new rule*/ + Assert.AreEqual( + @"body {font-family:Arial;}/**umb_name:My new rule*/ p{font-size:1em; color:blue;} /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}".StripWhitespace(), result.StripWhitespace()); } [Test] public void Append_Rule() { - var css = @"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}"; + string css = @"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}"; - var result = StylesheetHelper.AppendRule(css, new StylesheetRule() + string result = StylesheetHelper.AppendRule(css, new StylesheetRule() { Name = "My new rule", Selector = "p", Styles = "font-size:1em; color:blue;" }); - Assert.AreEqual(@"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;} + Assert.AreEqual( + @"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;} /**umb_name:My new rule*/ p{font-size:1em; color:blue;}".StripWhitespace(), result.StripWhitespace()); @@ -46,8 +52,8 @@ p{font-size:1em; color:blue;}".StripWhitespace(), result.StripWhitespace()); [Test] public void Duplicate_Names() { - var css = @"/** Umb_Name: Test */ p { font-size: 1em; } /** umb_name: Test */ li {padding:0px;}"; - var results = StylesheetHelper.ParseRules(css); + string css = @"/** Umb_Name: Test */ p { font-size: 1em; } /** umb_name: Test */ li {padding:0px;}"; + IEnumerable results = StylesheetHelper.ParseRules(css); Assert.AreEqual(1, results.Count()); } @@ -85,14 +91,13 @@ font-size: 1em; }")] public void ParseRules_Parses(string name, string selector, string styles, string css) { - // Act - var results = StylesheetHelper.ParseRules(css); + IEnumerable results = StylesheetHelper.ParseRules(css); // Assert Assert.AreEqual(1, results.Count()); - //Assert.IsTrue(results.First().RuleId.Value.Value.ToString() == file.Id.Value.Value + "/" + name); + // Assert.IsTrue(results.First().RuleId.Value.Value.ToString() == file.Id.Value.Value + "/" + name); Assert.AreEqual(name, results.First().Name); Assert.AreEqual(selector, results.First().Selector); Assert.AreEqual(styles.StripWhitespace(), results.First().Styles.StripWhitespace()); @@ -104,26 +109,29 @@ p { font-size: 1em; }")] + // Has a Name: keyword, but applies to 2 rules, so shouldn't parse [TestCase(@"/** umb_name: Test2 */ p, h2 { font-size: 1em; }")] + // Has it's name wrapping over two lines [TestCase("/** umb_name: Test\r\n2 */ p { font-size: 1em; }")] [TestCase("/** umb_name: Test\n2 */ p { font-size: 1em; }")] - //Only a single asterisk + + // Only a single asterisk [TestCase("/* umb_name: Test */ p { font-size: 1em; }")] + // Has a name with spaces over multiple lines [TestCase(@"/**UMB_NAME:Hello world */p{font-size: 1em;}")] public void ParseRules_DoesntParse(string css) { - // Act - var results = StylesheetHelper.ParseRules(css); + IEnumerable results = StylesheetHelper.ParseRules(css); // Assert Assert.IsTrue(results.Any() == false); @@ -133,12 +141,12 @@ world */p{font-size: 1em;}")] public void AppendRules_IsFormatted() { // base CSS - var css = Tabbed( + string css = Tabbed( @"body { #font-family:Arial; }"); // add a couple of rules - var result = StylesheetHelper.AppendRule(css, new StylesheetRule + string result = StylesheetHelper.AppendRule(css, new StylesheetRule { Name = "Test", Selector = ".test", @@ -152,7 +160,8 @@ world */p{font-size: 1em;}")] }); // verify the CSS formatting including the indents - Assert.AreEqual(Tabbed( + Assert.AreEqual( + Tabbed( @"body { #font-family:Arial; } @@ -166,15 +175,14 @@ world */p{font-size: 1em;}")] /**umb_name:Test2*/ .test2 { #font-color: green; -}"), result - ); +}"), result); } [Test] public void ParseFormattedRules_CanParse() { // base CSS - var css = Tabbed( + string css = Tabbed( @"body { #font-family:Arial; } @@ -189,7 +197,7 @@ world */p{font-size: 1em;}")] .test2 { #font-color: green; }"); - var rules = StylesheetHelper.ParseRules(css); + IEnumerable rules = StylesheetHelper.ParseRules(css); Assert.AreEqual(2, rules.Count()); Assert.AreEqual("Test", rules.First().Name); @@ -206,6 +214,5 @@ margin: 1rem;", rules.First().Styles); // can't put tabs in verbatim strings, so this will replace # with \t to test the CSS indents // - and it's tabs because the editor uses tabs, not spaces... private static string Tabbed(string input) => input.Replace("#", "\t"); - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs index 542d273954..b49a229133 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using System.Linq; using Microsoft.Extensions.Options; @@ -10,6 +13,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Common; using Umbraco.Tests.UnitTests.TestHelpers.Objects; +using Umbraco.Web; using Umbraco.Web.Routing; using Umbraco.Web.Templates; @@ -48,7 +52,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates

"); - Assert.AreEqual(@"

+ Assert.AreEqual( + @"

@@ -60,8 +65,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates [Test] public void Ensure_Image_Sources() { - //setup a mock URL provider which we'll use for testing - + // setup a mock URL provider which we'll use for testing var mediaType = new PublishedContentType(Guid.NewGuid(), 777, "image", PublishedItemType.Media, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); var media = new Mock(); media.Setup(x => x.ContentType).Returns(mediaType); @@ -71,17 +75,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates var umbracoContextAccessor = new TestUmbracoContextAccessor(); - var umbracoContextFactory = TestUmbracoContextFactory.Create( + IUmbracoContextFactory umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); var webRoutingSettings = new WebRoutingSettings(); - var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, + var publishedUrlProvider = new UrlProvider( + umbracoContextAccessor, Options.Create(webRoutingSettings), new UrlProviderCollection(Enumerable.Empty()), - new MediaUrlProviderCollection(new []{mediaUrlProvider.Object}), - Mock.Of() - ); - using (var reference = umbracoContextFactory.EnsureUmbracoContext()) + new MediaUrlProviderCollection(new[] { mediaUrlProvider.Object }), + Mock.Of()); + using (UmbracoContextReference reference = umbracoContextFactory.EnsureUmbracoContext()) { var mediaCache = Mock.Get(reference.UmbracoContext.Media); mediaCache.Setup(x => x.GetById(It.IsAny())).Returns(media.Object); @@ -99,7 +103,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates

"); - Assert.AreEqual(@"

+ Assert.AreEqual( + @"

@@ -115,33 +120,27 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates [TestCase( @"
", ExpectedResult = @"
", - TestName = "Empty source is not updated with no data-udi set" - )] + TestName = "Empty source is not updated with no data-udi set")] [TestCase( @"
", ExpectedResult = @"
", - TestName = "Empty source is updated with data-udi set" - )] + TestName = "Empty source is updated with data-udi set")] [TestCase( @"
", ExpectedResult = @"
", - TestName = "Filled source is overwritten with data-udi set" - )] + TestName = "Filled source is overwritten with data-udi set")] [TestCase( @"
", ExpectedResult = @"
", - TestName = "Attributes are persisted" - )] + TestName = "Attributes are persisted")] [TestCase( @"
", ExpectedResult = @"
", - TestName = "Source is trimmed and parameters are prefixed" - )] + TestName = "Source is trimmed and parameters are prefixed")] [TestCase( @"
", ExpectedResult = @"
", - TestName = "Parameters are prefixed" - )] + TestName = "Parameters are prefixed")] [TestCase( @"
@@ -154,8 +153,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates
", - TestName = "Multiple img tags are handled" - )] + TestName = "Multiple img tags are handled")] [Category("Ensure image sources")] public string Ensure_ImageSources_Processing(string sourceHtml) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs index 043481b9d0..726741cd1c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using Moq; using NUnit.Framework; @@ -8,6 +11,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Common; using Umbraco.Tests.UnitTests.TestHelpers.Objects; +using Umbraco.Web; using Umbraco.Web.Routing; using Umbraco.Web.Templates; @@ -43,15 +47,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates [TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")] [TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")] [TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")] - //this one has an invalid char so won't match + + // This one has an invalid char so won't match. [TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")] [TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")] public void ParseLocalLinks(string input, string result) { - //setup a mock URL provider which we'll use for testing + // setup a mock URL provider which we'll use for testing var contentUrlProvider = new Mock(); contentUrlProvider - .Setup(x => x.GetUrl( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(UrlInfo.Url("/my-test-url")); var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); var publishedContent = new Mock(); @@ -67,17 +72,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates var umbracoContextAccessor = new TestUmbracoContextAccessor(); - var umbracoContextFactory = TestUmbracoContextFactory.Create( + IUmbracoContextFactory umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); var webRoutingSettings = new WebRoutingSettings(); - var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, + var publishedUrlProvider = new UrlProvider( + umbracoContextAccessor, Microsoft.Extensions.Options.Options.Create(webRoutingSettings), - new UrlProviderCollection(new []{contentUrlProvider.Object}), - new MediaUrlProviderCollection(new []{mediaUrlProvider.Object}), - Mock.Of() - ); - using (var reference = umbracoContextFactory.EnsureUmbracoContext()) + new UrlProviderCollection(new[] { contentUrlProvider.Object }), + new MediaUrlProviderCollection(new[] { mediaUrlProvider.Object }), + Mock.Of()); + using (UmbracoContextReference reference = umbracoContextFactory.EnsureUmbracoContext()) { var contentCache = Mock.Get(reference.UmbracoContext.Content); contentCache.Setup(x => x.GetById(It.IsAny())).Returns(publishedContent.Object); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs index 27c78d7a68..85c96cf5be 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.IO; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates @@ -10,7 +13,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void NoOptions() { var view = ViewHelper.GetDefaultFileContent(); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; @@ -21,7 +25,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void Layout() { var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = ""Dharznoik.cshtml""; @@ -32,7 +37,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void ClassName() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; @@ -43,7 +49,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void Namespace() { var view = ViewHelper.GetDefaultFileContent(modelNamespace: "Models"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; @@ -54,7 +61,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void ClassNameAndNamespace() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using ContentModels = My.Models; @{ @@ -66,7 +74,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void ClassNameAndNamespaceAndAlias() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using MyModels = My.Models; @{ @@ -78,7 +87,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Templates public void Combined() { var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); - Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; + Assert.AreEqual( + FixView(@"@using Umbraco.Web.PublishedModels; @inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using MyModels = My.Models; @{ diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/VersionExtensionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/VersionExtensionTests.cs index a4ab15afe7..df80f3b38b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/VersionExtensionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/VersionExtensionTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core; @@ -22,7 +25,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core { var version = new Version(major, minor, build, rev); - var result = version.SubtractRevision(); + Version result = version.SubtractRevision(); Assert.AreEqual(new Version(outcome), result); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Xml/XmlHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Xml/XmlHelperTests.cs index 495ca0186d..8d4f8aef0f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Xml/XmlHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Xml/XmlHelperTests.cs @@ -1,4 +1,7 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; using System.Linq; using System.Xml; using System.Xml.XPath; @@ -15,17 +18,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml private XmlDocumentBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new XmlDocumentBuilder(); - } + public void SetUp() => _builder = new XmlDocumentBuilder(); [Ignore("This is a benchmark test so is ignored by default")] [Test] public void Sort_Nodes_Benchmark_Legacy() { - var xml = _builder.Build(); - var original = xml.GetElementById(1173.ToString()); + XmlDocument xml = _builder.Build(); + XmlElement original = xml.GetElementById(1173.ToString()); Assert.IsNotNull(original); long totalTime = 0; @@ -34,26 +34,27 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml for (var i = 0; i < iterations; i++) { - //don't measure the time for clone! - var parentNode = original.Clone(); + // don't measure the time for clone! + XmlNode parentNode = original.Clone(); watch.Start(); LegacySortNodes(ref parentNode); watch.Stop(); totalTime += watch.ElapsedMilliseconds; watch.Reset(); - //do assertions just to make sure it is working properly. + // Do assertions just to make sure it is working properly. var currSort = 0; - foreach (var child in parentNode.SelectNodes("./* [@id]").Cast()) + foreach (XmlNode child in parentNode.SelectNodes("./* [@id]").Cast()) { Assert.AreEqual(currSort, int.Parse(child.Attributes["sortOrder"].Value)); currSort++; } - //ensure the parent node's properties still exist first + // Ensure the parent node's properties still exist first. Assert.AreEqual("content", parentNode.ChildNodes[0].Name); Assert.AreEqual("umbracoUrlAlias", parentNode.ChildNodes[1].Name); - //then the child nodes should come straight after + + // Then the child nodes should come straight after. Assert.IsTrue(parentNode.ChildNodes[2].Attributes["id"] != null); } @@ -64,8 +65,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml [Test] public void Sort_Nodes_Benchmark_New() { - var xml = _builder.Build(); - var original = xml.GetElementById(1173.ToString()); + XmlDocument xml = _builder.Build(); + XmlElement original = xml.GetElementById(1173.ToString()); Assert.IsNotNull(original); long totalTime = 0; @@ -74,8 +75,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml for (var i = 0; i < iterations; i++) { - //don't measure the time for clone! - var parentNode = (XmlElement) original.Clone(); + // don't measure the time for clone! + var parentNode = (XmlElement)original.Clone(); watch.Start(); XmlHelper.SortNodes( parentNode, @@ -85,18 +86,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml totalTime += watch.ElapsedMilliseconds; watch.Reset(); - //do assertions just to make sure it is working properly. + // do assertions just to make sure it is working properly. var currSort = 0; - foreach (var child in parentNode.SelectNodes("./* [@id]").Cast()) + foreach (XmlNode child in parentNode.SelectNodes("./* [@id]").Cast()) { Assert.AreEqual(currSort, int.Parse(child.Attributes["sortOrder"].Value)); currSort++; } - //ensure the parent node's properties still exist first + // ensure the parent node's properties still exist first Assert.AreEqual("content", parentNode.ChildNodes[0].Name); Assert.AreEqual("umbracoUrlAlias", parentNode.ChildNodes[1].Name); - //then the child nodes should come straight after + + // then the child nodes should come straight after Assert.IsTrue(parentNode.ChildNodes[2].Attributes["id"] != null); } @@ -106,52 +108,56 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Xml [Test] public void Sort_Nodes() { - var xml = _builder.Build(); - var original = xml.GetElementById(1173.ToString()); + XmlDocument xml = _builder.Build(); + XmlElement original = xml.GetElementById(1173.ToString()); Assert.IsNotNull(original); - var parentNode = (XmlElement) original.Clone(); + var parentNode = (XmlElement)original.Clone(); XmlHelper.SortNodes( parentNode, "./* [@id]", x => x.AttributeValue("sortOrder")); - //do assertions just to make sure it is working properly. + // do assertions just to make sure it is working properly. var currSort = 0; - foreach (var child in parentNode.SelectNodes("./* [@id]").Cast()) + foreach (XmlNode child in parentNode.SelectNodes("./* [@id]").Cast()) { Assert.AreEqual(currSort, int.Parse(child.Attributes["sortOrder"].Value)); currSort++; } - //ensure the parent node's properties still exist first + // ensure the parent node's properties still exist first Assert.AreEqual("content", parentNode.ChildNodes[0].Name); Assert.AreEqual("umbracoUrlAlias", parentNode.ChildNodes[1].Name); - //then the child nodes should come straight after + + // then the child nodes should come straight after Assert.IsTrue(parentNode.ChildNodes[2].Attributes["id"] != null); } /// /// This was the logic to sort before and now lives here just to show the benchmarks tests above. /// - /// private static void LegacySortNodes(ref XmlNode parentNode) { - var n = parentNode.CloneNode(true); + XmlNode n = parentNode.CloneNode(true); // remove all children from original node var xpath = "./* [@id]"; foreach (XmlNode child in parentNode.SelectNodes(xpath)) + { parentNode.RemoveChild(child); + } - var nav = n.CreateNavigator(); - var expr = nav.Compile(xpath); - expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number); - var iterator = nav.Select(expr); + XPathNavigator nav = n.CreateNavigator(); + XPathExpression expr = nav.Compile(xpath); + expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, string.Empty, XmlDataType.Number); + XPathNodeIterator iterator = nav.Select(expr); while (iterator.MoveNext()) + { parentNode.AppendChild( - ((IHasXmlNode) iterator.Current).GetNode()); + ((IHasXmlNode)iterator.Current).GetNode()); + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/XmlExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/XmlExtensionsTests.cs index ae3762ef57..2d2fb9d85b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/XmlExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/XmlExtensionsTests.cs @@ -1,4 +1,7 @@ -using System.Xml; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Xml; using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core; @@ -14,7 +17,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core var cdata = new XElement("test", new XCData("hello world")); var xdoc = new XmlDocument(); - var xmlNode = cdata.GetXmlNode(xdoc); + XmlNode xmlNode = cdata.GetXmlNode(xdoc); Assert.AreEqual("hello world", xmlNode.InnerText); } @@ -25,7 +28,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core var cdata = new XElement("test", new XText("hello world")); var xdoc = new XmlDocument(); - var xmlNode = cdata.GetXmlNode(xdoc); + XmlNode xmlNode = cdata.GetXmlNode(xdoc); Assert.AreEqual("hello world", xmlNode.InnerText); } @@ -39,7 +42,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core var xdoc = new XmlDocument(); xdoc.LoadXml(xml); - var xmlNode = cdata.GetXmlNode(xdoc); + XmlNode xmlNode = cdata.GetXmlNode(xdoc); Assert.AreEqual("hello world", xmlNode.InnerText); Assert.AreEqual(xml, xdoc.OuterXml); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackOffice/BackOfficeLookupNormalizerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackOffice/BackOfficeLookupNormalizerTests.cs index 8172a712d8..9ce3a8a3c3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackOffice/BackOfficeLookupNormalizerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackOffice/BackOfficeLookupNormalizerTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using NUnit.Framework; using Umbraco.Core.Security; @@ -29,6 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice Assert.AreEqual(name, normalizedName); } + [Test] [TestCase(null)] [TestCase("")] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs index 2bf9a541b9..971a378fe8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Linq; using Moq; using NUnit.Framework; @@ -19,8 +22,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors [Test] public void Admin_Is_Authorized() { - var currentUser = CreateAdminUser(); - var savingUser = CreateUser(); + IUser currentUser = CreateAdminUser(); + IUser savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -32,7 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors mediaService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -40,8 +43,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors [Test] public void Non_Admin_Cannot_Save_Admin() { - var currentUser = CreateUser(); - var savingUser = CreateAdminUser(); + IUser currentUser = CreateUser(); + IUser savingUser = CreateAdminUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -53,7 +56,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors mediaService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); Assert.IsFalse(result.Success); } @@ -61,8 +64,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors [Test] public void Cannot_Grant_Group_Membership_Without_Being_A_Member() { - var currentUser = CreateUser(withGroup: true); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(withGroup: true); + IUser savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -74,7 +77,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors mediaService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] {"FunGroup"}); + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { "FunGroup" }); Assert.IsFalse(result.Success); } @@ -82,8 +85,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors [Test] public void Can_Grant_Group_Membership_With_Being_A_Member() { - var currentUser = CreateUser(withGroup: true); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(withGroup: true); + IUser savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -95,7 +98,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors mediaService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { "test" }); + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { "test" }); Assert.IsTrue(result.Success); } @@ -105,14 +108,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startContentIds: new[] { 9876 }); - var savingUser = CreateUser(startContentIds: new[] { 1234 }); + IUser currentUser = CreateUser(startContentIds: new[] { 9876 }); + IUser savingUser = CreateUser(startContentIds: new[] { 1234 }); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -121,18 +124,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath {Path = nodePaths[x], Id = x}); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 - var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234, 5555 }, new int[0], new string[0]); + // adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234, 5555 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -142,14 +142,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startContentIds: new[] { 9876 }); - var savingUser = CreateUser(startContentIds: new[] { 1234, 4567 }); + IUser currentUser = CreateUser(startContentIds: new[] { 9876 }); + IUser savingUser = CreateUser(startContentIds: new[] { 1234, 4567 }); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -158,18 +158,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok - var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234 }, new int[0], new string[0]); + // removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -179,14 +176,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startContentIds: new[] { 9876 }); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(startContentIds: new[] { 9876 }); + IUser savingUser = CreateUser(); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -195,18 +192,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 1234 but currentUser doesn't have access to it ... nope - var result = authHelper.IsAuthorized(currentUser, savingUser, new []{1234}, new int[0], new string[0]); + // adding 1234 but currentUser doesn't have access to it ... nope + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234 }, new int[0], new string[0]); Assert.IsFalse(result.Success); } @@ -216,14 +210,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startContentIds: new[] { 9876 }); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(startContentIds: new[] { 9876 }); + IUser savingUser = CreateUser(); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -232,18 +226,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 5555 which currentUser has access to since it's a child of 9876 ... ok - var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 5555 }, new int[0], new string[0]); + // adding 5555 which currentUser has access to since it's a child of 9876 ... ok + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 5555 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -253,15 +244,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - - var currentUser = CreateUser(startMediaIds: new[] { 9876 }); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(startMediaIds: new[] { 9876 }); + IUser savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -270,18 +260,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 1234 but currentUser doesn't have access to it ... nope - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] {1234}, new string[0]); + // adding 1234 but currentUser doesn't have access to it ... nope + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234 }, new string[0]); Assert.IsFalse(result.Success); } @@ -291,14 +278,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startMediaIds: new[] { 9876 }); - var savingUser = CreateUser(); + IUser currentUser = CreateUser(startMediaIds: new[] { 9876 }); + IUser savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -307,18 +294,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 5555 which currentUser has access to since it's a child of 9876 ... ok - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 5555 }, new string[0]); + // adding 5555 which currentUser has access to since it's a child of 9876 ... ok + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 5555 }, new string[0]); Assert.IsTrue(result.Success); } @@ -328,14 +312,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startMediaIds: new[] { 9876 }); - var savingUser = CreateUser(startMediaIds: new[] { 1234 }); + IUser currentUser = CreateUser(startMediaIds: new[] { 9876 }); + IUser savingUser = CreateUser(startMediaIds: new[] { 1234 }); var contentService = new Mock(); var mediaService = new Mock(); @@ -344,18 +328,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234, 5555 }, new string[0]); + // adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234, 5555 }, new string[0]); Assert.IsTrue(result.Success); } @@ -365,14 +346,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors { var nodePaths = new Dictionary { - {1234, "-1,1234"}, - {9876, "-1,9876"}, - {5555, "-1,9876,5555"}, - {4567, "-1,4567"}, + { 1234, "-1,1234" }, + { 9876, "-1,9876" }, + { 5555, "-1,9876,5555" }, + { 4567, "-1,4567" }, }; - var currentUser = CreateUser(startMediaIds: new[] { 9876 }); - var savingUser = CreateUser(startMediaIds: new[] { 1234, 4567 }); + IUser currentUser = CreateUser(startMediaIds: new[] { 9876 }); + IUser savingUser = CreateUser(startMediaIds: new[] { 1234, 4567 }); var contentService = new Mock(); var mediaService = new Mock(); @@ -381,27 +362,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors var userService = new Mock(); var entityService = new Mock(); entityService.Setup(service => service.GetAllPaths(It.IsAny(), It.IsAny())) - .Returns((UmbracoObjectTypes objType, int[] ids) => - { - return ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x }); - }); + .Returns((UmbracoObjectTypes objType, int[] ids) => ids.Select(x => new TreeEntityPath { Path = nodePaths[x], Id = x })); var authHelper = new UserEditorAuthorizationHelper( contentService.Object, mediaService.Object, entityService.Object); - //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok - var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234 }, new string[0]); + // removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok + Attempt result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234 }, new string[0]); Assert.IsTrue(result.Success); } private static IUser CreateUser(bool withGroup = false, int[] startContentIds = null, int[] startMediaIds = null) { - var builder = new UserBuilder() - .WithStartContentIds(startContentIds != null ? startContentIds : new int[0]) - .WithStartMediaIds(startMediaIds != null ? startMediaIds : new int[0]); + UserBuilder builder = new UserBuilder() + .WithStartContentIds(startContentIds ?? (new int[0])) + .WithStartMediaIds(startMediaIds ?? (new int[0])); if (withGroup) { builder = (UserBuilder)builder @@ -414,15 +392,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Editors return builder.Build(); } - private static IUser CreateAdminUser() - { - return new UserBuilder() + private static IUser CreateAdminUser() => + new UserBuilder() .AddUserGroup() .WithId(1) .WithName("Admin") .WithAlias(Constants.Security.AdminGroupAlias) .Done() .Build(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs index 449e005220..a1b00c9ab2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs @@ -1,13 +1,16 @@ -using Examine; -using NUnit.Framework; -using Umbraco.Examine; -using Moq; -using Umbraco.Core.Services; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; +using System.Linq; +using Examine; +using Moq; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; -using System; -using System.Linq; +using Umbraco.Core.Services; +using Umbraco.Examine; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { @@ -19,7 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(false, true, Mock.Of()); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Valid, result); result = validator.Validate(ValueSet.FromObject("777", IndexTypes.Media, new { hello = "world", path = "-1,555" })); @@ -27,7 +30,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine result = validator.Validate(ValueSet.FromObject("555", "invalid-category", new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); - } [Test] @@ -35,7 +37,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(false, true, Mock.Of()); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); @@ -47,7 +49,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(false, true, Mock.Of(), 555); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Filtered, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,444" })); @@ -63,12 +65,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Inclusion_Field_List() { - var validator = new ValueSetValidator(null, null, + var validator = new ValueSetValidator( + null, + null, new[] { "hello", "world" }, null); var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" }); - var result = validator.Validate(valueSet); + ValueSetValidationResult result = validator.Validate(valueSet); Assert.AreEqual(ValueSetValidationResult.Filtered, result); Assert.IsFalse(valueSet.Values.ContainsKey("path")); @@ -79,12 +83,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Exclusion_Field_List() { - var validator = new ValueSetValidator(null, null, + var validator = new ValueSetValidator( + null, + null, null, new[] { "hello", "world" }); var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" }); - var result = validator.Validate(valueSet); + ValueSetValidationResult result = validator.Validate(valueSet); Assert.AreEqual(ValueSetValidationResult.Filtered, result); Assert.IsTrue(valueSet.Values.ContainsKey("path")); @@ -95,12 +101,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Inclusion_Exclusion_Field_List() { - var validator = new ValueSetValidator(null, null, + var validator = new ValueSetValidator( + null, + null, new[] { "hello", "world" }, new[] { "world" }); var valueSet = ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555", world = "your oyster" }); - var result = validator.Validate(valueSet); + ValueSetValidationResult result = validator.Validate(valueSet); Assert.AreEqual(ValueSetValidationResult.Filtered, result); Assert.IsFalse(valueSet.Values.ContainsKey("path")); @@ -111,10 +119,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Inclusion_Type_List() { - var validator = new ContentValueSetValidator(false, true, Mock.Of(), + var validator = new ContentValueSetValidator( + false, + true, + Mock.Of(), includeItemTypes: new List { "include-content" }); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); @@ -127,10 +138,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Exclusion_Type_List() { - var validator = new ContentValueSetValidator(false, true, Mock.Of(), + var validator = new ContentValueSetValidator( + false, + true, + Mock.Of(), excludeItemTypes: new List { "exclude-content" }); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Valid, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); @@ -143,11 +157,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine [Test] public void Inclusion_Exclusion_Type_List() { - var validator = new ContentValueSetValidator(false, true, Mock.Of(), + var validator = new ContentValueSetValidator( + false, + true, + Mock.Of(), includeItemTypes: new List { "include-content", "exclude-content" }, excludeItemTypes: new List { "exclude-content" }); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, "test-content", new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); @@ -165,7 +182,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(true, false, Mock.Of()); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,-20,555,777" })); @@ -174,7 +191,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); - result = validator.Validate(new ValueSet("555", IndexTypes.Content, + result = validator.Validate(new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -189,7 +208,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(true, false, Mock.Of()); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555" })); Assert.AreEqual(ValueSetValidationResult.Filtered, result); result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,-21,555,777" })); @@ -197,7 +216,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Media, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Valid, result); - } [Test] @@ -205,10 +223,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(true, true, Mock.Of()); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Failed, result); - result = validator.Validate(new ValueSet("555", IndexTypes.Content, + result = validator.Validate(new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -217,7 +237,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine })); Assert.AreEqual(ValueSetValidationResult.Failed, result); - result = validator.Validate(new ValueSet("555", IndexTypes.Content, + result = validator.Validate(new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -232,7 +254,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine { var validator = new ContentValueSetValidator(true, true, Mock.Of()); - var result = validator.Validate(new ValueSet("555", IndexTypes.Content, + ValueSetValidationResult result = validator.Validate(new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -242,7 +266,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine })); Assert.AreEqual(ValueSetValidationResult.Failed, result); - result = validator.Validate(new ValueSet("555", IndexTypes.Content, + result = validator.Validate(new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -252,7 +278,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine })); Assert.AreEqual(ValueSetValidationResult.Valid, result); - var valueSet = new ValueSet("555", IndexTypes.Content, + var valueSet = new ValueSet( + "555", + IndexTypes.Content, new Dictionary { ["hello"] = "world", @@ -274,7 +302,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine result = validator.Validate(valueSet); Assert.AreEqual(ValueSetValidationResult.Filtered, result); - Assert.AreEqual(7, valueSet.Values.Count()); //filtered to 7 values (removes es-es values) + Assert.AreEqual(7, valueSet.Values.Count()); // filtered to 7 values (removes es-es values) Assert.IsFalse(valueSet.Values.ContainsKey($"{UmbracoExamineFieldNames.PublishedFieldName}_es-es")); Assert.IsFalse(valueSet.Values.ContainsKey("hello_es-ES")); Assert.IsFalse(valueSet.Values.ContainsKey("title_es-ES")); @@ -290,7 +318,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Examine .Returns(Attempt.Fail()); var validator = new ContentValueSetValidator(false, false, publicAccessService.Object); - var result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); + ValueSetValidationResult result = validator.Validate(ValueSet.FromObject("555", IndexTypes.Content, new { hello = "world", path = "-1,555" })); Assert.AreEqual(ValueSetValidationResult.Filtered, result); result = validator.Validate(ValueSet.FromObject("777", IndexTypes.Content, new { hello = "world", path = "-1,777" })); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs index 387d8aff44..10349a4f9e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs @@ -1,18 +1,17 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using NUnit.Framework; using Umbraco.Core.HealthCheck; -using Umbraco.Core.HealthCheck.Checks; using Umbraco.Infrastructure.HealthCheck; -using Umbraco.Web.HealthCheck; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HealthChecks { [TestFixture] public class HealthCheckResultsTests { - #region Stub checks - [HealthCheck("CFD6FC34-59C9-4402-B55F-C8BC96B628A1", "Stub check")] public abstract class StubHealthCheck : HealthCheck { @@ -25,27 +24,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HealthChecks _message = message; } - public override HealthCheckStatus ExecuteAction(HealthCheckAction action) - { - throw new NotImplementedException(); - } + public override HealthCheckStatus ExecuteAction(HealthCheckAction action) => throw new NotImplementedException(); - public override IEnumerable GetStatus() - { - return new List + public override IEnumerable GetStatus() => + new List { new HealthCheckStatus(_message) { ResultType = _resultType } }; - } } [HealthCheck("CFD6FC34-59C9-4402-B55F-C8BC96B628A1", "Stub check 1")] public class StubHealthCheck1 : StubHealthCheck { - public StubHealthCheck1(StatusResultType resultType, string message) : base(resultType, message) + public StubHealthCheck1(StatusResultType resultType, string message) + : base(resultType, message) { } } @@ -53,7 +48,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HealthChecks [HealthCheck("CFD6FC34-59C9-4402-B55F-C8BC96B628A2", "Stub check 2")] public class StubHealthCheck2 : StubHealthCheck { - public StubHealthCheck2(StatusResultType resultType, string message) : base(resultType, message) + public StubHealthCheck2(StatusResultType resultType, string message) + : base(resultType, message) { } } @@ -61,18 +57,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HealthChecks [HealthCheck("CFD6FC34-59C9-4402-B55F-C8BC96B628A3", "Stub check 3")] public class StubHealthCheck3 : StubHealthCheck { - public StubHealthCheck3(StatusResultType resultType, string message) : base(resultType, message) + public StubHealthCheck3(StatusResultType resultType, string message) + : base(resultType, message) { } - public override IEnumerable GetStatus() - { - throw new Exception("Check threw exception"); - } + public override IEnumerable GetStatus() => throw new Exception("Check threw exception"); } - #endregion - [Test] public void HealthCheckResults_WithSuccessfulChecks_ReturnsCorrectResultDescription() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs index ffad002928..d5bd10fe3c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs @@ -138,8 +138,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRunTimeState = new Mock(); mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs index 98164a7aac..752da01f0f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs @@ -81,8 +81,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRequestAccessor = new Mock(); mockRequestAccessor.Setup(x => x.GetApplicationUrl()).Returns(new Uri(ApplicationUrl)); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs index 564b716f75..b7e2f7d80e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs @@ -67,8 +67,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices MaxLogAge = TimeSpan.FromMinutes(MaxLogAgeInMinutes), }; - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs index fa3a609ce6..17ff9f0c5d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs @@ -90,8 +90,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRunTimeState = new Mock(); mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs index 6ea56792e2..5187f83375 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe [TestFixture] public class InstructionProcessTaskTests { - private Mock _mockDatabaseServerMessenger; + private Mock _mockDatabaseServerMessenger; [TestCase(RuntimeLevel.Boot)] [TestCase(RuntimeLevel.Install)] @@ -45,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe var mockLogger = new Mock>(); - _mockDatabaseServerMessenger = new Mock(); + _mockDatabaseServerMessenger = new Mock(); var settings = new GlobalSettings(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs index 7f58f39346..d293a5b7e8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs @@ -21,7 +21,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe private Mock _mockServerRegistrationService; private const string ApplicationUrl = "https://mysite.com/"; - private const string ServerIdentity = "Test/1"; private readonly TimeSpan _staleServerTimeout = TimeSpan.FromMinutes(2); [TestCase(RuntimeLevel.Boot)] @@ -63,8 +62,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe var mockLogger = new Mock>(); _mockServerRegistrationService = new Mock(); - _mockServerRegistrationService.SetupGet(x => x.CurrentServerIdentity).Returns(ServerIdentity); - + var settings = new GlobalSettings { DatabaseServerRegistrar = new DatabaseServerRegistrarSettings @@ -89,7 +87,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe .Verify( x => x.TouchServer( It.Is(y => y == ApplicationUrl), - It.Is(y => y == ServerIdentity), It.Is(y => y == _staleServerTimeout)), times); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs index 183e87e5ca..42e4c3e1e6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs @@ -1,15 +1,23 @@ -using Moq; -using NUnit.Framework; -using Serilog; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; -using StackExchange.Profiling.Internal; +using Moq; +using NUnit.Framework; +using Serilog; using Umbraco.Core; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Logging.Viewer; +using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; +using File = System.IO.File; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging { @@ -18,8 +26,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging { private ILogViewer _logViewer; - const string _logfileName = "UmbracoTraceLog.UNITTEST.20181112.json"; - const string _searchfileName = "logviewer.searches.config.js"; + private const string LogfileName = "UmbracoTraceLog.UNITTEST.20181112.json"; + private const string SearchfileName = "logviewer.searches.config.js"; private string _newLogfilePath; private string _newLogfileDirPath; @@ -27,38 +35,39 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging private string _newSearchfilePath; private string _newSearchfileDirPath; - private LogTimePeriod _logTimePeriod = new LogTimePeriod( - new DateTime(year: 2018, month: 11, day: 12, hour:0, minute:0, second:0), - new DateTime(year: 2018, month: 11, day: 13, hour: 0, minute: 0, second: 0) - ); + private readonly LogTimePeriod _logTimePeriod = new LogTimePeriod( + new DateTime(year: 2018, month: 11, day: 12, hour: 0, minute: 0, second: 0), + new DateTime(year: 2018, month: 11, day: 13, hour: 0, minute: 0, second: 0)); + [OneTimeSetUp] public void Setup() { var testRoot = TestContext.CurrentContext.TestDirectory.Split("bin")[0]; - //Create an example JSON log file to check results - //As a one time setup for all tets in this class/fixture - var ioHelper = TestHelper.IOHelper; - var hostingEnv = TestHelper.GetHostingEnvironment(); - var loggingConfiguration = TestHelper.GetLoggingConfiguration(hostingEnv); + // Create an example JSON log file to check results + // As a one time setup for all tets in this class/fixture + IIOHelper ioHelper = TestHelper.IOHelper; + IHostingEnvironment hostingEnv = TestHelper.GetHostingEnvironment(); - var exampleLogfilePath = Path.Combine(testRoot, "TestHelpers","Assets", _logfileName); + ILoggingConfiguration loggingConfiguration = TestHelper.GetLoggingConfiguration(hostingEnv); + + var exampleLogfilePath = Path.Combine(testRoot, "TestHelpers", "Assets", LogfileName); _newLogfileDirPath = loggingConfiguration.LogDirectory; - _newLogfilePath = Path.Combine(_newLogfileDirPath, _logfileName); + _newLogfilePath = Path.Combine(_newLogfileDirPath, LogfileName); - var exampleSearchfilePath = Path.Combine(testRoot, "TestHelpers","Assets", _searchfileName); + var exampleSearchfilePath = Path.Combine(testRoot, "TestHelpers", "Assets", SearchfileName); _newSearchfileDirPath = Path.Combine(hostingEnv.ApplicationPhysicalPath, @"config"); - _newSearchfilePath = Path.Combine(_newSearchfileDirPath, _searchfileName); + _newSearchfilePath = Path.Combine(_newSearchfileDirPath, SearchfileName); - //Create/ensure Directory exists + // Create/ensure Directory exists ioHelper.EnsurePathExists(_newLogfileDirPath); ioHelper.EnsurePathExists(_newSearchfileDirPath); - //Copy the sample files + // Copy the sample files File.Copy(exampleLogfilePath, _newLogfilePath, true); File.Copy(exampleSearchfilePath, _newSearchfilePath, true); - var logger = Mock.Of>(); + ILogger logger = Mock.Of>(); var logViewerConfig = new LogViewerConfig(hostingEnv); _logViewer = new SerilogJsonLogViewer(logger, logViewerConfig, loggingConfiguration, Log.Logger); } @@ -66,13 +75,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging [OneTimeTearDown] public void TearDown() { - //Cleanup & delete the example log & search files off disk - //Once all tests in this class/fixture have run + // Cleanup & delete the example log & search files off disk + // Once all tests in this class/fixture have run if (File.Exists(_newLogfilePath)) + { File.Delete(_newLogfilePath); + } if (File.Exists(_newSearchfilePath)) + { File.Delete(_newSearchfilePath); + } } [Test] @@ -80,14 +93,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging { var numberOfErrors = _logViewer.GetNumberOfErrors(_logTimePeriod); - //Our dummy log should contain 2 errors + // Our dummy log should contain 2 errors Assert.AreEqual(1, numberOfErrors); } [Test] public void Logs_Contain_Correct_Log_Level_Counts() { - var logCounts = _logViewer.GetLogLevelCounts(_logTimePeriod); + LogLevelCounts logCounts = _logViewer.GetLogLevelCounts(_logTimePeriod); Assert.AreEqual(55, logCounts.Debug); Assert.AreEqual(1, logCounts.Error); @@ -99,19 +112,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging [Test] public void Logs_Contains_Correct_Message_Templates() { - var templates = _logViewer.GetMessageTemplates(_logTimePeriod); + IEnumerable templates = _logViewer.GetMessageTemplates(_logTimePeriod); - //Count no of templates + // Count no of templates Assert.AreEqual(25, templates.Count()); - //Verify all templates & counts are unique + // Verify all templates & counts are unique CollectionAssert.AllItemsAreUnique(templates); - //Ensure the collection contains LogTemplate objects + // Ensure the collection contains LogTemplate objects CollectionAssert.AllItemsAreInstancesOfType(templates, typeof(LogTemplate)); - //Get first item & verify its template & count are what we expect - var popularTemplate = templates.FirstOrDefault(); + // Get first item & verify its template & count are what we expect + LogTemplate popularTemplate = templates.FirstOrDefault(); Assert.IsNotNull(popularTemplate); Assert.AreEqual("{EndMessage} ({Duration}ms) [Timing {TimingId}]", popularTemplate.MessageTemplate); @@ -121,8 +134,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging [Test] public void Logs_Can_Open_As_Small_File() { - //We are just testing a return value (as we know the example file is less than 200MB) - //But this test method does not test/check that + // We are just testing a return value (as we know the example file is less than 200MB) + // But this test method does not test/check that var canOpenLogs = _logViewer.CheckCanOpenLogs(_logTimePeriod); Assert.IsTrue(canOpenLogs); } @@ -132,51 +145,49 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging { var sw = new Stopwatch(); sw.Start(); - //Should get me the most 100 recent log entries & using default overloads for remaining params - var allLogs = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1); + + // Should get me the most 100 recent log entries & using default overloads for remaining params + PagedResult allLogs = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1); sw.Stop(); - //Check we get 100 results back for a page & total items all good :) + + // Check we get 100 results back for a page & total items all good :) Assert.AreEqual(100, allLogs.Items.Count()); Assert.AreEqual(102, allLogs.TotalItems); Assert.AreEqual(2, allLogs.TotalPages); - //Check collection all contain same object type + // Check collection all contain same object type CollectionAssert.AllItemsAreInstancesOfType(allLogs.Items, typeof(LogMessage)); - //Check first item is newest - var newestItem = allLogs.Items.First(); - DateTimeOffset newDate; - DateTimeOffset.TryParse("2018-11-12T08:39:18.1971147Z", out newDate); + // Check first item is newest + LogMessage newestItem = allLogs.Items.First(); + DateTimeOffset.TryParse("2018-11-12T08:39:18.1971147Z", out DateTimeOffset newDate); Assert.AreEqual(newDate, newestItem.Timestamp); - - //Check we call method again with a smaller set of results & in ascending - var smallQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, pageSize: 10, orderDirection: Direction.Ascending); + // Check we call method again with a smaller set of results & in ascending + PagedResult smallQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, pageSize: 10, orderDirection: Direction.Ascending); Assert.AreEqual(10, smallQuery.Items.Count()); Assert.AreEqual(11, smallQuery.TotalPages); - //Check first item is oldest - var oldestItem = smallQuery.Items.First(); - DateTimeOffset oldDate; - DateTimeOffset.TryParse("2018-11-12T08:34:45.8371142Z", out oldDate); + // Check first item is oldest + LogMessage oldestItem = smallQuery.Items.First(); + DateTimeOffset.TryParse("2018-11-12T08:34:45.8371142Z", out DateTimeOffset oldDate); Assert.AreEqual(oldDate, oldestItem.Timestamp); - - //Check invalid log levels - //Rather than expect 0 items - get all items back & ignore the invalid levels + // Check invalid log levels + // Rather than expect 0 items - get all items back & ignore the invalid levels string[] invalidLogLevels = { "Invalid", "NotALevel" }; - var queryWithInvalidLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: invalidLogLevels); + PagedResult queryWithInvalidLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: invalidLogLevels); Assert.AreEqual(102, queryWithInvalidLevels.TotalItems); - //Check we can call method with an array of logLevel (error & warning) - string [] logLevels = { "Warning", "Error" }; - var queryWithLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: logLevels); + // Check we can call method with an array of logLevel (error & warning) + string[] logLevels = { "Warning", "Error" }; + PagedResult queryWithLevels = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, logLevels: logLevels); Assert.AreEqual(7, queryWithLevels.TotalItems); - //Query @Level='Warning' BUT we pass in array of LogLevels for Debug & Info (Expect to get 0 results) + // Query @Level='Warning' BUT we pass in array of LogLevels for Debug & Info (Expect to get 0 results) string[] logLevelMismatch = { "Debug", "Information" }; - var filterLevelQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: "@Level='Warning'", logLevels: logLevelMismatch); + PagedResult filterLevelQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: "@Level='Warning'", logLevels: logLevelMismatch); Assert.AreEqual(0, filterLevelQuery.TotalItems); } @@ -191,17 +202,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging [Test] public void Logs_Can_Query_With_Expressions(string queryToVerify, int expectedCount) { - var testQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: queryToVerify); + PagedResult testQuery = _logViewer.GetLogs(_logTimePeriod, pageNumber: 1, filterExpression: queryToVerify); Assert.AreEqual(expectedCount, testQuery.TotalItems); } [Test] public void Log_Search_Can_Persist() { - //Add a new search + // Add a new search _logViewer.AddSavedSearch("Unit Test Example", "Has(UnitTest)"); - var searches = _logViewer.GetSavedSearches(); + IReadOnlyList searches = _logViewer.GetSavedSearches(); var savedSearch = new SavedLogSearch { @@ -209,17 +220,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging Query = "Has(UnitTest)" }; - //Check if we can find the newly added item from the results we get back - var findItem = searches.Where(x => x.Name == "Unit Test Example" && x.Query == "Has(UnitTest)"); + // Check if we can find the newly added item from the results we get back + IEnumerable findItem = searches.Where(x => x.Name == "Unit Test Example" && x.Query == "Has(UnitTest)"); Assert.IsNotNull(findItem, "We should have found the saved search, but get no results"); Assert.AreEqual(1, findItem.Count(), "Our list of searches should only contain one result"); // TODO: Need someone to help me find out why these don't work - //CollectionAssert.Contains(searches, savedSearch, "Can not find the new search that was saved"); - //Assert.That(searches, Contains.Item(savedSearch)); + // CollectionAssert.Contains(searches, savedSearch, "Can not find the new search that was saved"); + // Assert.That(searches, Contains.Item(savedSearch)); - //Remove the search from above & ensure it no longer exists + // Remove the search from above & ensure it no longer exists _logViewer.DeleteSavedSearch("Unit Test Example", "Has(UnitTest)"); searches = _logViewer.GetSavedSearches(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs index ba982cd593..ff443cd944 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -22,7 +25,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping var mapper = new UmbracoMapper(definitions); var thing1 = new Thing1 { Value = "value" }; - var thing2 = mapper.Map(thing1); + Thing2 thing2 = mapper.Map(thing1); Assert.IsNotNull(thing2); Assert.AreEqual("value", thing2.Value); @@ -48,7 +51,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping var thing1A = new Thing1 { Value = "valueA" }; var thing1B = new Thing1 { Value = "valueB" }; - var thing1 = new[] { thing1A, thing1B }; + Thing1[] thing1 = new[] { thing1A, thing1B }; var thing2 = mapper.Map, IEnumerable>(thing1).ToList(); Assert.IsNotNull(thing2); @@ -81,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping var mapper = new UmbracoMapper(definitions); var thing3 = new Thing3 { Value = "value" }; - var thing2 = mapper.Map(thing3); + Thing2 thing2 = mapper.Map(thing3); Assert.IsNotNull(thing2); Assert.AreEqual("value", thing2.Value); @@ -107,7 +110,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping // can map a PropertyCollection var source = new PropertyCollection(); - var target = mapper.Map>(source); + IEnumerable target = mapper.Map>(source); } [Test] @@ -129,7 +132,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping // if timing is good, and mapper does have non-concurrent dictionaries, it fails // practically, to reproduce, one needs to add a 1s sleep in the mapper's loop // hence, this test is explicit - var thing3 = new Thing3 { Value = "value" }; var thing4 = new Thing4(); Exception caught = null; @@ -138,6 +140,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping { // keep failing at mapping - and looping through the maps for (var i = 0; i < 10; i++) + { try { mapper.Map(thing4); @@ -147,6 +150,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping caught = e; Console.WriteLine($"{e.GetType().Name} {e.Message}"); } + } Console.WriteLine("done"); } @@ -158,7 +162,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping try { Console.WriteLine($"{DateTime.Now:O} mapping"); - var thing2 = mapper.Map(thing3); + Thing2 thing2 = mapper.Map(thing3); Console.WriteLine($"{DateTime.Now:O} mapped"); Assert.IsNotNull(thing2); @@ -186,7 +190,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping Fruit3 = Thing5Enum.Cherry }; - var thing6 = mapper.Map(thing5); + Thing6 thing6 = mapper.Map(thing5); Assert.IsNotNull(thing6); Assert.AreEqual(Thing6Enum.Apple, thing6.Fruit1); @@ -205,20 +209,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping var thing7 = new Thing7(); - var thing8 = mapper.Map(thing7); + Thing8 thing8 = mapper.Map(thing7); Assert.IsNotNull(thing8); Assert.IsNull(thing8.Things); } - private class Thing1 { public string Value { get; set; } } private class Thing3 : Thing1 - { } + { + } private class Thing2 { @@ -226,12 +230,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping } private class Thing4 - { } + { + } private class Thing5 { public Thing5Enum Fruit1 { get; set; } + public Thing5Enum Fruit2 { get; set; } + public Thing5Enum Fruit3 { get; set; } } @@ -245,7 +252,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping private class Thing6 { public Thing6Enum Fruit1 { get; set; } + public Thing6Enum Fruit2 { get; set; } + public Thing6Enum Fruit3 { get; set; } } @@ -268,26 +277,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping private class MapperDefinition1 : IMapDefinition { - public void DefineMaps(UmbracoMapper mapper) - { - mapper.Define((source, context) => new Thing2(), Map); - } + public void DefineMaps(UmbracoMapper mapper) => mapper.Define((source, context) => new Thing2(), Map); - private void Map(Thing1 source, Thing2 target, MapperContext context) - { - target.Value = source.Value; - } + private void Map(Thing1 source, Thing2 target, MapperContext context) => target.Value = source.Value; } private class MapperDefinition2 : IMapDefinition { - public void DefineMaps(UmbracoMapper mapper) - { + public void DefineMaps(UmbracoMapper mapper) => mapper.Define((source, context) => new ContentPropertyDto(), Map); - } private static void Map(IProperty source, ContentPropertyDto target, MapperContext context) - { } + { + } } private class MapperDefinition3 : IMapDefinition @@ -328,15 +330,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Mapping mapper.Define((source, context) => new Thing8(), Map2); } - private void Map1(Thing1 source, Thing2 target, MapperContext context) - { + private void Map1(Thing1 source, Thing2 target, MapperContext context) => target.Value = source.Value; - } - private void Map2(Thing7 source, Thing8 target, MapperContext context) - { + private void Map2(Thing7 source, Thing8 target, MapperContext context) => target.Things = context.Map>(source.Things); - } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs index febb36145b..1ced792520 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Infrastructure.Media; using Umbraco.Web.Models; @@ -9,36 +12,36 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media public class ImageSharpImageUrlGeneratorTests { private const string MediaPath = "/media/1005/img_0671.jpg"; - private static readonly ImageUrlGenerationOptions.CropCoordinates Crop = new ImageUrlGenerationOptions.CropCoordinates(0.58729977382575338m, 0.055768992440203169m, 0m, 0.32457553600198386m); - private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus1 = new ImageUrlGenerationOptions.FocalPointPosition(0.80827067669172936m, 0.96m); - private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus2 = new ImageUrlGenerationOptions.FocalPointPosition(0.41m, 0.4275m); - private static readonly ImageSharpImageUrlGenerator Generator = new ImageSharpImageUrlGenerator(); + private static readonly ImageUrlGenerationOptions.CropCoordinates s_crop = new ImageUrlGenerationOptions.CropCoordinates(0.58729977382575338m, 0.055768992440203169m, 0m, 0.32457553600198386m); + private static readonly ImageUrlGenerationOptions.FocalPointPosition s_focus1 = new ImageUrlGenerationOptions.FocalPointPosition(0.80827067669172936m, 0.96m); + private static readonly ImageUrlGenerationOptions.FocalPointPosition s_focus2 = new ImageUrlGenerationOptions.FocalPointPosition(0.41m, 0.4275m); + private static readonly ImageSharpImageUrlGenerator s_generator = new ImageSharpImageUrlGenerator(); [Test] public void GetCropUrl_CropAliasTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = Crop, Width = 100, Height = 100 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = s_crop, Width = 100, Height = 100 }); Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); } [Test] public void GetCropUrl_WidthHeightTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 200, Height = 300 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus1, Width = 200, Height = 300 }); Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300", urlString); } [Test] public void GetCropUrl_FocalPointTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 100, Height = 100 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus1, Width = 100, Height = 100 }); Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString); } [Test] public void GetCropUrlFurtherOptionsTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 200, Height = 300, FurtherOptions = "&filter=comic&roundedcorners=radius-26|bgcolor-fff" }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus1, Width = 200, Height = 300, FurtherOptions = "&filter=comic&roundedcorners=radius-26|bgcolor-fff" }); Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString); } @@ -48,7 +51,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrlNullTest() { - var urlString = Generator.GetImageUrl(null); + var urlString = s_generator.GetImageUrl(null); Assert.AreEqual(null, urlString); } @@ -58,7 +61,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrlEmptyTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(null)); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(null)); Assert.AreEqual("?mode=crop", urlString); } @@ -68,7 +71,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetBaseCropUrlFromModelTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(null) { Crop = Crop, Width = 100, Height = 100 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(null) { Crop = s_crop, Width = 100, Height = 100 }); Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString); } @@ -78,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_CropAliasHeightRatioModeTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = Crop, Width = 100, HeightRatio = 1 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = s_crop, Width = 100, HeightRatio = 1 }); Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&heightratio=1&width=100", urlString); } @@ -88,7 +91,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_WidthHeightRatioModeTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 300, HeightRatio = 0.5m }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus1, Width = 300, HeightRatio = 0.5m }); Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&heightratio=0.5&width=300", urlString); } @@ -98,7 +101,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_HeightWidthRatioModeTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Height = 150, WidthRatio = 2 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus1, Height = 150, WidthRatio = 2 }); Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&widthratio=2&height=150", urlString); } @@ -108,11 +111,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_SpecifiedCropModeTest() { - var urlStringMin = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Min, Width = 300, Height = 150 }); - var urlStringBoxPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.BoxPad, Width = 300, Height = 150 }); - var urlStringPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 300, Height = 150 }); - var urlStringMax = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Max, Width = 300, Height = 150 }); - var urlStringStretch = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Stretch, Width = 300, Height = 150 }); + var urlStringMin = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Min, Width = 300, Height = 150 }); + var urlStringBoxPad = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.BoxPad, Width = 300, Height = 150 }); + var urlStringPad = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 300, Height = 150 }); + var urlStringMax = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Max, Width = 300, Height = 150 }); + var urlStringStretch = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Stretch, Width = 300, Height = 150 }); Assert.AreEqual(MediaPath + "?mode=min&width=300&height=150", urlStringMin); Assert.AreEqual(MediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad); @@ -127,7 +130,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_UploadTypeTest() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Crop, ImageCropAnchor = ImageCropAnchor.Center, Width = 100, Height = 270 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Crop, ImageCropAnchor = ImageCropAnchor.Center, Width = 100, Height = 270 }); Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString); } @@ -137,7 +140,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_PreferFocalPointCenter() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 300, Height = 150 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 300, Height = 150 }); Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString); } @@ -147,7 +150,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidth() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200, HeightRatio = 0.5962962962962962962962962963m }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200, HeightRatio = 0.5962962962962962962962962963m }); Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); } @@ -157,7 +160,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPoint() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus2, Width = 200, HeightRatio = 0.5962962962962962962962962963m }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus2, Width = 200, HeightRatio = 0.5962962962962962962962962963m }); Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString); } @@ -167,7 +170,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPointIgnore() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus2, Width = 270, Height = 161 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = s_focus2, Width = 270, Height = 161 }); Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString); } @@ -177,7 +180,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_PreDefinedCropNoCoordinatesWithHeight() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200, WidthRatio = 1.6770186335403726708074534161m }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200, WidthRatio = 1.6770186335403726708074534161m }); Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString); } @@ -187,7 +190,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_WidthOnlyParameter() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200 }); Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=200", urlString); } @@ -197,7 +200,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_HeightOnlyParameter() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200 }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200 }); Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&height=200", urlString); } @@ -207,7 +210,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media [Test] public void GetCropUrl_BackgroundColorParameter() { - var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 400, Height = 400, FurtherOptions = "&bgcolor=fff" }); + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = ImageCropMode.Pad, Width = 400, Height = 400, FurtherOptions = "&bgcolor=fff" }); Assert.AreEqual(MediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/AlterMigrationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/AlterMigrationTests.cs index 23ee3e143a..c09b354bef 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/AlterMigrationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/AlterMigrationTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using System.Linq; using Microsoft.Extensions.Logging; @@ -15,7 +18,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations { private readonly ILogger _logger = Mock.Of>(); - [Test] public void Drop_Foreign_Key() { @@ -34,7 +36,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations // Assert Assert.That(database.Operations.Count, Is.EqualTo(1)); - Assert.That(database.Operations[0].Sql, + Assert.That( + database.Operations[0].Sql, Is.EqualTo("ALTER TABLE [umbracoUser2app] DROP CONSTRAINT [FK_umbracoUser2app_umbracoUser_id]")); } @@ -53,7 +56,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations } Assert.That(database.Operations.Count, Is.EqualTo(1)); - Assert.That(database.Operations[0].Sql, + Assert.That( + database.Operations[0].Sql, Is.EqualTo("ALTER TABLE [bar] ADD [foo] UniqueIdentifier NOT NULL")); } @@ -82,7 +86,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations } Assert.That(database.Operations.Count, Is.EqualTo(1)); - Assert.That(database.Operations[0].Sql, + Assert.That( + database.Operations[0].Sql, Is.EqualTo("ALTER TABLE [bar] ALTER COLUMN [foo] UniqueIdentifier NOT NULL")); } @@ -94,8 +99,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations } public override void Migrate() => + // bad/good syntax... - //Alter.Column("foo").OnTable("bar").AsGuid().NotNullable(); + //// Alter.Column("foo").OnTable("bar").AsGuid().NotNullable(); Alter.Table("bar").AlterColumn("foo").AsGuid().NotNullable().Do(); } @@ -114,9 +120,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations // Assert Assert.That(database.Operations.Any(), Is.True); - //Console output + // Console output Debug.Print("Number of expressions in context: {0}", database.Operations.Count); - Debug.Print(""); + Debug.Print(string.Empty); foreach (TestDatabase.Operation expression in database.Operations) { Debug.Print(expression.ToString()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs index 0511ee6290..a0d0966b99 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -32,8 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations .Setup(x => x.Database) .Returns(database); - var sqlContext = new SqlContext(new SqlServerSyntaxProvider(), DatabaseType.SQLCe, - Mock.Of()); + var sqlContext = new SqlContext(new SqlServerSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; IMigrationBuilder migrationBuilder = Mock.Of(); @@ -68,8 +70,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations var sourceState = kvs.GetValue("Umbraco.Tests.MigrationPlan") ?? string.Empty; // execute plan - state = plan.Execute(s, sourceState, migrationBuilder, loggerFactory.CreateLogger(), - loggerFactory); + state = plan.Execute(s, sourceState, migrationBuilder, loggerFactory.CreateLogger(), loggerFactory); // save new state kvs.SetValue("Umbraco.Tests.MigrationPlan", sourceState, state); @@ -97,10 +98,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations public void CannotTransitionToSameState() { var plan = new MigrationPlan("default"); - Assert.Throws(() => - { - plan.From("aaa").To("aaa"); - }); + Assert.Throws(() => plan.From("aaa").To("aaa")); } [Test] @@ -108,10 +106,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations { var plan = new MigrationPlan("default"); plan.From("aaa").To("bbb"); - Assert.Throws(() => - { - plan.From("aaa").To("ccc"); - }); + Assert.Throws(() => plan.From("aaa").To("ccc")); } [Test] @@ -191,7 +186,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations WritePlanToConsole(plan); plan.Validate(); - AssertList(plan.FollowPath(), "", "aaa", "bbb", "ccc", "*", "*", "fff", "ggg"); + AssertList(plan.FollowPath(), string.Empty, "aaa", "bbb", "ccc", "*", "*", "fff", "ggg"); AssertList(plan.FollowPath("ccc"), "ccc", "*", "*", "fff", "ggg"); AssertList(plan.FollowPath("eee"), "eee", "*", "*", "fff", "ggg"); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationTests.cs index 34093d0bce..b37338c08b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Data; using Microsoft.Extensions.Logging; using Moq; @@ -37,7 +40,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations public IScope DetachScope() => throw new NotImplementedException(); - public IScopeContext Context { get; set; } public ISqlContext SqlContext { get; set; } @@ -85,7 +87,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Migrations { } - public override void Migrate() => Execute.Sql("").Do(); + public override void Migrate() => Execute.Sql(string.Empty).Do(); } public class BadMigration1 : MigrationBase diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/PostMigrationTests.cs index 2b3e626d03..d1df3a8098 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/PostMigrationTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/AlterUserTableMigrationStub.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/AlterUserTableMigrationStub.cs index ee212fa96f..a5c119f995 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/AlterUserTableMigrationStub.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/AlterUserTableMigrationStub.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,7 +9,8 @@ namespace Umbraco.Tests.Migrations.Stubs { public AlterUserTableMigrationStub(IMigrationContext context) : base(context) - { } + { + } public override void Migrate() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/DropForeignKeyMigrationStub.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/DropForeignKeyMigrationStub.cs index 02561fb563..cf3a26c7d3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/DropForeignKeyMigrationStub.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/DropForeignKeyMigrationStub.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,7 +9,8 @@ namespace Umbraco.Tests.Migrations.Stubs { public DropForeignKeyMigrationStub(IMigrationContext context) : base(context) - { } + { + } public override void Migrate() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/Dummy.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/Dummy.cs index 1a81120a14..f998c4b8a4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/Dummy.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/Dummy.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FiveZeroMigration.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FiveZeroMigration.cs index f69862610f..d870ef82db 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FiveZeroMigration.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FiveZeroMigration.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,9 +9,11 @@ namespace Umbraco.Tests.Migrations.Stubs { public FiveZeroMigration(IMigrationContext context) : base(context) - { } + { + } public override void Migrate() - { } + { + } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FourElevenMigration.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FourElevenMigration.cs index fb1d905c0b..c168fa1c8f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FourElevenMigration.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/FourElevenMigration.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,8 +9,8 @@ namespace Umbraco.Tests.Migrations.Stubs { public FourElevenMigration(IMigrationContext context) : base(context) - { } - + { + } public override void Migrate() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration1.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration1.cs index d3bdc48cbf..1b5c580d5f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration1.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration1.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,8 +9,8 @@ namespace Umbraco.Tests.Migrations.Stubs { public SixZeroMigration1(IMigrationContext context) : base(context) - { } - + { + } public override void Migrate() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration2.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration2.cs index ed3f7b29ea..689e770a98 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration2.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/Stubs/SixZeroMigration2.cs @@ -1,4 +1,7 @@ -using Umbraco.Core.Migrations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Core.Migrations; namespace Umbraco.Tests.Migrations.Stubs { @@ -6,8 +9,8 @@ namespace Umbraco.Tests.Migrations.Stubs { public SixZeroMigration2(IMigrationContext context) : base(context) - { } - + { + } public override void Migrate() { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs index b94effb907..71087917b0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs @@ -1,4 +1,8 @@ -using Newtonsoft.Json; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Reflection; +using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; @@ -12,19 +16,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models private DataTypeBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new DataTypeBuilder(); - } + public void SetUp() => _builder = new DataTypeBuilder(); [Test] public void Can_Deep_Clone() { - var dtd = _builder - .WithId(3123) - .Build(); + DataType dtd = _builder + .WithId(3123) + .Build(); - var clone = (DataType) dtd.DeepClone(); + var clone = (DataType)dtd.DeepClone(); Assert.AreNotSame(clone, dtd); Assert.AreEqual(clone, dtd); @@ -41,9 +42,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models Assert.AreEqual(clone.Trashed, dtd.Trashed); Assert.AreEqual(clone.UpdateDate, dtd.UpdateDate); - //This double verifies by reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) + // This double verifies by reflection + PropertyInfo[] allProps = clone.GetType().GetProperties(); + foreach (PropertyInfo propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(dtd, null)); } @@ -52,10 +53,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models [Test] public void Can_Serialize_Without_Error() { - var item = _builder.Build(); + DataType item = _builder.Build(); Assert.DoesNotThrow(() => JsonConvert.SerializeObject(item)); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs index 117b9d87cc..8a341687f5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs @@ -1,7 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; @@ -15,114 +18,111 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models private EntitySlimBuilder _builder; [SetUp] - public void SetUp() - { - _builder = new EntitySlimBuilder(); - } + public void SetUp() => _builder = new EntitySlimBuilder(); [Test] public void Validate_Path() { - var entity = _builder + EntitySlim entity = _builder .WithoutIdentity() .Build(); - //it's empty with no id so we need to allow it + // it's empty with no id so we need to allow it Assert.IsTrue(entity.ValidatePath()); entity.Id = 1234; - //it has an id but no path, so we can't allow it + // it has an id but no path, so we can't allow it Assert.IsFalse(entity.ValidatePath()); entity.Path = "-1"; - //invalid path + // invalid path Assert.IsFalse(entity.ValidatePath()); entity.Path = string.Concat("-1,", entity.Id); - //valid path + // valid path Assert.IsTrue(entity.ValidatePath()); } [Test] public void Ensure_Path_Throws_Without_Id() { - var entity = _builder + EntitySlim entity = _builder .WithoutIdentity() .Build(); - //no id assigned + // no id assigned Assert.Throws(() => entity.EnsureValidPath(Mock.Of>(), umbracoEntity => new EntitySlim(), umbracoEntity => { })); } [Test] public void Ensure_Path_Throws_Without_Parent() { - var entity = _builder + EntitySlim entity = _builder .WithId(1234) .WithNoParentId() .Build(); - //no parent found + // no parent found Assert.Throws(() => entity.EnsureValidPath(Mock.Of>(), umbracoEntity => null, umbracoEntity => { })); } [Test] public void Ensure_Path_Entity_At_Root() { - var entity = _builder + EntitySlim entity = _builder .WithId(1234) .Build(); entity.EnsureValidPath(Mock.Of>(), umbracoEntity => null, umbracoEntity => { }); - //works because it's under the root + // works because it's under the root Assert.AreEqual("-1,1234", entity.Path); } [Test] public void Ensure_Path_Entity_Valid_Parent() { - var entity = _builder + EntitySlim entity = _builder .WithId(1234) .WithParentId(888) .Build(); entity.EnsureValidPath(Mock.Of>(), umbracoEntity => umbracoEntity.ParentId == 888 ? new EntitySlim { Id = 888, Path = "-1,888" } : null, umbracoEntity => { }); - //works because the parent was found + // works because the parent was found Assert.AreEqual("-1,888,1234", entity.Path); } [Test] public void Ensure_Path_Entity_Valid_Recursive_Parent() { - var parentA = _builder + EntitySlim parentA = _builder .WithId(999) .Build(); // Re-creating the class-level builder as we need to reset before usage when creating multiple entities. _builder = new EntitySlimBuilder(); - var parentB = _builder + EntitySlim parentB = _builder .WithId(888) .WithParentId(999) .Build(); _builder = new EntitySlimBuilder(); - var parentC = _builder + EntitySlim parentC = _builder .WithId(777) .WithParentId(888) .Build(); _builder = new EntitySlimBuilder(); - var entity = _builder + EntitySlim entity = _builder .WithId(1234) .WithParentId(777) .Build(); - Func getParent = umbracoEntity => + IUmbracoEntity GetParent(IUmbracoEntity umbracoEntity) { switch (umbracoEntity.ParentId) { @@ -137,10 +137,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models default: return null; } - }; + } - //this will recursively fix all paths - entity.EnsureValidPath(Mock.Of>(), getParent, umbracoEntity => { }); + // this will recursively fix all paths + entity.EnsureValidPath(Mock.Of>(), GetParent, umbracoEntity => { }); Assert.AreEqual("-1,999", parentA.Path); Assert.AreEqual("-1,999,888", parentB.Path); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/BulkDataReaderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/BulkDataReaderTests.cs index 10926ef20a..e01f071f3c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/BulkDataReaderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/BulkDataReaderTests.cs @@ -1,8 +1,12 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Data.Common; +using System.Data.SqlClient; using NUnit.Framework; using Umbraco.Core.Persistence; @@ -16,11 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// See: https://blogs.msdn.microsoft.com/anthonybloesch/2013/01/23/bulk-loading-data-with-idatareader-and-sqlbulkcopy/ /// [TestFixture] - public class BulkDataReaderTest + public class BulkDataReaderTests { - - #region Test constants - /// /// The schema name. /// @@ -56,10 +57,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// private const string TestXmlSchemaCollectionName = "Xml"; - #endregion - - #region Schema tests - /// /// Test that is functioning correctly. /// @@ -69,12 +66,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { using (var testReader = new BulkDataReaderSubclass()) { - var columnMappings = testReader.ColumnMappings; + ReadOnlyCollection columnMappings = testReader.ColumnMappings; Assert.IsTrue(columnMappings.Count > 0); Assert.AreEqual(columnMappings.Count, testReader.FieldCount); - foreach (var columnMapping in columnMappings) + foreach (SqlBulkCopyColumnMapping columnMapping in columnMappings) { Assert.AreEqual(columnMapping.SourceColumn, columnMapping.DestinationColumn); } @@ -82,9 +79,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test that is functioning correctly. + /// Test that is functioning correctly. /// - /// + /// [Test] public void GetDataTypeNameTest() { @@ -92,19 +89,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { Assert.IsTrue(testReader.FieldCount > 0); - for (var currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) + for (int currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) { - var schemaTable = testReader.GetSchemaTable(); + DataTable schemaTable = testReader.GetSchemaTable(); Assert.IsNotNull(schemaTable); - Assert.AreEqual(testReader.GetDataTypeName(currentColumn), ((Type) schemaTable.Rows[currentColumn][SchemaTableColumn.DataType]).Name); + Assert.AreEqual(testReader.GetDataTypeName(currentColumn), ((Type)schemaTable.Rows[currentColumn][SchemaTableColumn.DataType]).Name); } } } /// - /// Test that is functioning correctly. + /// Test that is functioning correctly. /// - /// + /// [Test] public void GetFieldTypeTest() { @@ -112,9 +109,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { Assert.IsTrue(testReader.FieldCount > 0); - for (var currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) + for (int currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) { - var schemaTable = testReader.GetSchemaTable(); + DataTable schemaTable = testReader.GetSchemaTable(); Assert.IsNotNull(schemaTable); Assert.AreEqual(testReader.GetFieldType(currentColumn), schemaTable.Rows[currentColumn][SchemaTableColumn.DataType]); } @@ -122,9 +119,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test that is functioning correctly. + /// Test that is functioning correctly. /// - /// + /// [Test] public void GetOrdinalTest() { @@ -132,7 +129,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { Assert.IsTrue(testReader.FieldCount > 0); - for (var currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) + for (int currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) { Assert.AreEqual(testReader.GetOrdinal(testReader.GetName(currentColumn)), currentColumn); Assert.AreEqual(testReader.GetOrdinal(testReader.GetName(currentColumn).ToUpperInvariant()), currentColumn); @@ -152,7 +149,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { using (var testReader = new BulkDataReaderSubclass()) { - var schemaTable = testReader.GetSchemaTable(); + DataTable schemaTable = testReader.GetSchemaTable(); Assert.IsNotNull(schemaTable); Assert.IsTrue(schemaTable.Rows.Count > 0); @@ -161,13 +158,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test that + /// Test that /// throws a for null column names. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNullColumnNameTest() { @@ -189,19 +186,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty column names. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowEmptyColumnNameTest() { @@ -223,19 +220,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nonpositive column sizes. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNonpositiveColumnSizeTest() { @@ -257,19 +254,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nonpositive numeric precision. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNonpositiveNumericPrecisionTest() { @@ -291,19 +288,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for negative numeric scale. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNegativeNumericScaleTest() { @@ -325,19 +322,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for binary column without a column size. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowBinaryWithoutSizeTest() { @@ -359,19 +356,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for binary column with a column size that is too large (>8000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowBinaryWithTooLargeSizeTest() { @@ -393,19 +390,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for char column without a column size. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowCharWithoutSizeTest() { @@ -427,19 +424,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for char column with a column size that is too large (>8000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowCharWithTooLargeSizeTest() { @@ -461,19 +458,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for decimal column without a column precision. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDecimalWithoutPrecisionTest() { @@ -495,19 +492,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for decimal column without a column scale. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDecimalWithoutScaleTest() { @@ -529,19 +526,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for decimal column with a column precision that is too large (>38). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDecimalWithTooLargePrecisionTest() { @@ -563,19 +560,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for decimal column with a column scale that is larger than the column precision. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDecimalWithTooLargeScaleTest() { @@ -597,19 +594,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for datetime2 column with a column size that has a precision that is too large (>7). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDateTime2WithTooLargePrecisionTest() { @@ -631,19 +628,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for datetimeoffset column with a column size that has a precision that is too large (>7). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowDateTimeOffsetWithTooLargePrecisionTest() { @@ -665,19 +662,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nchar column without a precision. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowFloatWithoutPrecisionTest() { @@ -699,19 +696,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for float column with a column precision that is too large (>53). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowFloatWithTooLargePrecisionTest() { @@ -733,19 +730,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nchar column without a column size. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNCharWithoutSizeTest() { @@ -767,19 +764,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nchar column with a column size that is too large (>4000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNCharWithTooLargeSizeTest() { @@ -801,19 +798,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for nvarchar column with a column size that is too large (>4000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowNVarCharWithTooLargeSizeTest() { @@ -835,19 +832,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for time column with a column precision that is too large (>7). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowTimeWithTooLargePrecisionTest() { @@ -869,19 +866,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for missing UDT schema name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowUdtMissingSchemaNameTest() { @@ -903,19 +900,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty UDT schema name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowUdtEmptySchemaNameTest() { @@ -937,19 +934,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for missing UDT name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowUdtMissingNameTest() { @@ -971,19 +968,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty UDT name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowUdtEmptyNameTest() { @@ -1005,19 +1002,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for varbinary column with a column size that is too large (>8000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowVarBinaryWithTooLargeSizeTest() { @@ -1039,19 +1036,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for varchar column with a column size that is too large (>8000). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowVarCharWithTooLargeSizeTest() { @@ -1073,19 +1070,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for null xml collection name but with a name for the database. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowXmlNullNameWithDatabaseNameTest() { @@ -1107,19 +1104,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for null xml collection name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowXmlNullNameWithOwningSchemaNameTest() { @@ -1141,19 +1138,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty xml collection database name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowXmlEmptyDatabaseNameTest() { @@ -1175,19 +1172,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty xml collection owning schema name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowXmlEmptyOwningSchemaNameTest() { @@ -1209,19 +1206,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for empty xml collection name. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowXmlEmptyNameTest() { @@ -1243,19 +1240,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for a structured column (which is illegal). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowStructuredTypeTest() { @@ -1277,19 +1274,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws a for a timestamp column (which is illegal). /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowTimestampTypeTest() { @@ -1311,23 +1308,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); }); } } /// - /// Test that + /// Test that /// throws an for a column with an unallowed optional column set. /// /// /// Uses to test the illegal schema combination. /// - /// + /// [Test] public void AddSchemaTableRowUnallowedOptionalColumnTest() { - // Column size set using (var testReader = new BulkDataReaderSchemaTest()) { @@ -1344,17 +1340,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Bit, SqlDbType.Date, SqlDbType.DateTime, SqlDbType.DateTime2, - SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.Real, - SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, - SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, - SqlDbType.Variant, SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Bit, SqlDbType.Date, SqlDbType.DateTime, SqlDbType.DateTime2, + SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.Real, + SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, + SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, + SqlDbType.Variant, SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1380,18 +1379,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, - SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, - SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.Udt, SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, - SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, + SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, + SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.Udt, SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, + SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1417,18 +1419,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, - SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, - SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, - SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, - SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, + SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, + SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, + SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, + SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1454,18 +1459,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, - SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, - SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, - SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, - SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Image, SqlDbType.Int, + SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, SqlDbType.NVarChar, SqlDbType.Real, + SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, SqlDbType.Structured, SqlDbType.Text, + SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, SqlDbType.Udt, SqlDbType.UniqueIdentifier, + SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1491,18 +1499,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, - SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, - SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, - SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, + SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, + SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, + SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1528,18 +1539,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = null; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, - SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, - SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, - SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, + SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, + SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, + SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Xml + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1565,18 +1579,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = null; testReader.XmlSchemaCollectionName = "Name"; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, - SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, - SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, - SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, + SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, + SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, + SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1602,18 +1619,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = "Schema"; testReader.XmlSchemaCollectionName = "Name"; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, - SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, - SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, - SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, + SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, + SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, + SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1639,18 +1659,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence testReader.XmlSchemaCollectionOwningSchema = "Schema"; testReader.XmlSchemaCollectionName = "Name"; - foreach (var dbtype in new List { SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, - SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, - SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, - SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, - SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, - SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt }) + foreach (SqlDbType dbtype in new List + { + SqlDbType.BigInt, SqlDbType.Binary, SqlDbType.Bit, SqlDbType.Char, SqlDbType.Date, + SqlDbType.DateTime, SqlDbType.DateTime2, SqlDbType.DateTimeOffset, SqlDbType.Decimal, SqlDbType.Float, + SqlDbType.Image, SqlDbType.Int, SqlDbType.Money, SqlDbType.NChar, SqlDbType.NText, + SqlDbType.NVarChar, SqlDbType.Real, SqlDbType.SmallDateTime, SqlDbType.SmallInt, SqlDbType.SmallMoney, + SqlDbType.Structured, SqlDbType.Text, SqlDbType.Time, SqlDbType.Timestamp, SqlDbType.TinyInt, + SqlDbType.UniqueIdentifier, SqlDbType.VarBinary, SqlDbType.VarChar, SqlDbType.Variant, SqlDbType.Udt + }) { testReader.ProviderType = dbtype; try { - var unused = testReader.GetSchemaTable(); + DataTable unused = testReader.GetSchemaTable(); Assert.Fail(); } @@ -1661,10 +1684,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } } - #endregion; - - #region Rowset tests - /// /// Test that is functioning correctly. /// @@ -1698,12 +1717,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test that is functioning correctly. + /// Test that is functioning correctly. /// /// /// Because nested row sets are not supported, this should always return null; /// - /// + /// [Test] public void GetDataTest() { @@ -1718,7 +1737,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test and related functions. + /// Test and related functions. /// /// /// Uses to test legal schema combinations. @@ -1731,13 +1750,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.IsTrue(testReader.Read()); // this[int] - for (var column = 0; column < BulkDataReaderSubclass.ExpectedResultSet.Count; column++) + for (int column = 0; column < BulkDataReaderSubclass.ExpectedResultSet.Count; column++) { Assert.AreEqual(testReader[column], BulkDataReaderSubclass.ExpectedResultSet[column]); } // this[string] - for (var column = 0; column < BulkDataReaderSubclass.ExpectedResultSet.Count; column++) + for (int column = 0; column < BulkDataReaderSubclass.ExpectedResultSet.Count; column++) { Assert.AreEqual(testReader[testReader.GetName(column)], BulkDataReaderSubclass.ExpectedResultSet[column]); @@ -1746,8 +1765,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence // GetValues { - var values = new object[BulkDataReaderSubclass.ExpectedResultSet.Count]; - var expectedValues = new object[BulkDataReaderSubclass.ExpectedResultSet.Count]; + object[] values = new object[BulkDataReaderSubclass.ExpectedResultSet.Count]; + object[] expectedValues = new object[BulkDataReaderSubclass.ExpectedResultSet.Count]; Assert.AreEqual(testReader.GetValues(values), values.Length); @@ -1758,20 +1777,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence // Typed getters { - var currentColumn = 0; + int currentColumn = 0; Assert.AreEqual(testReader.GetInt64(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); currentColumn++; - { - var expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; - var expectedLength = expectedResult.Length; - var buffer = new byte[expectedLength]; + byte[] expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; + int expectedLength = expectedResult.Length; + byte[] buffer = new byte[expectedLength]; Assert.AreEqual(testReader.GetBytes(currentColumn, 0, buffer, 0, expectedLength), expectedLength); Assert.IsTrue(ArraysMatch(buffer, expectedResult)); } + currentColumn++; Assert.AreEqual(testReader.GetBoolean(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); @@ -1790,11 +1809,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence currentColumn++; Assert.AreEqual(testReader.GetString(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); - { - var expectedResult = ((string)BulkDataReaderSubclass.ExpectedResultSet[currentColumn]).ToCharArray(); - var expectedLength = expectedResult.Length; - var buffer = new char[expectedLength]; + char[] expectedResult = ((string)BulkDataReaderSubclass.ExpectedResultSet[currentColumn]).ToCharArray(); + int expectedLength = expectedResult.Length; + char[] buffer = new char[expectedLength]; Assert.AreEqual(testReader.GetChars(currentColumn, 0, buffer, 0, expectedLength), expectedLength); @@ -1826,7 +1844,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.AreEqual(testReader.GetDouble(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); currentColumn++; - { byte[] expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; int expectedLength = expectedResult.Length; @@ -1836,6 +1853,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.IsTrue(ArraysMatch(buffer, expectedResult)); } + currentColumn++; Assert.AreEqual(testReader.GetInt32(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); @@ -1885,20 +1903,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.AreEqual(testReader.GetGuid(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); currentColumn++; - { - var expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; - var expectedLength = expectedResult.Length; - var buffer = new byte[expectedLength]; - - Assert.AreEqual(testReader.GetBytes(currentColumn, 0, buffer, 0, expectedLength), expectedLength); - - Assert.IsTrue(ArraysMatch(buffer, expectedResult)); - } - currentColumn++; - - { - var expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; + byte[] expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; int expectedLength = expectedResult.Length; byte[] buffer = new byte[expectedLength]; @@ -1906,6 +1912,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.IsTrue(ArraysMatch(buffer, expectedResult)); } + + currentColumn++; + { + byte[] expectedResult = (byte[])BulkDataReaderSubclass.ExpectedResultSet[currentColumn]; + int expectedLength = expectedResult.Length; + byte[] buffer = new byte[expectedLength]; + + Assert.AreEqual(testReader.GetBytes(currentColumn, 0, buffer, 0, expectedLength), expectedLength); + + Assert.IsTrue(ArraysMatch(buffer, expectedResult)); + } + currentColumn++; Assert.AreEqual(testReader.GetString(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn]); @@ -1935,13 +1953,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } /// - /// Test throws a when + /// Test throws a when /// the index is too small. /// /// /// Uses to test the method. /// - /// + /// [Test] public void GetValueIndexTooSmallTest() { @@ -1951,19 +1969,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetValue(-1); + object unused = testReader.GetValue(-1); }); } } /// - /// Test throws a when + /// Test throws a when /// the index is too large. /// /// /// Uses to test the method. /// - /// + /// [Test] public void GetValueIndexTooLargeTest() { @@ -1973,19 +1991,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetValue(testReader.FieldCount); + object unused = testReader.GetValue(testReader.FieldCount); }); } } /// - /// Test throws a when + /// Test throws a when /// the index is too small. /// /// /// Uses to test the method. /// - /// + /// [Test] public void GetDataIndexTooSmallTest() { @@ -1995,13 +2013,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetData(-1); + IDataReader unused = testReader.GetData(-1); }); } } /// - /// Test throws a when + /// Test throws a when /// the index is too large. /// /// @@ -2016,21 +2034,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence Assert.Throws(() => { - var unused = testReader.GetData(testReader.FieldCount); + IDataReader unused = testReader.GetData(testReader.FieldCount); }); } } /// - /// Test that functions correctly. + /// Test that functions correctly. /// - /// + /// [Test] public void IsDbNullTest() { using (var testReader = new BulkDataReaderSubclass()) { - for (var currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) + for (int currentColumn = 0; currentColumn < testReader.FieldCount; currentColumn++) { Assert.AreEqual(testReader.IsDBNull(currentColumn), BulkDataReaderSubclass.ExpectedResultSet[currentColumn] == null); } @@ -2071,10 +2089,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } } - #endregion - - #region Test IDisposable - /// /// Test that the interface is functioning correctly. /// @@ -2104,27 +2118,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence } } - #endregion - - #region Utility - /// - /// Do the two arrays match exactly? + /// Do the two arrays match exactly? /// - /// + /// /// The type of the array elements. /// /// - /// The first array. + /// The first array. /// /// - /// The second array. + /// The second array. /// /// - /// True if the arrays have the same length and contents. + /// True if the arrays have the same length and contents. /// - private static bool ArraysMatch(ElementType[] left, - ElementType[] right) + private static bool ArraysMatch(TElementType[] left, TElementType[] right) { if (left == null) { @@ -2152,18 +2161,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence return result; } - #endregion - - #region Test stubs - /// /// A subclass of used for testing its utility functions. /// private class BulkDataReaderSubclass : BulkDataReader { - - #region Constructors - /// /// Constructor. /// @@ -2171,31 +2173,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { } - #endregion - - #region BulkDataReader - /// /// See . /// /// - /// Returns . + /// Returns . /// - protected override string SchemaName - { - get { return BulkDataReaderTest.TestSchemaName; } - } + protected override string SchemaName => BulkDataReaderTests.TestSchemaName; /// /// See . /// /// - /// Returns . + /// Returns . /// - protected override string TableName - { - get { return BulkDataReaderTest.TestTableName; } - } + protected override string TableName => BulkDataReaderTests.TestTableName; /// /// See @@ -2236,17 +2228,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence AddSchemaTableRow("Time", null, null, null, false, false, false, SqlDbType.Time, null, null, null, null, null); AddSchemaTableRow("Time_5", null, 5, null, false, false, false, SqlDbType.Time, null, null, null, null, null); AddSchemaTableRow("TinyInt", null, null, null, false, false, false, SqlDbType.TinyInt, null, null, null, null, null); - AddSchemaTableRow("Udt", null, null, null, false, false, false, SqlDbType.Udt, BulkDataReaderTest.TestUdtSchemaName, BulkDataReaderTest.TestUdtName, null, null, null); + AddSchemaTableRow("Udt", null, null, null, false, false, false, SqlDbType.Udt, BulkDataReaderTests.TestUdtSchemaName, BulkDataReaderTests.TestUdtName, null, null, null); AddSchemaTableRow("UniqueIdentifier", null, null, null, false, false, false, SqlDbType.UniqueIdentifier, null, null, null, null, null); AddSchemaTableRow("VarBinary_20", 20, null, null, false, false, false, SqlDbType.VarBinary, null, null, null, null, null); AddSchemaTableRow("VarBinary_Max", null, null, null, false, false, false, SqlDbType.VarBinary, null, null, null, null, null); AddSchemaTableRow("VarChar_20", 20, null, null, false, false, false, SqlDbType.VarChar, null, null, null, null, null); AddSchemaTableRow("VarChar_Max", null, null, null, false, false, false, SqlDbType.VarChar, null, null, null, null, null); AddSchemaTableRow("Variant", null, null, null, false, false, false, SqlDbType.Variant, null, null, null, null, null); - AddSchemaTableRow("Xml_Database", null, null, null, false, false, false, SqlDbType.Xml, null, null, BulkDataReaderTest.TestXmlSchemaCollectionDatabaseName, BulkDataReaderTest.TestXmlSchemaCollectionSchemaName, BulkDataReaderTest.TestXmlSchemaCollectionName); - AddSchemaTableRow("Xml_Database_XML", null, null, null, false, false, false, SqlDbType.Xml, null, null, BulkDataReaderTest.TestXmlSchemaCollectionDatabaseName, BulkDataReaderTest.TestXmlSchemaCollectionSchemaName, BulkDataReaderTest.TestXmlSchemaCollectionName); - AddSchemaTableRow("Xml_Schema", null, null, null, false, false, false, SqlDbType.Xml, null, null, null, BulkDataReaderTest.TestXmlSchemaCollectionSchemaName, BulkDataReaderTest.TestXmlSchemaCollectionName); - AddSchemaTableRow("Xml_Xml", null, null, null, false, false, false, SqlDbType.Xml, null, null, null, null, BulkDataReaderTest.TestXmlSchemaCollectionName); + AddSchemaTableRow("Xml_Database", null, null, null, false, false, false, SqlDbType.Xml, null, null, BulkDataReaderTests.TestXmlSchemaCollectionDatabaseName, BulkDataReaderTests.TestXmlSchemaCollectionSchemaName, BulkDataReaderTests.TestXmlSchemaCollectionName); + AddSchemaTableRow("Xml_Database_XML", null, null, null, false, false, false, SqlDbType.Xml, null, null, BulkDataReaderTests.TestXmlSchemaCollectionDatabaseName, BulkDataReaderTests.TestXmlSchemaCollectionSchemaName, BulkDataReaderTests.TestXmlSchemaCollectionName); + AddSchemaTableRow("Xml_Schema", null, null, null, false, false, false, SqlDbType.Xml, null, null, null, BulkDataReaderTests.TestXmlSchemaCollectionSchemaName, BulkDataReaderTests.TestXmlSchemaCollectionName); + AddSchemaTableRow("Xml_Xml", null, null, null, false, false, false, SqlDbType.Xml, null, null, null, null, BulkDataReaderTests.TestXmlSchemaCollectionName); AddSchemaTableRow("Xml", null, null, null, false, false, false, SqlDbType.Xml, null, null, null, null, null); } @@ -2255,7 +2247,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// public static readonly ReadOnlyCollection ExpectedResultSet = new ReadOnlyCollection(new List { - (long)10, + 10L, new byte[20], true, null, @@ -2269,19 +2261,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence DateTime.UtcNow, DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, - (decimal)10.5, + 10.5M, (double)10.5, new byte[20], (int)10, - (decimal)10.5, + 10.5M, "nchar 20", "ntext", "nvarchar 20", "nvarchar max", - (float)10.5, + 10.5F, DateTime.UtcNow, (short)10, - (decimal)10.5, + 10.5M, "text", DateTime.UtcNow.TimeOfDay, DateTime.UtcNow.TimeOfDay, @@ -2301,7 +2293,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence }); /// - /// See + /// See /// /// /// The zero-based column ordinal. @@ -2309,16 +2301,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// /// The value of the column in . /// - /// - public override object GetValue(int i) - { - return BulkDataReaderSubclass.ExpectedResultSet[i]; - } + /// + public override object GetValue(int i) => BulkDataReaderSubclass.ExpectedResultSet[i]; /// /// The number of rows read. /// - private int readCount = 0; + private int _readCount = 0; /// /// See @@ -2327,89 +2316,76 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// True if there are more rows; otherwise, false. /// /// - public override bool Read() - { - return readCount++ < 1; - } - - #endregion - + public override bool Read() => _readCount++ < 1; } private class BulkDataReaderSchemaTest : BulkDataReader { - - #region Properties - /// - /// Is the column nullable (i.e. optional)? + /// Gets or sets a value indicating whether the column is nullable (i.e. optional). /// public bool AllowDBNull { get; set; } /// - /// The name of the column. + /// Gets or sets the name of the column. /// public string ColumnName { get; set; } /// - /// The size of the column which may be null if not applicable. + /// Gets or sets the size of the column which may be null if not applicable. /// public int? ColumnSize { get; set; } /// - /// Is the column part of the primary key? + /// Gets or sets a value indicating whether the column part of the primary key. /// public bool IsKey { get; set; } /// - /// Are the column values unique (i.e. never duplicated)? + /// Gets or sets a value indicating whether the column values are unique (i.e. never duplicated). /// public bool IsUnique { get; set; } /// - /// The precision of the column which may be null if not applicable. + /// Gets or sets the precision of the column which may be null if not applicable. /// public short? NumericPrecision { get; set; } /// - /// The scale of the column which may be null if not applicable. + /// Gets or sets the scale of the column which may be null if not applicable. /// public short? NumericScale { get; set; } /// - /// The corresponding . + /// Gets or sets the corresponding . /// public SqlDbType ProviderType { get; set; } /// - /// The schema name of the UDT. + /// Gets or sets the schema name of the UDT. /// public string UdtSchema { get; set; } /// - /// The type name of the UDT. + /// Gets or sets the type name of the UDT. /// public string UdtType { get; set; } /// - /// For XML columns the schema collection's database name. Otherwise, null. + /// Gets or sets the schema collection's database name for XML columns. Otherwise, null. /// public string XmlSchemaCollectionDatabase { get; set; } /// - /// For XML columns the schema collection's name. Otherwise, null. + /// Gets or sets the schema collection's name for XML columns. Otherwise, null. /// public string XmlSchemaCollectionName { get; set; } /// - /// For XML columns the schema collection's schema name. Otherwise, null. + /// Gets or sets the schema collection's scheme name for XML columns. Otherwise, null. /// public string XmlSchemaCollectionOwningSchema { get; set; } - #endregion - - #region Constructors - /// /// Constructor. /// @@ -2417,31 +2393,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence { } - #endregion - - #region BulkDataReader - /// /// See . /// /// - /// Returns . + /// Returns . /// - protected override string SchemaName - { - get { return BulkDataReaderTest.TestSchemaName; } - } + protected override string SchemaName => BulkDataReaderTests.TestSchemaName; /// /// See . /// /// - /// Returns . + /// Returns . /// - protected override string TableName - { - get { return BulkDataReaderTest.TestTableName; } - } + protected override string TableName => BulkDataReaderTests.TestTableName; /// /// See @@ -2449,25 +2415,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// /// Creates a schema row for the various values. /// - protected override void AddSchemaTableRows() - { - AddSchemaTableRow(this.ColumnName, - this.ColumnSize, - this.NumericPrecision, - this.NumericScale, - this.IsUnique, - this.IsKey, - this.AllowDBNull, - this.ProviderType, - this.UdtSchema, - this.UdtType, - this.XmlSchemaCollectionDatabase, - this.XmlSchemaCollectionOwningSchema, - this.XmlSchemaCollectionName); - } + protected override void AddSchemaTableRows() => + AddSchemaTableRow( + ColumnName, + ColumnSize, + NumericPrecision, + NumericScale, + IsUnique, + IsKey, + AllowDBNull, + ProviderType, + UdtSchema, + UdtType, + XmlSchemaCollectionDatabase, + XmlSchemaCollectionOwningSchema, + XmlSchemaCollectionName); /// - /// See + /// See /// /// /// The test stub is only for testing schema functionality and behaves as if it has no rows. @@ -2478,12 +2443,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// /// Never returns. /// - /// - public override object GetValue(int i) - { - throw new InvalidOperationException("No data."); - } - + /// + public override object GetValue(int i) => throw new InvalidOperationException("No data."); /// /// See @@ -2492,15 +2453,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence /// False. /// /// - public override bool Read() - { - return false; - } - - #endregion - + public override bool Read() => false; } - - #endregion } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentMapperTest.cs index 7c0ea0d642..5db6493858 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Mappers; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentTypeMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentTypeMapperTest.cs index 6666055ed7..923de28f13 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentTypeMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/ContentTypeMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -20,7 +23,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Name_Property() { - // Act string column = new ContentTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Name"); @@ -31,7 +33,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Thumbnail_Property() { - // Act string column = new ContentTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Thumbnail"); @@ -42,7 +43,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Description_Property() { - // Act string column = new ContentTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Description"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DataTypeMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DataTypeMapperTest.cs index 0725528254..7fdd2882c4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DataTypeMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DataTypeMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -21,7 +24,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Key_Property() { - // Act string column = new DataTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Key"); @@ -32,7 +34,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_DatabaseType_Property() { - // Act string column = new DataTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("DatabaseType"); @@ -43,7 +44,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_PropertyEditorAlias_Property() { - // Act string column = new DataTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("EditorAlias"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryMapperTest.cs index a27fc89dac..f31110f30a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -20,7 +23,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Key_Property() { - // Act string column = new DictionaryMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Key"); @@ -31,7 +33,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_ItemKey_Property() { - // Act string column = new DictionaryMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("ItemKey"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryTranslationMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryTranslationMapperTest.cs index c1fbc6ad61..ebe57e7746 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryTranslationMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/DictionaryTranslationMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -10,7 +13,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Key_Property() { - // Act string column = new DictionaryTranslationMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Key"); @@ -21,7 +23,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Language_Property() { - // Act string column = new DictionaryTranslationMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Language"); @@ -32,7 +33,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Value_Property() { - // Act string column = new DictionaryTranslationMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Value"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/LanguageMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/LanguageMapperTest.cs index 382d8c6826..20a446ad70 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/LanguageMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/LanguageMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -10,7 +13,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_Id_Property() { - // Act string column = new LanguageMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("Id"); @@ -21,7 +23,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_IsoCode_Property() { - // Act string column = new LanguageMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("IsoCode"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/MediaMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/MediaMapperTest.cs index cc7d528c3c..a94e4cade3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/MediaMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/MediaMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyGroupMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyGroupMapperTest.cs index f5fa18e4ee..40c74f25a5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyGroupMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyGroupMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyTypeMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyTypeMapperTest.cs index ba2d40feab..72223e952f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyTypeMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/PropertyTypeMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationMapperTest.cs index 4f1b4a7944..add7cd8b4b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationTypeMapperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationTypeMapperTest.cs index e17d6905ac..310b12c1cf 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationTypeMapperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Mappers/RelationTypeMapperTest.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Persistence.Mappers; using Umbraco.Tests.TestHelpers; @@ -30,7 +33,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_ChildObjectType_Property() { - // Act string column = new RelationTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("ChildObjectType"); @@ -41,7 +43,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Mappers [Test] public void Can_Map_IsBidirectional_Property() { - // Act string column = new RelationTypeMapper(TestHelper.GetMockSqlContext(), TestHelper.CreateMaps()).Map("IsBidirectional"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs index 9e9b148bb6..4ad1b89bf6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlExtensionsTests.cs @@ -1,9 +1,12 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using NPoco; using NUnit.Framework; -using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Querying; using Umbraco.Tests.TestHelpers; using static Umbraco.Core.Persistence.SqlExtensionsStatics; @@ -15,7 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void WhereTest() { - var sql = new Sql(SqlContext) + Sql sql = new Sql(SqlContext) .Select("*") .From() .Where(x => x.LanguageId == null); @@ -45,7 +48,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests // but the above comparison fails if @0 is null // what we want is something similar to: - sql = new Sql(SqlContext) .Select("*") .From() @@ -56,15 +58,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests // 'course it would be nicer if '==' could do it // see note in ExpressionVisitorBase for SqlNullableEquals - //sql = new Sql(SqlContext) + // sql = new Sql(SqlContext) // .Select("*") // .From() // .Where(x => x.LanguageId.SqlNullableEquals(nid)); - //Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@0 is not null) AND ([umbracoPropertyData].[languageId] = @0))))", sql.SQL, sql.SQL); + // Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@0 is not null) AND ([umbracoPropertyData].[languageId] = @0))))", sql.SQL, sql.SQL); // but, the expression above fails with SQL CE, 'specified argument for the function is not valid' in 'isnull' function // so... compare with fallback values - sql = new Sql(SqlContext) .Select("*") .From() @@ -89,7 +90,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void WhereInValueFieldTest() { - var sql = new Sql(SqlContext) + Sql sql = new Sql(SqlContext) .Select("*") .From() .WhereIn(x => x.NodeId, new[] { 1, 2, 3 }); @@ -101,8 +102,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests { // this test used to fail because x => x.Text was evaluated as a lambda // and returned "[umbracoNode].[text] = @0"... had to fix WhereIn. - - var sql = new Sql(SqlContext) + Sql sql = new Sql(SqlContext) .Select("*") .From() .WhereIn(x => x.Text, new[] { "a", "b", "c" }); @@ -113,7 +113,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests public void SelectTests() { // select the whole DTO - var sql = Sql() + Sql sql = Sql() .Select() .From(); Assert.AreEqual("SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] FROM [dto1]", sql.SQL.NoCrLf()); @@ -135,7 +135,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests .Select(r => r.Select(x => x.Dto2)) .From() .InnerJoin().On(left => left.Id, right => right.Dto1Id); - Assert.AreEqual(@"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] + Assert.AreEqual( + @"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] , [dto2].[id] AS [Dto2__Id], [dto2].[dto1id] AS [Dto2__Dto1Id], [dto2].[name] AS [Dto2__Name] FROM [dto1] INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf(), sql.SQL); @@ -146,7 +147,8 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf(), .From() .InnerJoin().On(left => left.Id, right => right.Dto1Id) .InnerJoin().On(left => left.Id, right => right.Dto2Id); - Assert.AreEqual(@"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] + Assert.AreEqual( + @"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] , [dto2].[id] AS [Dto2__Id], [dto2].[dto1id] AS [Dto2__Dto1Id], [dto2].[name] AS [Dto2__Name] , [dto3].[id] AS [Dto2__Dto3__Id], [dto3].[dto2id] AS [Dto2__Dto3__Dto2Id], [dto3].[name] AS [Dto2__Dto3__Name] FROM [dto1] @@ -158,7 +160,8 @@ INNER JOIN [dto3] ON [dto2].[id] = [dto3].[dto2id]".NoCrLf(), sql.SQL.NoCrLf()); .Select(r => r.Select(x => x.Dto2s)) .From() .InnerJoin().On(left => left.Id, right => right.Dto1Id); - Assert.AreEqual(@"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] + Assert.AreEqual( + @"SELECT [dto1].[id] AS [Id], [dto1].[name] AS [Name], [dto1].[value] AS [Value] , [dto2].[id] AS [Dto2s__Id], [dto2].[dto1id] AS [Dto2s__Dto1Id], [dto2].[name] AS [Dto2s__Name] FROM [dto1] INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); @@ -189,7 +192,7 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); [Test] public void UpdateTests() { - var sql = Sql() + Sql sql = Sql() .Update(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker")) .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias"); } @@ -201,12 +204,16 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); { [Column("id")] public int Id { get; set; } + [Column("name")] public string Name { get; set; } + [Column("value")] public int Value { get; set; } + [Reference] public Dto2 Dto2 { get; set; } + [Reference] public List Dto2s { get; set; } } @@ -218,10 +225,13 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); { [Column("id")] public int Id { get; set; } + [Column("dto1id")] public int Dto1Id { get; set; } + [Column("name")] public string Name { get; set; } + [Reference] public Dto3 Dto3 { get; set; } } @@ -233,8 +243,10 @@ INNER JOIN [dto2] ON [dto1].[id] = [dto2].[dto1id]".NoCrLf(), sql.SQL.NoCrLf()); { [Column("id")] public int Id { get; set; } + [Column("dto2id")] public int Dto2Id { get; set; } + [Column("name")] public string Name { get; set; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTemplateTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTemplateTests.cs index 0367571d61..54c9814909 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTemplateTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTemplateTests.cs @@ -1,12 +1,14 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using Moq; using NPoco; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests { @@ -23,14 +25,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests // want to cache as a (static) template for ever, and ever - note // that using a MemoryCache would allow us to set a size limit, or // something equivalent, to reduce risk of memory explosion - var sql = sqlTemplates.Get("xxx", s => s + Sql sql = sqlTemplates.Get("xxx", s => s .SelectAll() .From("zbThing1") .Where("id=@id", new { id = SqlTemplate.Arg("id") })).Sql(new { id = 1 }); - var sql2 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(1); + Sql sql2 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(1); - var sql3 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(new { id = 1 }); + Sql sql3 = sqlTemplates.Get("xxx", x => throw new InvalidOperationException("Should be cached.")).Sql(new { id = 1 }); } [Test] @@ -44,10 +46,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests const string sqlBase = "SELECT [zbThing1].[id] AS [Id], [zbThing1].[name] AS [Name] FROM [zbThing1] WHERE "; - var template = sqlTemplates.Get("sql1", s => s.Select().From() + SqlTemplate template = sqlTemplates.Get("sql1", s => s.Select().From() .Where(x => x.Name == SqlTemplate.Arg("value"))); - var sql = template.Sql("foo"); + Sql sql = template.Sql("foo"); Assert.AreEqual(sqlBase + "(([zbThing1].[name] = @0))", sql.SQL.NoCrLf()); Assert.AreEqual(1, sql.Arguments.Length); Assert.AreEqual("foo", sql.Arguments[0]); @@ -90,7 +92,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests // but we cannot name them, because the arg name is the value of "i" // so we have to explicitely create the argument - template = sqlTemplates.Get("sql4", s => s.Select().From() .Where(x => x.Id == SqlTemplate.Arg("i"))); @@ -105,7 +106,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests Assert.AreEqual(123, sql.Arguments[0]); // and thanks to a patched visitor, this now works - sql = template.Sql(new { i = "foo" }); Assert.AreEqual(sqlBase + "(([zbThing1].[id] = @0))", sql.SQL.NoCrLf()); Assert.AreEqual(1, sql.Arguments.Length); @@ -120,7 +120,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests Assert.Throws(() => template.Sql(new { i = 123, j = 456 })); // now with more arguments - template = sqlTemplates.Get("sql4a", s => s.Select().From() .Where(x => x.Id == SqlTemplate.Arg("i") && x.Name == SqlTemplate.Arg("name"))); sql = template.Sql(0, 1); @@ -139,7 +138,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests Assert.AreEqual(1, sql.Arguments[1]); // works, magic - template = sqlTemplates.Get("sql5", s => s.Select().From() .WhereIn(x => x.Id, SqlTemplate.ArgIn("i"))); @@ -178,20 +176,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests // idea to just add the WhereIn to a templated, immutable SQL template // more fun... - template = sqlTemplates.Get("sql6", s => s.Select().From() + // do NOT do this, this is NOT a visited expression - //.Append(" AND whatever=@0", SqlTemplate.Arg("j")) + //// .Append(" AND whatever=@0", SqlTemplate.Arg("j")) // does not work anymore - due to proper TemplateArg //// instead, directly name the argument - //.Append("AND whatever=@0", "j") - //.Append("AND whatever=@0", "k") + ////.Append("AND whatever=@0", "j") + ////.Append("AND whatever=@0", "k") // instead, explicitely create the argument .Append("AND whatever=@0", SqlTemplate.Arg("j")) - .Append("AND whatever=@0", SqlTemplate.Arg("k")) - ); + .Append("AND whatever=@0", SqlTemplate.Arg("k"))); sql = template.Sql(new { j = new[] { 1, 2, 3 }, k = "oops" }); Assert.AreEqual(sqlBase.TrimEnd("WHERE ") + "AND whatever=@0,@1,@2 AND whatever=@3", sql.SQL.NoCrLf()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTests.cs index 80408bb211..a3fd28d952 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoSqlTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using NPoco; using NUnit.Framework; @@ -7,7 +10,6 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests { @@ -18,7 +20,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests public void Where_Clause_With_Starts_With_Additional_Parameters() { var content = new NodeDto() { NodeId = 123, Path = "-1,123" }; - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Path.SqlStartsWith(content.Path, TextColumnType.NVarchar)); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[path]) LIKE upper(@0))", sql.SQL.Replace("\n", " ")); @@ -29,8 +31,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_Starts_With_By_Variable() { - var content = new NodeDto() {NodeId = 123, Path = "-1,123"}; - var sql = Sql().SelectAll().From() + var content = new NodeDto() { NodeId = 123, Path = "-1,123" }; + Sql sql = Sql().SelectAll().From() .Where(x => x.Path.StartsWith(content.Path) && x.NodeId != content.NodeId); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((upper([umbracoNode].[path]) LIKE upper(@0) AND ([umbracoNode].[id] <> @1)))", sql.SQL.Replace("\n", " ")); @@ -43,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests public void Where_Clause_With_Not_Starts_With() { const int level = 1; - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Level == level && !x.Path.StartsWith("-20")); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((([umbracoNode].[level] = @0) AND NOT (upper([umbracoNode].[path]) LIKE upper(@1))))", sql.SQL.Replace("\n", " ")); @@ -56,7 +58,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests public void Where_Clause_With_EqualsFalse_Starts_With() { const int level = 1; - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Level == level && x.Path.StartsWith("-20") == false); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((([umbracoNode].[level] = @0) AND NOT (upper([umbracoNode].[path]) LIKE upper(@1))))", sql.SQL.Replace("\n", " ")); @@ -68,7 +70,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_Equals_Clause() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Text.Equals("Hello@world.com")); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[text]) = upper(@0))", sql.SQL.Replace("\n", " ")); @@ -79,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_False_Boolean() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Trashed == false); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (NOT ([umbracoNode].[trashed] = @0))", sql.SQL.Replace("\n", " ")); @@ -90,7 +92,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_EqualsFalse_Boolean() { - var sql = Sql().SelectAll().From().Where(x => x.Trashed == false); + Sql sql = Sql().SelectAll().From().Where(x => x.Trashed == false); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (NOT ([umbracoNode].[trashed] = @0))", sql.SQL.Replace("\n", " ")); Assert.AreEqual(1, sql.Arguments.Length); @@ -100,7 +102,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_Boolean() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Trashed); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[trashed] = @0)", sql.SQL.Replace("\n", " ")); @@ -111,7 +113,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_ToUpper() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Text.ToUpper() == "hello".ToUpper()); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((upper([umbracoNode].[text]) = upper(@0)))", sql.SQL.Replace("\n", " ")); @@ -122,7 +124,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_ToString() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Text == 1.ToString()); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (([umbracoNode].[text] = @0))", sql.SQL.Replace("\n", " ")); @@ -133,7 +135,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_With_Wildcard() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Text.StartsWith("D")); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (upper([umbracoNode].[text]) LIKE upper(@0))", sql.SQL.Replace("\n", " ")); @@ -144,7 +146,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_Single_Constant() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.NodeId == 2); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (([umbracoNode].[id] = @0))", sql.SQL.Replace("\n", " ")); @@ -155,7 +157,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_And_Constant() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.NodeId != 2 && x.NodeId != 3); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((([umbracoNode].[id] <> @0) AND ([umbracoNode].[id] <> @1)))", sql.SQL.Replace("\n", " ")); @@ -167,7 +169,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Clause_Or_Constant() { - var sql = Sql().SelectAll().From() + Sql sql = Sql().SelectAll().From() .Where(x => x.Text == "hello" || x.NodeId == 3); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ((([umbracoNode].[text] = @0) OR ([umbracoNode].[id] = @1)))", sql.SQL.Replace("\n", " ")); @@ -179,21 +181,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Where_Null() { - var sql = Sql().SelectAll().From().WhereNull(x => x.NodeId); + Sql sql = Sql().SelectAll().From().WhereNull(x => x.NodeId); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (([umbracoNode].[id] IS NULL))", sql.SQL.Replace("\n", " ")); } [Test] public void Where_Not_Null() { - var sql = Sql().SelectAll().From().WhereNotNull(x => x.NodeId); + Sql sql = Sql().SelectAll().From().WhereNotNull(x => x.NodeId); Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (([umbracoNode].[id] IS NOT NULL))", sql.SQL.Replace("\n", " ")); } [Test] public void Where_Any() { - var sql = Sql().SelectAll().From().WhereAny( + Sql sql = Sql().SelectAll().From().WhereAny( s => s.Where(x => x.NodeId == 1), s => s.Where(x => x.NodeId == 2)); @@ -203,10 +205,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_Select_From_With_Type() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]"); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll().From(); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); @@ -217,13 +219,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_InnerJoin_With_Types() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll() .From($"[{Constants.DatabaseSchema.Tables.DocumentVersion}]") .InnerJoin($"[{Constants.DatabaseSchema.Tables.ContentVersion}]") .On($"[{Constants.DatabaseSchema.Tables.DocumentVersion}].[id] = [{Constants.DatabaseSchema.Tables.ContentVersion}].[id]"); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll().From() .InnerJoin() .On(left => left.Id, right => right.Id); @@ -236,10 +238,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_OrderBy_With_Type() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").OrderBy($"([{Constants.DatabaseSchema.Tables.Content}].[contentTypeId])"); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll().From().OrderBy(x => x.ContentTypeId); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); @@ -250,10 +252,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_GroupBy_With_Type() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").GroupBy($"[{Constants.DatabaseSchema.Tables.Content}].[contentTypeId]"); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll().From().GroupBy(x => x.ContentTypeId); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); @@ -264,10 +266,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_Use_Where_Predicate() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").Where($"([{Constants.DatabaseSchema.Tables.Content}].[nodeId] = @0)", 1045); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll().From().Where(x => x.NodeId == 1045); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); @@ -278,13 +280,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests [Test] public void Can_Use_Where_And_Predicate() { - var expected = Sql(); + Sql expected = Sql(); expected.SelectAll() .From($"[{Constants.DatabaseSchema.Tables.Content}]") .Where($"([{Constants.DatabaseSchema.Tables.Content}].[nodeId] = @0)", 1045) .Where($"([{Constants.DatabaseSchema.Tables.Content}].[contentTypeId] = @0)", 1050); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll() .From() .Where(x => x.NodeId == 1045) @@ -300,7 +302,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.NPocoTests { var sessionId = Guid.NewGuid(); - var sql = Sql() + Sql sql = Sql() .SelectAll() .From() .Where(x => x.SessionId == sessionId); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs index 66253de575..dfd8e5ed12 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using NUnit.Framework; using Umbraco.Core; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs index 708e7cac70..b6a389d83d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using NPoco; using NUnit.Framework; @@ -15,7 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Verify_Base_Clause() { - var NodeObjectTypeId = Constants.ObjectTypes.DataType; + var nodeObjectTypeId = Constants.ObjectTypes.DataType; var expected = new Sql(); expected.Select("*") @@ -28,7 +31,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying .From() .InnerJoin() .On(left => left.NodeId, right => right.NodeId) - .Where(x => x.NodeObjectType == NodeObjectTypeId); + .Where(x => x.NodeObjectType == nodeObjectTypeId); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs index 436c202398..eed6fcdf59 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs @@ -1,21 +1,24 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; +using System.Linq; using System.Linq.Expressions; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Tests.TestHelpers; -using System.Linq; -using Microsoft.Extensions.Logging.Abstractions; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying { @@ -25,8 +28,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Equals_Claus_With_Two_Entity_Values() { - var serializer = new ConfigurationEditorJsonSerializer(); - var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of()), serializer) + var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), new ConfigurationEditorJsonSerializer()) { Id = 12345 }; @@ -43,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Query_With_Content_Type_Alias() { - //Arrange + // Arrange Expression> predicate = content => content.ContentType.Alias == "Test"; var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor(SqlContext.SqlSyntax, Mappers); var result = modelToSqlExpressionHelper.Visit(predicate); @@ -57,7 +59,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Query_With_Content_Type_Aliases_IEnumerable() { - //Arrange - Contains is IEnumerable.Contains extension method + // Arrange - Contains is IEnumerable.Contains extension method var aliases = new[] { "Test1", "Test2" }; Expression> predicate = content => aliases.Contains(content.ContentType.Alias); var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor(SqlContext.SqlSyntax, Mappers); @@ -73,7 +75,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Query_With_Content_Type_Aliases_List() { - //Arrange - Contains is List.Contains instance method + // Arrange - Contains is List.Contains instance method var aliases = new System.Collections.Generic.List { "Test1", "Test2" }; Expression> predicate = content => aliases.Contains(content.ContentType.Alias); var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor(SqlContext.SqlSyntax, Mappers); @@ -89,9 +91,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void CachedExpression_Can_Verify_Path_StartsWith_Predicate_In_Same_Result() { - //Arrange + // Arrange - //use a single cached expression for multiple expressions and ensure the correct output + // use a single cached expression for multiple expressions and ensure the correct output // is done for both of them. var cachedExpression = new CachedExpression(); @@ -108,13 +110,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying var result2 = modelToSqlExpressionHelper2.Visit(cachedExpression); Assert.AreEqual("upper([umbracoNode].[path]) LIKE upper(@0)", result2); Assert.AreEqual("-1,123,97%", modelToSqlExpressionHelper2.GetSqlParameters()[0]); - } [Test] public void Can_Verify_Path_StartsWith_Predicate_In_Same_Result() { - //Arrange + // Arrange Expression> predicate = content => content.Path.StartsWith("-1"); var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor(SqlContext.SqlSyntax, Mappers); var result = modelToSqlExpressionHelper.Visit(predicate); @@ -126,7 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Verify_ParentId_StartsWith_Predicate_In_Same_Result() { - //Arrange + // Arrange Expression> predicate = content => content.ParentId == -1; var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor(SqlContext.SqlSyntax, Mappers); var result = modelToSqlExpressionHelper.Visit(predicate); @@ -195,10 +196,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying Assert.AreEqual("blah@blah.com", modelToSqlExpressionHelper.GetSqlParameters()[2]); } - private string GetSomeValue(string s) - { - return "xx" + s + "xx"; - } + private string GetSomeValue(string s) => "xx" + s + "xx"; private class Foo { @@ -242,12 +240,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying // and how would we get the comma there? we'd have to parse .StartsWith(group.Name + ',') // which is going to be quite complicated => no - //// how can we do user.Login.StartsWith(other.Value) ?? to use in WHERE or JOIN.ON clauses ?? - //Expression> predicate2 = (user, group) => user.Login.StartsWith(group.Name); - //var modelToSqlExpressionHelper2 = new PocoToSqlExpressionVisitor(SqlContext, null, null); - //var result2 = modelToSqlExpressionHelper2.Visit(predicate2); // fails, for now + // how can we do user.Login.StartsWith(other.Value) ?? to use in WHERE or JOIN.ON clauses ?? + //// Expression> predicate2 = (user, group) => user.Login.StartsWith(group.Name); + //// var modelToSqlExpressionHelper2 = new PocoToSqlExpressionVisitor(SqlContext, null, null); + //// var result2 = modelToSqlExpressionHelper2.Visit(predicate2); // fails, for now - //Console.WriteLine(result2); + //// Console.WriteLine(result2); Expression> predicate3 = (user, group) => SqlExtensionsStatics.SqlText(user.Login, group.Name, (n1, n2) => $"({n1} LIKE concat({n2}, ',%'))"); var modelToSqlExpressionHelper3 = new PocoToSqlExpressionVisitor(SqlContext, null, null); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaRepositorySqlClausesTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaRepositorySqlClausesTest.cs index 8c26f6a06b..09958a73b0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaRepositorySqlClausesTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using NPoco; using NUnit.Framework; @@ -15,7 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Verify_Base_Clause() { - var nodeObjectTypeId = Constants.ObjectTypes.Media; + Guid nodeObjectTypeId = Constants.ObjectTypes.Media; var expected = new Sql(); expected.Select("*") @@ -24,7 +27,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying .InnerJoin("[umbracoNode]").On($"[{Constants.DatabaseSchema.Tables.Content}].[nodeId] = [umbracoNode].[id]") .Where("([umbracoNode].[nodeObjectType] = @0)", new Guid("b796f64c-1f99-4ffb-b886-4bf4bc011a9c")); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll() .From() .InnerJoin() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaTypeRepositorySqlClausesTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaTypeRepositorySqlClausesTest.cs index f28540454d..4187ecf1df 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaTypeRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/MediaTypeRepositorySqlClausesTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Diagnostics; using NPoco; using NUnit.Framework; @@ -15,7 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Can_Verify_Base_Clause() { - var NodeObjectTypeId = Constants.ObjectTypes.MediaType; + Guid nodeObjectTypeId = Constants.ObjectTypes.MediaType; var expected = new Sql(); expected.Select("*") @@ -23,12 +26,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying .InnerJoin("[umbracoNode]").On("[cmsContentType].[nodeId] = [umbracoNode].[id]") .Where("([umbracoNode].[nodeObjectType] = @0)", new Guid("4ea4382b-2f5a-4c2b-9587-ae9b3cf3602e")); - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll() .From() .InnerJoin() .On(left => left.NodeId, right => right.NodeId) - .Where(x => x.NodeObjectType == NodeObjectTypeId); + .Where(x => x.NodeObjectType == nodeObjectTypeId); Assert.That(sql.SQL, Is.EqualTo(expected.SQL)); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/QueryBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/QueryBuilderTests.cs index f4b8c2b250..00500c9094 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/QueryBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/QueryBuilderTests.cs @@ -1,6 +1,9 @@ -using System.Diagnostics; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Diagnostics; +using NPoco; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -16,16 +19,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying public void Can_Build_StartsWith_Query_For_IContent() { // Arrange - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll(); sql.From("umbracoNode"); - var query = new Query(SqlContext).Where(x => x.Path.StartsWith("-1")); + IQuery query = new Query(SqlContext).Where(x => x.Path.StartsWith("-1")); // Act var translator = new SqlTranslator(sql, query); - var result = translator.Translate(); - var strResult = result.SQL; + Sql result = translator.Translate(); + string strResult = result.SQL; string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (upper([umbracoNode].[path]) LIKE upper(@0))"; @@ -43,16 +46,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying public void Can_Build_ParentId_Query_For_IContent() { // Arrange - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll(); sql.From("umbracoNode"); - var query = new Query(SqlContext).Where(x => x.ParentId == -1); + IQuery query = new Query(SqlContext).Where(x => x.ParentId == -1); // Act var translator = new SqlTranslator(sql, query); - var result = translator.Translate(); - var strResult = result.SQL; + Sql result = translator.Translate(); + string strResult = result.SQL; string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([umbracoNode].[parentId] = @0))"; @@ -70,16 +73,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying public void Can_Build_ContentTypeAlias_Query_For_IContentType() { // Arrange - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll(); sql.From("umbracoNode"); - var query = new Query(SqlContext).Where(x => x.Alias == "umbTextpage"); + IQuery query = new Query(SqlContext).Where(x => x.Alias == "umbTextpage"); // Act var translator = new SqlTranslator(sql, query); - var result = translator.Translate(); - var strResult = result.SQL; + Sql result = translator.Translate(); + string strResult = result.SQL; string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([cmsContentType].[alias] = @0))"; @@ -98,14 +101,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying const string path = "-1,1046,1076,1089"; const int id = 1046; - var sql = Sql(); + Sql sql = Sql(); sql.SelectAll() .From(); // the actual SELECT really does not matter - var query = SqlContext.Query().Where(x => x.Path.StartsWith(path) && x.Id != id && x.Published && x.Trashed == false); + IQuery query = SqlContext.Query().Where(x => x.Path.StartsWith(path) && x.Id != id && x.Published && x.Trashed == false); var translator = new SqlTranslator(sql, query); - var result = translator.Translate(); + Sql result = translator.Translate(); Assert.AreEqual("-1,1046,1076,1089%", result.Arguments[0]); Assert.AreEqual(1046, result.Arguments[1]); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs index 40a932181c..cbf3e7daaa 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Serialization; @@ -49,7 +52,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Serialization [Test] public void DeserializeSubset__Subset_value_as_object() { - var expected = new MyStruct() { Key = "Test" @@ -65,7 +67,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Serialization [Test] public void DeserializeSubset__Subset_value_as_array() { - var expected = new []{"test"}; + var expected = new[] { "test" }; var key = "text"; var full = $"{{\"{key}\": {JsonConvert.SerializeObject(expected)}"; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs index 6eebf5d237..63331762b6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Reflection; using System.Text; using NUnit.Framework; @@ -23,7 +26,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services string TypeName(Type type) { if (!type.IsGenericType) + { return type.Name; + } + var sb = new StringBuilder(); TypeNameSb(type, sb); return sb.ToString(); @@ -36,24 +42,42 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services name = pos > 0 ? name.Substring(0, pos) : name; sb.Append(name); if (!type.IsGenericType) + { return; + } + sb.Append("<"); var first = true; foreach (var arg in type.GetGenericArguments()) { - if (first) first = false; - else sb.Append(", "); + if (first) + { + first = false; + } + else + { + sb.Append(", "); + } + TypeNameSb(arg, sb); } + sb.Append(">"); } foreach (var e in events) { // only continue if this is a TypedEventHandler - if (!e.EventHandlerType.IsGenericType) continue; + if (!e.EventHandlerType.IsGenericType) + { + continue; + } + var typeDef = e.EventHandlerType.GetGenericTypeDefinition(); - if (typedEventHandler != typeDef) continue; + if (typedEventHandler != typeDef) + { + continue; + } // get the event args type var eventArgsType = e.EventHandlerType.GenericTypeArguments[1]; @@ -62,7 +86,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services // exclude -ing (eg Saving) events, we don't deal with them in EventDefinitionBase (they always trigger) var found = EventNameExtractor.FindEvents(serviceType, eventArgsType, EventNameExtractor.MatchIngNames); - if (found.Length == 1) continue; + if (found.Length == 1) + { + continue; + } if (found.Length == 0) { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs index dc857d2d5d..6bfc252574 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -13,7 +16,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [TestFixture] public class LocalizedTextServiceTests { - private static ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + private static readonly ILoggerFactory s_loggerFactory = NullLoggerFactory.Instance; + [Test] public void Using_Dictionary_Gets_All_Stored_Values() { @@ -27,22 +31,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea1", new Dictionary { - {"testKey1", "testValue1"}, - {"testKey2", "testValue2"} + { "testKey1", "testValue1" }, + { "testKey2", "testValue2" } } }, { "testArea2", new Dictionary { - {"blah1", "blahValue1"}, - {"blah2", "blahValue2"} + { "blah1", "blahValue1" }, + { "blah2", "blahValue2" } } }, } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.GetAllStoredValues(culture); + IDictionary result = txtService.GetAllStoredValues(culture); Assert.AreEqual(4, result.Count); Assert.AreEqual("testArea1/testKey1", result.ElementAt(0).Key); @@ -53,18 +57,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services Assert.AreEqual("testValue2", result["testArea1/testKey2"]); Assert.AreEqual("blahValue1", result["testArea2/blah1"]); Assert.AreEqual("blahValue2", result["testArea2/blah2"]); - } [Test] public void Using_XDocument_Gets_All_Stored_Values() { var culture = CultureInfo.GetCultureInfo("en-US"); - var txtService = new LocalizedTextService(new Dictionary> + var txtService = new LocalizedTextService( + new Dictionary> { { culture, new Lazy(() => new XDocument( - new XElement("language", + new XElement( + "language", new XElement("area", new XAttribute("alias", "testArea1"), new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"), new XElement("key", new XAttribute("alias", "testKey2"), "testValue2")), @@ -72,9 +77,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "blah1"), "blahValue1"), new XElement("key", new XAttribute("alias", "blah2"), "blahValue2"))))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.GetAllStoredValues(culture); + IDictionary result = txtService.GetAllStoredValues(culture); Assert.AreEqual(4, result.Count()); Assert.AreEqual("testArea1/testKey1", result.ElementAt(0).Key); @@ -85,10 +90,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services Assert.AreEqual("testValue2", result["testArea1/testKey2"]); Assert.AreEqual("blahValue1", result["testArea2/blah1"]); Assert.AreEqual("blahValue2", result["testArea2/blah2"]); - } - [Test] public void Using_XDocument_Gets_All_Stored_Values_With_Duplicates() { @@ -98,17 +101,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { { culture, new Lazy(() => new XDocument( - new XElement("language", + new XElement( + "language", new XElement("area", new XAttribute("alias", "testArea1"), new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"), new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"))))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.GetAllStoredValues(culture); + IDictionary result = txtService.GetAllStoredValues(culture); Assert.AreEqual(1, result.Count()); - } [Test] @@ -124,14 +127,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "testValue"} + { "testKey", "testValue" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testArea/testKey", culture); + string result = txtService.Localize("testArea/testKey", culture); Assert.AreEqual("testValue", result); } @@ -149,14 +152,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "testValue"} + { "testKey", "testValue" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testKey", culture); + string result = txtService.Localize("testKey", culture); Assert.AreEqual("testValue", result); } @@ -174,16 +177,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "testValue"} + { "testKey", "testValue" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testArea/doNotFind", culture); + string result = txtService.Localize("testArea/doNotFind", culture); - //NOTE: Based on how legacy works, the default text does not contain the area, just the key + // NOTE: Based on how legacy works, the default text does not contain the area, just the key Assert.AreEqual("[doNotFind]", result); } @@ -200,14 +203,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "testValue"} + { "testKey", "testValue" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("doNotFind", culture); + string result = txtService.Localize("doNotFind", culture); Assert.AreEqual("[doNotFind]", result); } @@ -225,14 +228,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "Hello %0%, you are such a %1% %2%"} + { "testKey", "Hello %0%, you are such a %1% %2%" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testKey", culture, + string result = txtService.Localize( + "testKey", + culture, new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } }); Assert.AreEqual("Hello world, you are such a great planet", result); @@ -251,9 +256,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testArea/testKey", culture); + string result = txtService.Localize("testArea/testKey", culture); Assert.AreEqual("testValue", result); } @@ -271,9 +276,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testKey", culture); + string result = txtService.Localize("testKey", culture); Assert.AreEqual("testValue", result); } @@ -291,11 +296,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testArea/doNotFind", culture); + string result = txtService.Localize("testArea/doNotFind", culture); - //NOTE: Based on how legacy works, the default text does not contain the area, just the key + // NOTE: Based on how legacy works, the default text does not contain the area, just the key Assert.AreEqual("[doNotFind]", result); } @@ -312,9 +317,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("doNotFind", culture); + string result = txtService.Localize("doNotFind", culture); Assert.AreEqual("[doNotFind]", result); } @@ -332,9 +337,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services new XElement("key", new XAttribute("alias", "testKey"), "Hello %0%, you are such a %1% %2%")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); - var result = txtService.Localize("testKey", culture, + string result = txtService.Localize("testKey", culture, new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } }); Assert.AreEqual("Hello world, you are such a great planet", result); @@ -353,12 +358,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { "testArea", new Dictionary { - {"testKey", "testValue"} + { "testKey", "testValue" } } } } } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); Assert.AreEqual("[testKey]", txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU"))); } @@ -373,10 +378,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { culture, new Lazy(() => new XDocument( new XElement("area", new XAttribute("alias", "testArea"), - new XElement("key", new XAttribute("alias", "testKey"), - "testValue")))) + new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, _loggerFactory.CreateLogger()); + }, s_loggerFactory.CreateLogger()); Assert.AreEqual("[testKey]", txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU"))); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs index 3acfce1781..2f26b041c6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs @@ -1,10 +1,14 @@ -using System.Threading; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PropertyEditors; @@ -22,19 +26,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services textService.Setup(x => x.Localize(It.IsAny(), Thread.CurrentThread.CurrentCulture, null)).Returns("Localized text"); var dataTypeService = new Mock(); - var dataType = Mock.Of( - x => x.Configuration == (object)string.Empty //irrelevant but needs a value + IDataType dataType = Mock.Of( + x => x.Configuration == (object)string.Empty // irrelevant but needs a value && x.DatabaseType == ValueStorageType.Nvarchar && x.EditorAlias == Constants.PropertyEditors.Aliases.TextBox); dataTypeService.Setup(x => x.GetDataType(It.IsAny())).Returns(() => dataType); dt = dataType; - //new data editor that returns a TextOnlyValueEditor which will do the validation for the properties - var dataEditor = Mock.Of( + // new data editor that returns a TextOnlyValueEditor which will do the validation for the properties + IDataEditor dataEditor = Mock.Of( x => x.Type == EditorType.PropertyValue && x.Alias == Constants.PropertyEditors.Aliases.TextBox); Mock.Get(dataEditor).Setup(x => x.GetValueEditor(It.IsAny())) - .Returns(new CustomTextOnlyValueEditor(Mock.Of(), Mock.Of(), new DataEditorAttribute(Constants.PropertyEditors.Aliases.TextBox, "Test Textbox", "textbox"), textService.Object, Mock.Of())); + .Returns(new CustomTextOnlyValueEditor(Mock.Of(), Mock.Of(), new DataEditorAttribute(Constants.PropertyEditors.Aliases.TextBox, "Test Textbox", "textbox"), textService.Object, Mock.Of(), new JsonNetSerializer())); var propEditors = new PropertyEditorCollection(new DataEditorCollection(new[] { dataEditor })); @@ -44,22 +48,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [Test] public void Validate_Invariant_Properties_On_Variant_Default_Culture() { - MockObjects(out var validationService, out var dataType); + MockObjects(out PropertyValidationService validationService, out IDataType dataType); - var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture}); + var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture }); p1.SetValue("Hello", "en-US"); var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing }); p2.SetValue("Hello", null); var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture }); - p3.SetValue(null, "en-US"); //invalid + p3.SetValue(null, "en-US"); // invalid var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing }); - p4.SetValue(null, null); //invalid + p4.SetValue(null, null); // invalid - var content = Mock.Of( - x => x.Published == true //set to published, the default culture will validate invariant anyways + IContent content = Mock.Of( + x => x.Published == true // set to published, the default culture will validate invariant anyways && x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 })); - var result = validationService.IsPropertyDataValid(content, out var invalid, CultureImpact.Explicit("en-US", true)); + bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", true)); Assert.IsFalse(result); Assert.AreEqual(2, invalid.Length); @@ -68,22 +72,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [Test] public void Validate_Invariant_Properties_On_Variant_Non_Default_Culture() { - MockObjects(out var validationService, out var dataType); + MockObjects(out PropertyValidationService validationService, out IDataType dataType); var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture }); p1.SetValue("Hello", "en-US"); var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing }); p2.SetValue("Hello", null); var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture }); - p3.SetValue(null, "en-US"); //invalid + p3.SetValue(null, "en-US"); // invalid var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing }); - p4.SetValue(null, null); //invalid + p4.SetValue(null, null); // invalid - var content = Mock.Of( - x => x.Published == false //set to not published, the non default culture will need to validate invariant too + IContent content = Mock.Of( + x => x.Published == false // set to not published, the non default culture will need to validate invariant too && x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 })); - var result = validationService.IsPropertyDataValid(content, out var invalid, CultureImpact.Explicit("en-US", false)); + bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", false)); Assert.IsFalse(result); Assert.AreEqual(2, invalid.Length); @@ -92,22 +96,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [Test] public void Validate_Variant_Properties_On_Variant() { - MockObjects(out var validationService, out var dataType); + MockObjects(out PropertyValidationService validationService, out IDataType dataType); var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture }); - p1.SetValue(null, "en-US"); //invalid + p1.SetValue(null, "en-US"); // invalid var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing }); - p2.SetValue(null, null); //invalid + p2.SetValue(null, null); // invalid var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture }); - p3.SetValue(null, "en-US"); //ignored because the impact isn't the default lang + the content is published + p3.SetValue(null, "en-US"); // ignored because the impact isn't the default lang + the content is published var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing }); - p4.SetValue(null, null); //ignored because the impact isn't the default lang + the content is published + p4.SetValue(null, null); // ignored because the impact isn't the default lang + the content is published - var content = Mock.Of( - x => x.Published == true //set to published + IContent content = Mock.Of( + x => x.Published == true // set to published && x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 })); - var result = validationService.IsPropertyDataValid(content, out var invalid, CultureImpact.Explicit("en-US", false)); + bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Explicit("en-US", false)); Assert.IsFalse(result); Assert.AreEqual(2, invalid.Length); @@ -116,21 +120,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [Test] public void Validate_Invariant_Properties_On_Invariant() { - MockObjects(out var validationService, out var dataType); + MockObjects(out PropertyValidationService validationService, out IDataType dataType); var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture }); - p1.SetValue(null, "en-US"); //ignored since this is variant + p1.SetValue(null, "en-US"); // ignored since this is variant var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing }); - p2.SetValue(null, null); //invalid + p2.SetValue(null, null); // invalid var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture }); - p3.SetValue("Hello", "en-US"); //ignored since this is variant + p3.SetValue("Hello", "en-US"); // ignored since this is variant var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing }); - p4.SetValue(null, null); //invalid + p4.SetValue(null, null); // invalid - var content = Mock.Of( + IContent content = Mock.Of( x => x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 })); - var result = validationService.IsPropertyDataValid(content, out var invalid, CultureImpact.Invariant); + bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.Invariant); Assert.IsFalse(result); Assert.AreEqual(2, invalid.Length); @@ -139,37 +143,40 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services [Test] public void Validate_Properties_On_All() { - MockObjects(out var validationService, out var dataType); + MockObjects(out PropertyValidationService validationService, out IDataType dataType); var p1 = new Property(new PropertyType(ShortStringHelper, dataType, "test1") { Mandatory = true, Variations = ContentVariation.Culture }); - p1.SetValue(null, "en-US"); //invalid + p1.SetValue(null, "en-US"); // invalid var p2 = new Property(new PropertyType(ShortStringHelper, dataType, "test2") { Mandatory = true, Variations = ContentVariation.Nothing }); - p2.SetValue(null, null); //invalid + p2.SetValue(null, null); // invalid var p3 = new Property(new PropertyType(ShortStringHelper, dataType, "test3") { Mandatory = true, Variations = ContentVariation.Culture }); - p3.SetValue(null, "en-US"); //invalid + p3.SetValue(null, "en-US"); // invalid var p4 = new Property(new PropertyType(ShortStringHelper, dataType, "test4") { Mandatory = true, Variations = ContentVariation.Nothing }); - p4.SetValue(null, null); //invalid + p4.SetValue(null, null); // invalid - var content = Mock.Of( + IContent content = Mock.Of( x => x.Properties == new PropertyCollection(new[] { p1, p2, p3, p4 })); - var result = validationService.IsPropertyDataValid(content, out var invalid, CultureImpact.All); + bool result = validationService.IsPropertyDataValid(content, out IProperty[] invalid, CultureImpact.All); Assert.IsFalse(result); Assert.AreEqual(4, invalid.Length); } - - //used so we can inject a mock - we should fix the base class DataValueEditor to be able to have the ILocalizedTextField passed + // used so we can inject a mock - we should fix the base class DataValueEditor to be able to have the ILocalizedTextField passed // in to create the Requried and Regex validators so we aren't using singletons private class CustomTextOnlyValueEditor : TextOnlyValueEditor { private readonly ILocalizedTextService _textService; - public CustomTextOnlyValueEditor(IDataTypeService dataTypeService, ILocalizationService localizationService, DataEditorAttribute attribute, ILocalizedTextService textService, IShortStringHelper shortStringHelper) : base(dataTypeService, localizationService, attribute, textService, shortStringHelper) - { - _textService = textService; - } + public CustomTextOnlyValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + DataEditorAttribute attribute, + ILocalizedTextService textService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(dataTypeService, localizationService, attribute, textService, shortStringHelper, jsonSerializer) => _textService = textService; public override IValueRequiredValidator RequiredValidator => new RequiredValidator(_textService); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs index 80c8b057ab..af77d0e570 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs @@ -1,8 +1,12 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; +using Semver; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded; @@ -13,12 +17,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded [TestFixture] public class BuilderTests { - [Test] public void GenerateSimpleType() { - // Umbraco returns nice, pascal-cased names - + // Umbraco returns nice, pascal-cased names. var type1 = new TypeModel { Id = 1, @@ -35,21 +37,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded ModelClrType = typeof(string), }); - var types = new[] { type1 }; - - var code = new Dictionary - { - }; + TypeModel[] types = new[] { type1 }; var modelsBuilderConfig = new ModelsBuilderSettings(); var builder = new TextBuilder(modelsBuilderConfig, types); - var btypes = builder.TypeModels; var sb = new StringBuilder(); builder.Generate(sb, builder.GetModelsToGenerate().First()); var gen = sb.ToString(); - var version = ApiVersion.Current.Version; + SemVersion version = ApiVersion.Current.Version; var expected = @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -110,8 +107,7 @@ namespace Umbraco.Web.PublishedModels [Test] public void GenerateSimpleType_Ambiguous_Issue() { - // Umbraco returns nice, pascal-cased names - + // Umbraco returns nice, pascal-cased names. var type1 = new TypeModel { Id = 1, @@ -138,25 +134,13 @@ namespace Umbraco.Web.PublishedModels ItemType = TypeModel.ItemTypes.Element, }; - var types = new[] { type1, type2 }; - - var code = new Dictionary - { - { "code", @" -namespace Umbraco.Web.PublishedModels -{ - public partial class Foo - { - } -} -" } - }; + TypeModel[] types = new[] { type1, type2 }; var modelsBuilderConfig = new ModelsBuilderSettings(); - var builder = new TextBuilder(modelsBuilderConfig, types); - var btypes = builder.TypeModels; - - builder.ModelsNamespace = "Umbraco.Web.PublishedModels"; + var builder = new TextBuilder(modelsBuilderConfig, types) + { + ModelsNamespace = "Umbraco.Web.PublishedModels" + }; var sb1 = new StringBuilder(); builder.Generate(sb1, builder.GetModelsToGenerate().Skip(1).First()); @@ -167,7 +151,7 @@ namespace Umbraco.Web.PublishedModels builder.Generate(sb, builder.GetModelsToGenerate().First()); var gen = sb.ToString(); - var version = ApiVersion.Current.Version; + SemVersion version = ApiVersion.Current.Version; var expected = @"//------------------------------------------------------------------------------ // // This code was generated by a tool. @@ -228,8 +212,6 @@ namespace Umbraco.Web.PublishedModels [Test] public void GenerateAmbiguous() { - // NOTE: since - var type1 = new TypeModel { Id = 1, @@ -258,20 +240,20 @@ namespace Umbraco.Web.PublishedModels ClrName = "Prop3", ModelClrType = typeof(global::Umbraco.Core.Exceptions.BootFailedException), }); - var types = new[] { type1 }; - - var code = new Dictionary - { - }; + TypeModel[] types = new[] { type1 }; var modelsBuilderConfig = new ModelsBuilderSettings(); - var builder = new TextBuilder(modelsBuilderConfig, types); - builder.ModelsNamespace = "Umbraco.ModelsBuilder.Models"; // forces conflict with Umbraco.ModelsBuilder.Umbraco - var btypes = builder.TypeModels; + var builder = new TextBuilder(modelsBuilderConfig, types) + { + ModelsNamespace = "Umbraco.ModelsBuilder.Models" // forces conflict with Umbraco.ModelsBuilder.Umbraco + }; var sb = new StringBuilder(); - foreach (var model in builder.GetModelsToGenerate()) + foreach (TypeModel model in builder.GetModelsToGenerate()) + { builder.Generate(sb, model); + } + var gen = sb.ToString(); Console.WriteLine(gen); @@ -289,9 +271,10 @@ namespace Umbraco.Web.PublishedModels { // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - - var builder = new TextBuilder(); - builder.ModelsNamespaceForTests = "ModelsNamespace"; + var builder = new TextBuilder + { + ModelsNamespaceForTests = "ModelsNamespace" + }; var sb = new StringBuilder(); builder.WriteClrType(sb, input); Assert.AreEqual(expected, sb.ToString()); @@ -305,7 +288,6 @@ namespace Umbraco.Web.PublishedModels { // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - var builder = new TextBuilder(); builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder"); builder.ModelsNamespaceForTests = "ModelsNamespace"; @@ -325,15 +307,16 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::System.Text.StringBuilder", sb.ToString()); } [Test] public void WriteClrTypeAnother_WithoutUsing() { - var builder = new TextBuilder(); - builder.ModelsNamespaceForTests = "Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Models"; + var builder = new TextBuilder + { + ModelsNamespaceForTests = "Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Models" + }; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(StringBuilder)); Assert.AreEqual("global::System.Text.StringBuilder", sb.ToString()); @@ -351,7 +334,6 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::System.Text.ASCIIEncoding", sb.ToString()); } @@ -367,7 +349,6 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::System.Text.ASCIIEncoding", sb.ToString()); } @@ -383,7 +364,6 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding", sb.ToString()); } @@ -399,7 +379,6 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding", sb.ToString()); } @@ -415,21 +394,28 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding.Nested", sb.ToString()); } - public class Class1 { } + public class Class1 + { + } } // make it public to be ambiguous (see above) public class ASCIIEncoding { // can we handle nested types? - public class Nested { } + public class Nested + { + } } - class BuilderTestsClass1 { } + public class BuilderTestsClass1 + { + } - public class System { } + public class System + { + } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs index 2afcd4f471..45065bbd53 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs @@ -1,10 +1,10 @@ -namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded { public static class StringExtensions { - public static string ClearLf(this string s) - { - return s.Replace("\r", ""); - } + public static string ClearLf(this string s) => s.Replace("\r", string.Empty); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs index 25d1d9f1f9..0c75318c87 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using NUnit.Framework; using Umbraco.ModelsBuilder.Embedded; @@ -9,23 +12,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded [TestFixture] public class UmbracoApplicationTests { - //[Test] - //public void Test() - //{ - // // start and terminate - // using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) - // { } + //// [Test] + //// public void Test() + //// { + //// // start and terminate + //// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) + //// { } - // // start and terminate - // using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) - // { } + //// // start and terminate + //// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) + //// { } - // // start, use and terminate - // using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) - // { - // var types = app.GetContentTypes(); - // } - //} + //// // start, use and terminate + //// using (var app = Application.GetApplication(TestOptions.ConnectionString, TestOptions.DatabaseProvider)) + //// { + //// var types = app.GetContentTypes(); + //// } + //// } [Test] public void ThrowsOnDuplicateAliases() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.PublishedCache.NuCache/SnapDictionaryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.PublishedCache.NuCache/SnapDictionaryTests.cs index 91317848c6..7a60cf473c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.PublishedCache.NuCache/SnapDictionaryTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.PublishedCache.NuCache/SnapDictionaryTests.cs @@ -1,4 +1,6 @@ - +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Linq; using System.Threading.Tasks; @@ -47,7 +49,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s = d.CreateSnapshot(); + SnapDictionary.Snapshot s = d.CreateSnapshot(); Assert.AreEqual(1, s.Gen); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -67,7 +69,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache public void MissingReturnsNull() { var d = new SnapDictionary(); - var s = d.CreateSnapshot(); + SnapDictionary.Snapshot s = d.CreateSnapshot(); Assert.IsNull(s.Get(1)); } @@ -80,18 +82,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache // gen 1 d.Set(1, "one"); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual("one", s1.Get(1)); // gen 2 d.Clear(1); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.IsNull(s2.Get(1)); Assert.AreEqual("one", s1.Get(1)); } + [Retry(5)] // TODO make this test non-flaky. [Test] public async Task CollectValues() { @@ -109,7 +112,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -124,7 +127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -139,7 +142,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var tv = d.Test.GetValues(1); + SnapDictionary.TestHelper.GenVal[] tv = d.Test.GetValues(1); Assert.AreEqual(3, tv[0].Gen); Assert.AreEqual(2, tv[1].Gen); Assert.AreEqual(1, tv[2].Gen); @@ -184,7 +187,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache var d = new SnapDictionary(); d.Test.CollectAuto = false; - for (var i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) { d.Set(i, i.ToString()); d.CreateSnapshot().Dispose(); @@ -200,8 +203,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(0, d.SnapCount); Assert.AreEqual(32, d.Count); - for (var i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) + { d.Set(i, null); + } d.CreateSnapshot().Dispose(); @@ -218,6 +223,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(0, d.Count); } + [Retry(5)] // TODO make this test non-flaky. [Test] public async Task CollectNulls() { @@ -235,7 +241,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -250,7 +256,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -267,7 +273,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var tv = d.Test.GetValues(1); + SnapDictionary.TestHelper.GenVal[] tv = d.Test.GetValues(1); Assert.AreEqual(3, tv[0].Gen); Assert.AreEqual(2, tv[1].Gen); Assert.AreEqual(1, tv[2].Gen); @@ -332,11 +338,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsTrue(d.Test.NextGen); await d.CollectAsync(); - var tv = d.Test.GetValues(1); + SnapDictionary.TestHelper.GenVal[] tv = d.Test.GetValues(1); Assert.AreEqual(1, tv.Length); Assert.AreEqual(1, tv[0].Gen); - var s = d.CreateSnapshot(); + SnapDictionary.Snapshot s = d.CreateSnapshot(); Assert.AreEqual("one", s.Get(1)); Assert.AreEqual(1, d.Test.LiveGen); @@ -389,7 +395,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache // collect liveGen GC.Collect(); - Assert.IsTrue(d.Test.GenObjs.TryPeek(out var genObj)); + Assert.IsTrue(d.Test.GenObjs.TryPeek(out global::Umbraco.Web.PublishedCache.NuCache.Snap.GenObj genObj)); genObj = null; // in Release mode, it works, but in Debug mode, the weak reference is still alive @@ -424,7 +430,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -436,7 +442,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -448,7 +454,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(3, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -484,7 +490,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -496,7 +502,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -508,7 +514,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(3, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); @@ -527,6 +533,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.GetValues(1).Length); } + [Retry(5)] // TODO make this test non-flaky. [Test] public async Task RandomTest1() { @@ -536,14 +543,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache d.Set(1, "one"); d.Set(2, "two"); - var s1 = d.CreateSnapshot(); - var v1 = s1.Get(1); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); + string v1 = s1.Get(1); Assert.AreEqual("one", v1); d.Set(1, "uno"); - var s2 = d.CreateSnapshot(); - var v2 = s2.Get(1); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); + string v2 = s2.Get(1); Assert.AreEqual("uno", v2); v1 = s1.Get(1); @@ -573,6 +580,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(0, d.SnapCount); } + [Retry(5)] // TODO make this test non-flaky. [Test] public async Task RandomTest2() { @@ -582,14 +590,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache d.Set(1, "one"); d.Set(2, "two"); - var s1 = d.CreateSnapshot(); - var v1 = s1.Get(1); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); + string v1 = s1.Get(1); Assert.AreEqual("one", v1); d.Clear(1); - var s2 = d.CreateSnapshot(); - var v2 = s2.Get(1); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); + string v2 = s2.Get(1); Assert.AreEqual(null, v2); v1 = s1.Get(1); @@ -634,7 +642,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache using (d.GetScopedWriteLock(GetScopeProvider())) { - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(0, s1.Gen); Assert.AreEqual(1, d.Test.LiveGen); @@ -642,7 +650,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsNull(s1.Get(1)); } - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(1, s2.Gen); Assert.AreEqual(1, d.Test.LiveGen); @@ -663,7 +671,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, s1.Gen); Assert.AreEqual(1, d.Test.LiveGen); @@ -678,7 +686,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, s2.Gen); Assert.AreEqual(2, d.Test.LiveGen); @@ -695,7 +703,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(2, s3.Gen); Assert.AreEqual(3, d.Test.LiveGen); @@ -703,7 +711,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual("uno", s3.Get(1)); } - var s4 = d.CreateSnapshot(); + SnapDictionary.Snapshot s4 = d.CreateSnapshot(); Assert.AreEqual(3, s4.Gen); Assert.AreEqual(3, d.Test.LiveGen); @@ -715,16 +723,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache public void NestedWriteLocking1() { var d = new SnapDictionary(); - var t = d.Test; + SnapDictionary.TestHelper t = d.Test; t.CollectAuto = false; Assert.AreEqual(0, d.CreateSnapshot().Gen); // no scope context: writers nest, last one to be disposed commits + IScopeProvider scopeProvider = GetScopeProvider(); - var scopeProvider = GetScopeProvider(); - - using (var w1 = d.GetScopedWriteLock(scopeProvider)) + using (IDisposable w1 = d.GetScopedWriteLock(scopeProvider)) { Assert.AreEqual(1, t.LiveGen); Assert.IsTrue(t.IsLocked); @@ -732,7 +739,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.Throws(() => { - using (var w2 = d.GetScopedWriteLock(scopeProvider)) + using (IDisposable w2 = d.GetScopedWriteLock(scopeProvider)) { } }); @@ -760,16 +767,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(0, d.CreateSnapshot().Gen); // scope context: writers enlist - var scopeContext = new ScopeContext(); - var scopeProvider = GetScopeProvider(scopeContext); + IScopeProvider scopeProvider = GetScopeProvider(scopeContext); - using (var w1 = d.GetScopedWriteLock(scopeProvider)) + using (IDisposable w1 = d.GetScopedWriteLock(scopeProvider)) { // This one is interesting, although we don't allow recursive locks, since this is - // using the same ScopeContext/key, the lock acquisition is only done once - - using (var w2 = d.GetScopedWriteLock(scopeProvider)) + // using the same ScopeContext/key, the lock acquisition is only done once. + using (IDisposable w2 = d.GetScopedWriteLock(scopeProvider)) { Assert.AreSame(w1, w2); @@ -782,16 +787,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache public void NestedWriteLocking3() { var d = new SnapDictionary(); - var t = d.Test; + SnapDictionary.TestHelper t = d.Test; t.CollectAuto = false; Assert.AreEqual(0, d.CreateSnapshot().Gen); var scopeContext = new ScopeContext(); - var scopeProvider1 = GetScopeProvider(); - var scopeProvider2 = GetScopeProvider(scopeContext); + IScopeProvider scopeProvider1 = GetScopeProvider(); + IScopeProvider scopeProvider2 = GetScopeProvider(scopeContext); - using (var w1 = d.GetScopedWriteLock(scopeProvider1)) + using (IDisposable w1 = d.GetScopedWriteLock(scopeProvider1)) { Assert.AreEqual(1, t.LiveGen); Assert.IsTrue(t.IsLocked); @@ -799,11 +804,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.Throws(() => { - using (var w2 = d.GetScopedWriteLock(scopeProvider2)) + using (IDisposable w2 = d.GetScopedWriteLock(scopeProvider2)) { } }); - } } @@ -820,7 +824,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, s1.Gen); Assert.AreEqual(1, d.Test.LiveGen); @@ -835,15 +839,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(2, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, s2.Gen); Assert.AreEqual(2, d.Test.LiveGen); Assert.IsFalse(d.Test.NextGen); Assert.AreEqual("uno", s2.Get(1)); - - var scopeProvider = GetScopeProvider(); + IScopeProvider scopeProvider = GetScopeProvider(); using (d.GetScopedWriteLock(scopeProvider)) { // gen 3 @@ -854,7 +857,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(2, s3.Gen); Assert.AreEqual(3, d.Test.LiveGen); @@ -862,7 +865,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual("uno", s3.Get(1)); } - var s4 = d.CreateSnapshot(); + SnapDictionary.Snapshot s4 = d.CreateSnapshot(); Assert.AreEqual(3, s4.Gen); Assert.AreEqual(3, d.Test.LiveGen); @@ -876,35 +879,34 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache var d = new SnapDictionary(); d.Test.CollectAuto = false; - // gen 1 d.Set(1, "one"); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, s1.Gen); Assert.AreEqual("one", s1.Get(1)); d.Set(1, "uno"); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, s2.Gen); Assert.AreEqual("uno", s2.Get(1)); - var scopeProvider = GetScopeProvider(); + IScopeProvider scopeProvider = GetScopeProvider(); using (d.GetScopedWriteLock(scopeProvider)) { // creating a snapshot in a write-lock does NOT return the "current" content // it uses the previous snapshot, so new snapshot created only on release d.SetLocked(1, "ein"); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(2, s3.Gen); Assert.AreEqual("uno", s3.Get(1)); // but live snapshot contains changes - var ls = d.Test.LiveSnapshot; + SnapDictionary.Snapshot ls = d.Test.LiveSnapshot; Assert.AreEqual("ein", ls.Get(1)); Assert.AreEqual(3, ls.Gen); } - var s4 = d.CreateSnapshot(); + SnapDictionary.Snapshot s4 = d.CreateSnapshot(); Assert.AreEqual(3, s4.Gen); Assert.AreEqual("ein", s4.Get(1)); } @@ -917,39 +919,39 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache // gen 1 d.Set(1, "one"); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, s1.Gen); Assert.AreEqual("one", s1.Get(1)); d.Set(1, "uno"); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, s2.Gen); Assert.AreEqual("uno", s2.Get(1)); var scopeContext = new ScopeContext(); - var scopeProvider = GetScopeProvider(scopeContext); + IScopeProvider scopeProvider = GetScopeProvider(scopeContext); using (d.GetScopedWriteLock(scopeProvider)) { // creating a snapshot in a write-lock does NOT return the "current" content // it uses the previous snapshot, so new snapshot created only on release d.SetLocked(1, "ein"); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(2, s3.Gen); Assert.AreEqual("uno", s3.Get(1)); // but live snapshot contains changes - var ls = d.Test.LiveSnapshot; + SnapDictionary.Snapshot ls = d.Test.LiveSnapshot; Assert.AreEqual("ein", ls.Get(1)); Assert.AreEqual(3, ls.Gen); } - var s4 = d.CreateSnapshot(); + SnapDictionary.Snapshot s4 = d.CreateSnapshot(); Assert.AreEqual(2, s4.Gen); Assert.AreEqual("uno", s4.Get(1)); scopeContext.ScopeExit(true); - var s5 = d.CreateSnapshot(); + SnapDictionary.Snapshot s5 = d.CreateSnapshot(); Assert.AreEqual(3, s5.Gen); Assert.AreEqual("ein", s5.Get(1)); } @@ -958,17 +960,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache public void ScopeLocking2() { var d = new SnapDictionary(); - var t = d.Test; + SnapDictionary.TestHelper t = d.Test; t.CollectAuto = false; // gen 1 d.Set(1, "one"); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.AreEqual(1, s1.Gen); Assert.AreEqual("one", s1.Get(1)); d.Set(1, "uno"); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.AreEqual(2, s2.Gen); Assert.AreEqual("uno", s2.Get(1)); @@ -976,13 +978,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsFalse(t.NextGen); var scopeContext = new ScopeContext(); - var scopeProvider = GetScopeProvider(scopeContext); + IScopeProvider scopeProvider = GetScopeProvider(scopeContext); using (d.GetScopedWriteLock(scopeProvider)) { // creating a snapshot in a write-lock does NOT return the "current" content // it uses the previous snapshot, so new snapshot created only on release d.SetLocked(1, "ein"); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.AreEqual(2, s3.Gen); Assert.AreEqual("uno", s3.Get(1)); @@ -992,7 +994,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsTrue(t.IsLocked); // but live snapshot contains changes - var ls = t.LiveSnapshot; + SnapDictionary.Snapshot ls = t.LiveSnapshot; Assert.AreEqual("ein", ls.Get(1)); Assert.AreEqual(3, ls.Gen); } @@ -1003,7 +1005,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsTrue(t.IsLocked); // no changes until exit - var s4 = d.CreateSnapshot(); + SnapDictionary.Snapshot s4 = d.CreateSnapshot(); Assert.AreEqual(2, s4.Gen); Assert.AreEqual("uno", s4.Get(1)); @@ -1015,7 +1017,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.IsFalse(t.IsLocked); // no changes since not completed - var s5 = d.CreateSnapshot(); + SnapDictionary.Snapshot s5 = d.CreateSnapshot(); Assert.AreEqual(2, s5.Gen); Assert.AreEqual("uno", s5.Get(1)); } @@ -1033,14 +1035,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache d.Set(3, "three"); d.Set(4, "four"); - var s1 = d.CreateSnapshot(); - var all = s1.GetAll().ToArray(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); + string[] all = s1.GetAll().ToArray(); Assert.AreEqual(4, all.Length); Assert.AreEqual("one", all[0]); Assert.AreEqual("four", all[3]); d.Set(1, "uno"); - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); all = s1.GetAll().ToArray(); Assert.AreEqual(4, all.Length); @@ -1067,7 +1069,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.LiveGen); Assert.IsNull(d.Test.GenObj); - var s1 = d.CreateSnapshot(); + SnapDictionary.Snapshot s1 = d.CreateSnapshot(); Assert.IsFalse(d.Test.NextGen); Assert.AreEqual(1, d.Test.LiveGen); Assert.IsNotNull(d.Test.GenObj); @@ -1083,13 +1085,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(1, d.Test.GenObj.Gen); var scopeContext = new ScopeContext(); - var scopeProvider = GetScopeProvider(scopeContext); + IScopeProvider scopeProvider = GetScopeProvider(scopeContext); // scopeProvider.Context == scopeContext -> writer is scoped // writer is scope contextual and scoped // when disposed, nothing happens // when the context exists, the writer is released - using (d.GetScopedWriteLock(scopeProvider)) { d.SetLocked(1, "ein"); @@ -1109,7 +1110,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); // panic! - var s2 = d.CreateSnapshot(); + SnapDictionary.Snapshot s2 = d.CreateSnapshot(); Assert.IsTrue(d.Test.IsLocked); Assert.IsNotNull(d.Test.GenObj); @@ -1126,7 +1127,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache Assert.AreEqual(3, d.Test.LiveGen); Assert.IsTrue(d.Test.NextGen); - var s3 = d.CreateSnapshot(); + SnapDictionary.Snapshot s3 = d.CreateSnapshot(); Assert.IsFalse(d.Test.IsLocked); Assert.IsNotNull(d.Test.GenObj); @@ -1137,7 +1138,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache private IScopeProvider GetScopeProvider(ScopeContext scopeContext = null) { - var scopeProvider = Mock.Of(); + IScopeProvider scopeProvider = Mock.Of(); Mock.Get(scopeProvider) .Setup(x => x.Context).Returns(scopeContext); return scopeProvider; @@ -1178,7 +1179,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Umbraco.PublishedCache private static IScopeProvider GetScopeProvider() { - var scopeProvider = Mock.Of(); + IScopeProvider scopeProvider = Mock.Of(); Mock.Get(scopeProvider) .Setup(x => x.Context).Returns(() => null); return scopeProvider; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/AllowedContentTypeDetail.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/AllowedContentTypeDetail.cs index 08ac69b1bb..b4c59de805 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/AllowedContentTypeDetail.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/AllowedContentTypeDetail.cs @@ -1,4 +1,7 @@ -namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders { public class AllowedContentTypeDetail { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ContentTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ContentTypeBuilderTests.cs index 98d887d984..157bf67fea 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ContentTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ContentTypeBuilderTests.cs @@ -1,5 +1,7 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using NUnit.Framework; using Umbraco.Core; @@ -23,8 +25,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testPropertyGroupName = "Content"; const int testParentId = 98; const int testCreatorId = 22; - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testLevel = 3; const string testPath = "-1, 4, 10"; const int testSortOrder = 5; @@ -43,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new ContentTypeBuilder(); // Act - var contentType = builder + IContentType contentType = builder .WithId(testId) .WithKey(testKey) .WithAlias(testAlias) @@ -119,7 +121,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders Assert.IsFalse(contentType.IsContainer); Assert.AreEqual(2, contentType.PropertyTypes.Count()); - var propertyTypeIds = contentType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); + IOrderedEnumerable propertyTypeIds = contentType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 1, propertyTypeIds.Min()); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 2, propertyTypeIds.Max()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DataTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DataTypeBuilderTests.cs index ce47c69763..5e9ebccdb9 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DataTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DataTypeBuilderTests.cs @@ -1,4 +1,8 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -16,12 +20,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new DataTypeBuilder(); // Act - var dtd = builder + DataType dataType = builder .WithId(testId) .Build(); // Assert - Assert.AreEqual(testId, dtd.Id); + Assert.AreEqual(testId, dataType.Id); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DocumentEntitySlimBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DocumentEntitySlimBuilderTests.cs index 0aa93be802..3f99904f61 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DocumentEntitySlimBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/DocumentEntitySlimBuilderTests.cs @@ -1,6 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using NUnit.Framework; +using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -26,15 +30,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testContentTypeIcon = "icon"; const string testContentTypeThumbnail = "thumb"; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; var testAdditionalData1 = new KeyValuePair("test1", 123); var testAdditionalData2 = new KeyValuePair("test2", "hello"); var builder = new DocumentEntitySlimBuilder(); // Act - var item = builder + DocumentEntitySlim item = builder .WithId(testId) .WithKey(testKey) .WithCreatorId(testCreatorId) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs index 1efd9ddc01..a30ec6b0bf 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs @@ -1,5 +1,9 @@ -using System.Globalization; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Globalization; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -17,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var expected = CultureInfo.GetCultureInfo("en-GB"); // Act - var language = builder + ILanguage language = builder .WithCultureInfo(expected.Name) .Build(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MacroBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MacroBuilderTests.cs index bf5d899d6a..fd98331634 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MacroBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MacroBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -31,7 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new MacroBuilder(); // Act - var macro = builder + Macro macro = builder .WithId(id) .WithKey(key) .WithUseInEditor(useInEditor) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MediaTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MediaTypeBuilderTests.cs index 1c4af5da81..720c6dbb8c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MediaTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MediaTypeBuilderTests.cs @@ -1,5 +1,7 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Linq; using NUnit.Framework; using Umbraco.Core; @@ -23,8 +25,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testPropertyGroupName = "Additional Content"; const int testParentId = 98; const int testCreatorId = 22; - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testLevel = 3; const string testPath = "-1, 4, 10"; const int testSortOrder = 5; @@ -39,7 +41,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new MediaTypeBuilder(); // Act - var mediaType = builder + IMediaType mediaType = builder .WithId(testId) .WithKey(testKey) .WithAlias(testAlias) @@ -99,7 +101,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders Assert.IsFalse(mediaType.IsContainer); Assert.AreEqual(7, mediaType.PropertyTypes.Count()); // 5 from media properties group, 2 custom - var propertyTypeIds = mediaType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); + IOrderedEnumerable propertyTypeIds = mediaType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 1, propertyTypeIds.Min()); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 7, propertyTypeIds.Max()); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberBuilderTests.cs index 4a85949826..16b1a98ec8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberBuilderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -33,12 +36,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const int testSortOrder = 5; const bool testTrashed = false; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testFailedPasswordAttempts = 22; - var testLastLockoutDate = DateTime.Now.AddHours(-2); - var testLastLoginDate = DateTime.Now.AddHours(-3); - var testLastPasswordChangeDate = DateTime.Now.AddHours(-4); + DateTime testLastLockoutDate = DateTime.Now.AddHours(-2); + DateTime testLastLoginDate = DateTime.Now.AddHours(-3); + DateTime testLastPasswordChangeDate = DateTime.Now.AddHours(-4); var testPropertyType1 = new PropertyTypeDetail { Alias = "title", Name = "Title", SortOrder = 1, DataTypeId = -88 }; var testPropertyType2 = new PropertyTypeDetail { Alias = "bodyText", Name = "Body Text", SortOrder = 2, DataTypeId = -87 }; var testPropertyType3 = new PropertyTypeDetail { Alias = "author", Name = "Author", Description = "Writer of the article", SortOrder = 1, DataTypeId = -88 }; @@ -53,7 +56,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new MemberBuilder(); // Act - var member = builder + Member member = builder .AddMemberType() .WithId(testMemberTypeId) .WithAlias(testMemberTypeAlias) @@ -140,7 +143,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders Assert.AreEqual(testPropertyData2.Value, member.GetValue(testPropertyData2.Key)); Assert.AreEqual(testPropertyData3.Value, member.GetValue(testPropertyData3.Key)); - var propertyIds = member.Properties.Select(x => x.Id).OrderBy(x => x); + IOrderedEnumerable propertyIds = member.Properties.Select(x => x.Id).OrderBy(x => x); Assert.AreEqual(testPropertyIdsIncrementingFrom + 1, propertyIds.Min()); Assert.AreEqual(testPropertyIdsIncrementingFrom + 10, propertyIds.Max()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberGroupBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberGroupBuilderTests.cs index 4cb47de052..afa7de5aac 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberGroupBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberGroupBuilderTests.cs @@ -1,6 +1,10 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -17,15 +21,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testName = "Test Group"; const int testCreatorId = 4; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; var testAdditionalData1 = new KeyValuePair("test1", 123); var testAdditionalData2 = new KeyValuePair("test2", "hello"); var builder = new MemberGroupBuilder(); // Act - var group = builder + MemberGroup group = builder .WithId(testId) .WithKey(testKey) .WithName(testName) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberTypeBuilderTests.cs index e42ad306f8..b55d6467f1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/MemberTypeBuilderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -23,8 +26,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testPropertyGroupName = "Content"; const int testParentId = 98; const int testCreatorId = 22; - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testLevel = 3; const string testPath = "-1, 4, 10"; const int testSortOrder = 5; @@ -40,7 +43,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new MemberTypeBuilder(); // Act - var memberType = builder + IMemberType memberType = builder .WithId(testId) .WithKey(testKey) .WithAlias(testAlias) @@ -99,7 +102,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders Assert.IsFalse(memberType.IsContainer); Assert.AreEqual(9, memberType.PropertyTypes.Count()); // 7 from membership properties group, 2 custom - var propertyTypeIds = memberType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); + IOrderedEnumerable propertyTypeIds = memberType.PropertyTypes.Select(x => x.Id).OrderBy(x => x); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 1, propertyTypeIds.Min()); Assert.AreEqual(testPropertyTypeIdsIncrementingFrom + 9, propertyTypeIds.Max()); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyBuilderTests.cs index 7010132091..8ce3b89bd3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -14,14 +18,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders // Arrange const int testId = 4; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; var testPropertyTypeId = 3; var builder = new PropertyBuilder(); // Act - var property = builder + IProperty property = builder .WithId(testId) .WithKey(testKey) .WithCreateDate(testCreateDate) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyGroupBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyGroupBuilderTests.cs index aa68e02388..adc460732b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyGroupBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyGroupBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -16,14 +20,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var testKey = Guid.NewGuid(); const string testName = "Group1"; const int testSortOrder = 555; - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testPropertyTypeId = 3; var builder = new PropertyGroupBuilder(); // Act - var propertyGroup = builder + PropertyGroup propertyGroup = builder .WithId(testId) .WithCreateDate(testCreateDate) .WithName(testName) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeBuilderTests.cs index 6bcb22ce4d..a774e924f8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeBuilderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; @@ -21,8 +24,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testName = "Test"; const int testSortOrder = 9; const int testDataTypeId = 5; - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const string testDescription = "testing"; const int testPropertyGroupId = 11; const bool testMandatory = true; @@ -33,7 +36,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new PropertyTypeBuilder(); // Act - var propertyType = builder + PropertyType propertyType = builder .WithId(testId) .WithPropertyEditorAlias(testPropertyEditorAlias) .WithValueStorageType(testValueStorageType) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeDetail.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeDetail.cs index 1b1a1f013b..d074e6443d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeDetail.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/PropertyTypeDetail.cs @@ -1,4 +1,7 @@ -namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders { public class PropertyTypeDetail { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationBuilderTests.cs index b59ae261e0..09d9121295 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -16,8 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const int childId = 8; const int id = 4; var key = Guid.NewGuid(); - var createDate = DateTime.Now.AddHours(-1); - var updateDate = DateTime.Now; + DateTime createDate = DateTime.Now.AddHours(-1); + DateTime updateDate = DateTime.Now; const string comment = "test comment"; const int relationTypeId = 66; const string relationTypeAlias = "test"; @@ -28,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new RelationBuilder(); // Act - var relation = builder + Relation relation = builder .BetweenIds(parentId, childId) .WithId(id) .WithComment(comment) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationTypeBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationTypeBuilderTests.cs index 274ae7d878..e262d5ebbe 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationTypeBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RelationTypeBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -16,9 +20,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string alias = "test"; const string name = "Test"; var key = Guid.NewGuid(); - var createDate = DateTime.Now.AddHours(-2); - var updateDate = DateTime.Now.AddHours(-1); - var deleteDate = DateTime.Now; + DateTime createDate = DateTime.Now.AddHours(-2); + DateTime updateDate = DateTime.Now.AddHours(-1); + DateTime deleteDate = DateTime.Now; var parentObjectType = Guid.NewGuid(); var childObjectType = Guid.NewGuid(); const bool isBidirectional = true; @@ -26,7 +30,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new RelationTypeBuilder(); // Act - var relationType = builder + IRelationType relationType = builder .WithId(id) .WithAlias(alias) .WithName(name) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs index c770860b9c..9c8e5fbc28 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs @@ -1,6 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.IO; using NUnit.Framework; +using Umbraco.Core.Models; using Umbraco.Core.Routing; using Umbraco.Tests.Common.Builders; @@ -19,7 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new StylesheetBuilder(); // Act - var stylesheet = builder + Stylesheet stylesheet = builder .WithPath(testPath) .WithContent(testContent) .Build(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateBuilderTests.cs index 717c937f7d..e0ec812d4e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateBuilderTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; @@ -17,8 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const string testAlias = "test"; const string testName = "Test"; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const string testPath = "-1,3"; const string testContent = "blah"; const string testMasterTemplateAlias = "master"; @@ -27,7 +30,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new TemplateBuilder(); // Act - var template = builder + ITemplate template = builder .WithId(3) .WithAlias(testAlias) .WithName(testName) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateDetail.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateDetail.cs index 2a085931b8..f612fcf0a3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateDetail.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/TemplateDetail.cs @@ -1,4 +1,7 @@ -namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders { public class TemplateDetail { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserBuilderTests.cs index 5b3b0595a3..1063f7cf96 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserBuilderTests.cs @@ -1,5 +1,9 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; +using Umbraco.Core.Models.Membership; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -20,12 +24,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders const bool testIsApproved = true; const bool testIsLockedOut = true; var testKey = Guid.NewGuid(); - var testCreateDate = DateTime.Now.AddHours(-1); - var testUpdateDate = DateTime.Now; + DateTime testCreateDate = DateTime.Now.AddHours(-1); + DateTime testUpdateDate = DateTime.Now; const int testFailedPasswordAttempts = 22; - var testLastLockoutDate = DateTime.Now.AddHours(-2); - var testLastLoginDate = DateTime.Now.AddHours(-3); - var testLastPasswordChangeDate = DateTime.Now.AddHours(-4); + DateTime testLastLockoutDate = DateTime.Now.AddHours(-2); + DateTime testLastLoginDate = DateTime.Now.AddHours(-3); + DateTime testLastPasswordChangeDate = DateTime.Now.AddHours(-4); var testComments = "comments"; var testSessionTimeout = 5; var testStartContentIds = new[] { 3 }; @@ -34,7 +38,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new UserBuilder(); // Act - var user = builder + User user = builder .WithId(testId) .WithKey(testKey) .WithName(testName) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs index 0cfa0649ff..2751ea0e15 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs @@ -1,5 +1,9 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using NUnit.Framework; +using Umbraco.Core.Models.Membership; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -24,7 +28,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new UserGroupBuilder(); // Act - var userGroup = builder + IUserGroup userGroup = builder .WithId(testId) .WithAlias(testAlias) .WithName(testName) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/XmlDocumentBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/XmlDocumentBuilderTests.cs index 64f305edd8..028b2842d1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/XmlDocumentBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/XmlDocumentBuilderTests.cs @@ -1,4 +1,8 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Xml; +using NUnit.Framework; using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders @@ -16,7 +20,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new XmlDocumentBuilder(); // Act - var xml = builder + XmlDocument xml = builder .WithContent(content) .Build(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerTests.cs similarity index 86% rename from src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerTests.cs index 4f4db85e5e..d8e5a04c59 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using AutoFixture.NUnit3; using Moq; using NUnit.Framework; @@ -9,9 +12,10 @@ using Umbraco.Web.Common.Exceptions; namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers { [TestFixture] - public class UsersControllerUnitTests + public class UsersControllerTests { - [Test,AutoMoqData] + [Test] + [AutoMoqData] public void PostUnlockUsers_When_User_Lockout_Update_Fails_Expect_Failure_Response( [Frozen] IBackOfficeUserManager backOfficeUserManager, UsersController sut, @@ -25,6 +29,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers Assert.ThrowsAsync(() => sut.PostUnlockUsers(userIds)); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Extensions/ModelStateExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Extensions/ModelStateExtensionsTests.cs index 01dad1eebf..ce182c7e7c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Extensions/ModelStateExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Extensions/ModelStateExtensionsTests.cs @@ -1,4 +1,8 @@ -using System.ComponentModel.DataAnnotations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using Microsoft.AspNetCore.Mvc.ModelBinding; using Moq; @@ -11,7 +15,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions [TestFixture] public class ModelStateExtensionsTests { - [Test] public void Get_Cultures_With_Errors() { @@ -19,12 +22,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); //invariant property - ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); //variant property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property + ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); // variant property - var result = ms.GetVariantsWithErrors("en-US"); + IReadOnlyList<(string culture, string segment)> result = ms.GetVariantsWithErrors("en-US"); - //even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property + // even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property Assert.AreEqual(1, result.Count); Assert.AreEqual("en-US", result[0].culture); @@ -44,12 +47,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); //invariant property - ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); //variant property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property + ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); // variant property - var result = ms.GetVariantsWithPropertyErrors("en-US"); + IReadOnlyList<(string culture, string segment)> result = ms.GetVariantsWithPropertyErrors("en-US"); - //even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property + // even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property Assert.AreEqual(1, result.Count); Assert.AreEqual("en-US", result[0].culture); } @@ -61,7 +64,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); //invariant property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property Assert.AreEqual("_Properties.headerImage.invariant.null", ms.Keys.First()); } @@ -73,7 +76,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US"); //variant property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US"); // variant property Assert.AreEqual("_Properties.headerImage.en-US.null", ms.Keys.First()); } @@ -85,7 +88,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null, "mySegment"); //invariant/segment property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null, "mySegment"); // invariant/segment property Assert.AreEqual("_Properties.headerImage.invariant.mySegment", ms.Keys.First()); } @@ -97,7 +100,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US", "mySegment"); //variant/segment property + ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US", "mySegment"); // variant/segment property Assert.AreEqual("_Properties.headerImage.en-US.mySegment", ms.Keys.First()); } @@ -109,7 +112,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", null, "mySegment"); //invariant/segment property + ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", null, "mySegment"); // invariant/segment property Assert.AreEqual("_Properties.headerImage.invariant.mySegment.myField", ms.Keys.First()); } @@ -121,7 +124,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions var localizationService = new Mock(); localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US"); - ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", "en-US", "mySegment"); //variant/segment property + ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", "en-US", "mySegment"); // variant/segment property Assert.AreEqual("_Properties.headerImage.en-US.mySegment.myField", ms.Keys.First()); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs index e18f5cb3f4..fe442a023b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs @@ -1,10 +1,14 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Primitives; using Moq; using NUnit.Framework; using Umbraco.Core.Models.Membership; @@ -20,14 +24,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Appends_Header_When_No_User_Parameter_Provider() { // Arrange - var context = CreateContext(); + ActionExecutingContext context = CreateContext(); var attribute = new AppendUserModifiedHeaderAttribute(); // Act attribute.OnActionExecuting(context); // Assert - context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue); + context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out StringValues headerValue); Assert.AreEqual("1", headerValue[0]); } @@ -35,14 +39,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Append_Header_If_Already_Exists() { // Arrange - var context = CreateContext(headerValue: "0"); + ActionExecutingContext context = CreateContext(headerValue: "0"); var attribute = new AppendUserModifiedHeaderAttribute(); // Act attribute.OnActionExecuting(context); // Assert - context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue); + context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out StringValues headerValue); Assert.AreEqual("0", headerValue[0]); } @@ -50,7 +54,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Append_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User() { // Arrange - var context = CreateContext(actionArgument: new KeyValuePair("UserId", 99)); + ActionExecutingContext context = CreateContext(actionArgument: new KeyValuePair("UserId", 99)); var userIdParameter = "UserId"; var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter); @@ -65,7 +69,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Appends_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User() { // Arrange - var context = CreateContext(actionArgument: new KeyValuePair("UserId", 100)); + ActionExecutingContext context = CreateContext(actionArgument: new KeyValuePair("UserId", 100)); var userIdParameter = "UserId"; var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter); @@ -73,7 +77,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters attribute.OnActionExecuting(context); // Assert - context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue); + context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out StringValues headerValue); Assert.AreEqual("1", headerValue[0]); } @@ -95,7 +99,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters .SetupGet(x => x.CurrentUser) .Returns(currentUserMock.Object); - var serviceProviderMock = new Mock(); serviceProviderMock .Setup(x => x.GetService(typeof(IBackOfficeSecurity))) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs index 295ece927d..97f819a402 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.ComponentModel.DataAnnotations; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -11,7 +14,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters [TestFixture] public class ContentModelValidatorTests { - [Test] public void Test_Serializer() { @@ -52,7 +54,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters var outerError = new ComplexEditorValidationResult(); var id4 = Guid.NewGuid(); var addressBookCollectionElementTypeResult = new ComplexEditorElementTypeValidationResult("addressBookCollection", id4); - var booksPropertyTypeResult= new ComplexEditorPropertyTypeValidationResult("books"); + var booksPropertyTypeResult = new ComplexEditorPropertyTypeValidationResult("books"); booksPropertyTypeResult.AddValidationResult(nestedLevel1); // books is the outer most validation result addressBookCollectionElementTypeResult.ValidationResults.Add(booksPropertyTypeResult); outerError.ValidationResults.Add(addressBookCollectionElementTypeResult); @@ -60,7 +62,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters var serialized = JsonConvert.SerializeObject(outerError, Formatting.Indented, new ValidationResultConverter()); Console.WriteLine(serialized); - var jsonError = JsonConvert.DeserializeObject(serialized); + JArray jsonError = JsonConvert.DeserializeObject(serialized); Assert.IsNotNull(jsonError.SelectToken("$[0]")); Assert.AreEqual(id4.ToString(), jsonError.SelectToken("$[0].$id").Value()); @@ -105,6 +107,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters Assert.IsNotNull(error5); Assert.AreEqual(2, error5.Count); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs index 6126ee9419..fcd0dd0aea 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; using Moq; @@ -23,16 +26,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters [Test] public void GetValueFromResponse_Already_EnumerableContent() { - var expected = new List() {new ContentItemBasic()}; + var expected = new List() { new ContentItemBasic() }; - var att = new FilterAllowedOutgoingContentFilter(expected.GetType(), + var att = new FilterAllowedOutgoingContentFilter( + expected.GetType(), null, ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of()); - var result = att.GetValueFromResponse(new ObjectResult(expected)); + dynamic result = att.GetValueFromResponse(new ObjectResult(expected)); Assert.AreEqual(expected, result); } @@ -41,16 +45,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void GetValueFromResponse_From_Property() { var expected = new List() { new ContentItemBasic() }; - var container = new MyTestClass() {MyList = expected}; + var container = new MyTestClass() { MyList = expected }; - var att = new FilterAllowedOutgoingContentFilter(expected.GetType(), + var att = new FilterAllowedOutgoingContentFilter( + expected.GetType(), nameof(MyTestClass.MyList), ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of()); - var result = att.GetValueFromResponse(new ObjectResult(container)); + dynamic result = att.GetValueFromResponse(new ObjectResult(container)); Assert.AreEqual(expected, result); } @@ -61,45 +66,47 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters var expected = new List() { new ContentItemBasic() }; var container = new MyTestClass() { MyList = expected }; - var att = new FilterAllowedOutgoingContentFilter(expected.GetType(), + var att = new FilterAllowedOutgoingContentFilter( + expected.GetType(), "DontFind", ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of()); - var actual = att.GetValueFromResponse(new ObjectResult(container)); + dynamic actual = att.GetValueFromResponse(new ObjectResult(container)); Assert.IsNull(actual); - } [Test] public void Filter_On_Start_Node() { - var user = CreateUser(id: 9, startContentId: 5); + IUser user = CreateUser(id: 9, startContentId: 5); var userServiceMock = new Mock(); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; var entityServiceMock = new Mock(); entityServiceMock.Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns(new[] { Mock.Of(entity => entity.Id == 5 && entity.Path == "-1,5") }); - var entityService = entityServiceMock.Object; + IEntityService entityService = entityServiceMock.Object; var list = new List(); - var att = new FilterAllowedOutgoingContentFilter(list.GetType(), + var att = new FilterAllowedOutgoingContentFilter( + list.GetType(), null, ActionBrowse.ActionLetter, userService, entityService, - Mock.Of() ); + Mock.Of()); - var path = ""; + var path = string.Empty; for (var i = 0; i < 10; i++) { if (i > 0 && path.EndsWith(",") == false) { path += ","; } + path += i.ToInvariantString(); list.Add(new ContentItemBasic { Id = i, Name = "Test" + i, ParentId = i, Path = path }); } @@ -107,7 +114,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters att.FilterBasedOnStartNode(list, user); Assert.AreEqual(5, list.Count); - } [Test] @@ -116,30 +122,33 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters var list = new List(); for (var i = 0; i < 10; i++) { - list.Add(new ContentItemBasic{Id = i, Name = "Test" + i, ParentId = -1}); + list.Add(new ContentItemBasic { Id = i, Name = "Test" + i, ParentId = -1 }); } + var ids = list.Select(x => (int)x.Id).ToArray(); - var user = CreateUser(id: 9, startContentId: 0); + IUser user = CreateUser(id: 9, startContentId: 0); var userServiceMock = new Mock(); - //we're only assigning 3 nodes browse permissions so that is what we expect as a result + + // We're only assigning 3 nodes browse permissions so that is what we expect as a result var permissions = new EntityPermissionCollection { - new EntityPermission(9876, 1, new string[]{ ActionBrowse.ActionLetter.ToString() }), - new EntityPermission(9876, 2, new string[]{ ActionBrowse.ActionLetter.ToString() }), - new EntityPermission(9876, 3, new string[]{ ActionBrowse.ActionLetter.ToString() }), - new EntityPermission(9876, 4, new string[]{ ActionUpdate.ActionLetter.ToString() }) + new EntityPermission(9876, 1, new string[] { ActionBrowse.ActionLetter.ToString() }), + new EntityPermission(9876, 2, new string[] { ActionBrowse.ActionLetter.ToString() }), + new EntityPermission(9876, 3, new string[] { ActionBrowse.ActionLetter.ToString() }), + new EntityPermission(9876, 4, new string[] { ActionUpdate.ActionLetter.ToString() }) }; userServiceMock.Setup(x => x.GetPermissions(user, ids)).Returns(permissions); - var userService = userServiceMock.Object; + IUserService userService = userServiceMock.Object; - var att = new FilterAllowedOutgoingContentFilter(list.GetType(), + var att = new FilterAllowedOutgoingContentFilter( + list.GetType(), null, ActionBrowse.ActionLetter, userService, Mock.Of(), - Mock.Of() ); + Mock.Of()); att.FilterBasedOnPermissions(list, user); Assert.AreEqual(3, list.Count); @@ -148,13 +157,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters Assert.AreEqual(3, list.ElementAt(2).Id); } - private IUser CreateUser(int id = 0, int? startContentId = null) - { - return new UserBuilder() + private IUser CreateUser(int id = 0, int? startContentId = null) => + new UserBuilder() .WithId(id) .WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0]) .Build(); - } private class MyTestClass { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/OnlyLocalRequestsAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/OnlyLocalRequestsAttributeTests.cs index 7d1fbdddf1..f616216974 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/OnlyLocalRequestsAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/OnlyLocalRequestsAttributeTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -18,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Set_Result_When_No_Remote_Address() { // Arrange - var context = CreateContext(); + ActionExecutingContext context = CreateContext(); var attribute = new OnlyLocalRequestsAttribute(); // Act @@ -32,7 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Set_Result_When_Remote_Address_Is_Null_Ip_Address() { // Arrange - var context = CreateContext(remoteIpAddress: "::1"); + ActionExecutingContext context = CreateContext(remoteIpAddress: "::1"); var attribute = new OnlyLocalRequestsAttribute(); // Act @@ -46,7 +49,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Set_Result_When_Remote_Address_Matches_Local_Address() { // Arrange - var context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "100.1.2.3"); + ActionExecutingContext context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "100.1.2.3"); var attribute = new OnlyLocalRequestsAttribute(); // Act @@ -60,7 +63,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Returns_Not_Found_When_Remote_Address_Does_Not_Match_Local_Address() { // Arrange - var context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "100.1.2.2"); + ActionExecutingContext context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "100.1.2.2"); var attribute = new OnlyLocalRequestsAttribute(); // Act @@ -75,7 +78,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Set_Result_When_Remote_Address_Matches_LoopBack_Address() { // Arrange - var context = CreateContext(remoteIpAddress: "127.0.0.1", localIpAddress: "::1"); + ActionExecutingContext context = CreateContext(remoteIpAddress: "127.0.0.1", localIpAddress: "::1"); var attribute = new OnlyLocalRequestsAttribute(); // Act @@ -89,7 +92,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Returns_Not_Found_When_Remote_Address_Does_Not_Match_LoopBack_Address() { // Arrange - var context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "::1"); + ActionExecutingContext context = CreateContext(remoteIpAddress: "100.1.2.3", localIpAddress: "::1"); var attribute = new OnlyLocalRequestsAttribute(); // Act diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ValidationFilterAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ValidationFilterAttributeTests.cs index 51521c48fa..a14084c923 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ValidationFilterAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/ValidationFilterAttributeTests.cs @@ -1,12 +1,12 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Collections.Generic; -using System.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Routing; using Moq; using NUnit.Framework; @@ -21,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Does_Not_Set_Result_When_No_Errors_In_Model_State() { // Arrange - var context = CreateContext(); + ActionExecutingContext context = CreateContext(); var attribute = new ValidationFilterAttribute(); // Act @@ -35,7 +35,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters public void Returns_Bad_Request_When_Errors_In_Model_State() { // Arrange - var context = CreateContext(withError: true); + ActionExecutingContext context = CreateContext(withError: true); var attribute = new ValidationFilterAttribute(); // Act diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgeryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgeryTests.cs index 7899ef39c2..568318006e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgeryTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeAntiforgeryTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Linq; using System.Security.Claims; @@ -43,12 +46,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Security var container = new ServiceCollection(); container.AddLogging(); container.AddAntiforgery(); - var services = container.BuildServiceProvider(); + ServiceProvider services = container.BuildServiceProvider(); - var antiforgery = services.GetRequiredService(); - var options = services.GetRequiredService>(); + IAntiforgery antiforgery = services.GetRequiredService(); + IOptions options = services.GetRequiredService>(); - var httpContext = GetHttpContext(); + HttpContext httpContext = GetHttpContext(); var backofficeAntiforgery = new BackOfficeAntiforgery(antiforgery, options); backofficeAntiforgery.GetTokens(httpContext, out var cookieToken, out var headerToken); @@ -58,7 +61,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Security // the same context cannot validate since it's already created tokens httpContext = GetHttpContext(); - var result = await backofficeAntiforgery.ValidateRequestAsync(httpContext); + Attempt result = await backofficeAntiforgery.ValidateRequestAsync(httpContext); Assert.IsFalse(result.Success); // missing token diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs index 80432cdce2..b677f11f2c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs @@ -1,10 +1,10 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Extensions; @@ -22,7 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security { var globalSettings = new GlobalSettings(); - var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); + IRuntimeState runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); var mgr = new BackOfficeCookieManager( Mock.Of(), runtime, @@ -39,7 +39,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security { var globalSettings = new GlobalSettings(); - var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); + IRuntimeState runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); var mgr = new BackOfficeCookieManager( Mock.Of(), runtime, @@ -56,7 +56,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security { var globalSettings = new GlobalSettings(); - var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); + IRuntimeState runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); GenerateAuthPaths(out var remainingTimeoutSecondsPath, out var isAuthPath); @@ -73,13 +73,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security Assert.IsTrue(result); } - [Test] public void ShouldAuthenticateRequest_Not_Back_Office() { var globalSettings = new GlobalSettings(); - var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); + IRuntimeState runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); var mgr = new BackOfficeCookieManager( Mock.Of(), @@ -104,7 +103,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Backoffice.Security // this is on the same controller but is considered a back office request var aPath = isAuthPath = $"/umbraco/{Constants.Web.Mvc.BackOfficePathSegment}/{Constants.Web.Mvc.BackOfficeApiArea}/{controllerName}/{nameof(AuthenticationController.IsAuthenticated)}".ToLower(); - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs index eb8b2f8a23..79a971d9f4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -14,7 +17,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration [Test] public void Content_Display_To_Json() { - //create 3 tabs with 3 properties each + // create 3 tabs with 3 properties each var tabs = new List>(); for (var tabIndex = 0; tabIndex < 3; tabIndex++) { @@ -33,6 +36,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration HideLabel = false }); } + tabs.Add(new Tab() { Alias = "Tab" + tabIndex, @@ -60,7 +64,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration Assert.AreEqual("1234", jObject["id"].ToString()); Assert.AreEqual("Test", jObject["variants"][0]["name"].ToString()); - var jsonTabs = jObject["variants"][0]["tabs"]; + + JToken jsonTabs = jObject["variants"][0]["tabs"]; Assert.AreEqual(3, jsonTabs.Count()); for (var tab = 0; tab < jsonTabs.Count(); tab++) { @@ -79,6 +84,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration } } } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs index f082ba5d76..c29f5f16b7 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.WebAssets; @@ -7,13 +10,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration [TestFixture] public class JsInitializationTests { - [Test] public void Parse_Main() { var result = BackOfficeJavaScriptInitializer.WriteScript("[World]", "Hello", "Blah"); - Assert.AreEqual(@"LazyLoad.js([World], function () { + Assert.AreEqual( + @"LazyLoad.js([World], function () { //we need to set the legacy UmbClientMgr path if ((typeof UmbClientMgr) !== ""undefined"") { UmbClientMgr.setUmbracoPath('Hello'); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs index 0663c423d8..fd9f28946f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.WebAssets; @@ -11,12 +14,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration [Test] public void Parse() { - var d = new Dictionary(); - d.Add("test1", "Test 1"); - d.Add("test2", "Test 2"); - d.Add("test3", "Test 3"); - d.Add("test4", "Test 4"); - d.Add("test5", "Test 5"); + var d = new Dictionary + { + { "test1", "Test 1" }, + { "test2", "Test 2" }, + { "test3", "Test 3" }, + { "test4", "Test 4" }, + { "test5", "Test 5" } + }; var output = ServerVariablesParser.Parse(d).StripWhitespace(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs index abb44a5dfb..19433769fa 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs @@ -1,4 +1,7 @@ -using System.Text.Encodings.Web; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Text.Encodings.Web; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; @@ -10,7 +13,6 @@ using Umbraco.Extensions; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Filters { - [TestFixture] public class HtmlHelperExtensionMethodsTests { @@ -18,16 +20,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Filters private const string SampleWithBoldAndAnchorElements = "Hello world, this is some text with a link"; [SetUp] - public virtual void Initialize() - { - //create an empty htmlHelper - _htmlHelper = new HtmlHelper(Mock.Of(), + public virtual void Initialize() => + + // Create an empty HtmlHelper. + _htmlHelper = new HtmlHelper( + Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new HtmlTestEncoder(), UrlEncoder.Default); - } private HtmlHelper _htmlHelper; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs index bee0b8bf15..5fc5987354 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Collections.Generic; using System.IO; using System.Linq; @@ -8,7 +11,6 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Tests.UnitTests.AutoFixture; @@ -48,7 +50,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var viewResult = await sut.Index() as ViewResult; var fileName = GetViewName(viewResult, Path.DirectorySeparatorChar.ToString()); - var views = GetUiFiles(new[] { "umbraco", "UmbracoInstall" }); + IEnumerable views = GetUiFiles(new[] { "umbraco", "UmbracoInstall" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } @@ -63,7 +65,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var viewResult = sut.Index() as ViewResult; var fileName = GetViewName(viewResult); - var views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); + IEnumerable views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } @@ -80,24 +82,24 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common Mock.Get(hostingEnvironment).Setup(x => x.ToAbsolute("/")).Returns("http://localhost/"); Mock.Get(hostingEnvironment).SetupGet(x => x.ApplicationVirtualPath).Returns("/"); - sut.TempData = tempDataDictionary; var viewResult = await sut.Default() as ViewResult; var fileName = GetViewName(viewResult); - var views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); + IEnumerable views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } - [Test] public void LanguageFilesAreLowercase() { - var files = GetUiFiles(new[] { "umbraco", "config", "lang" }); + IEnumerable files = GetUiFiles(new[] { "umbraco", "config", "lang" }); foreach (var fileName in files) { - Assert.AreEqual(fileName.ToLower(), fileName, + Assert.AreEqual( + fileName.ToLower(), + fileName, $"Language files must be all lowercase but {fileName} is not lowercase."); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs index 3ed4a28b06..03bab2e02b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.DataProtection; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.AspNetCore.DataProtection; using NUnit.Framework; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; @@ -36,6 +39,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Filters Assert.DoesNotThrow(() => filter.ValidateRouteString(validUfprt, ControllerName, ControllerAction, Area)); Assert.DoesNotThrow(() => filter.ValidateRouteString(validUfprt, ControllerName.ToLowerInvariant(), ControllerAction.ToLowerInvariant(), Area.ToLowerInvariant())); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Formatters/IgnoreRequiredAttributesResolverUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Formatters/IgnoreRequiredAttributesResolverUnitTests.cs index 94133c9e27..ab087b325a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Formatters/IgnoreRequiredAttributesResolverUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Formatters/IgnoreRequiredAttributesResolverUnitTests.cs @@ -1,4 +1,6 @@ -using System.ComponentModel.DataAnnotations; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Runtime.Serialization; using Newtonsoft.Json; using NUnit.Framework; @@ -9,7 +11,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Formatters [TestFixture] public class IgnoreRequiredAttributesResolverUnitTests { - [Test] public void Test() { @@ -17,14 +18,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Formatters Assert.Multiple(() => { - //Ensure the deserialization throws if using default settings + // Ensure the deserialization throws if using default settings Assert.Throws(() => JsonConvert.DeserializeObject(emptyJsonObject)); - var actual = JsonConvert.DeserializeObject(emptyJsonObject,new JsonSerializerSettings - { - ContractResolver = new IgnoreRequiredAttributesResolver() - }); + ObjectWithRequiredProperty actual = JsonConvert.DeserializeObject( + emptyJsonObject, + new JsonSerializerSettings + { + ContractResolver = new IgnoreRequiredAttributesResolver() + }); Assert.IsNotNull(actual); Assert.IsNull(actual.Property); @@ -35,7 +38,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Formatters private class ObjectWithRequiredProperty { [DataMember(Name = "property", IsRequired = true)] - public string Property{ get; set; } + public string Property { get; set; } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs index 417880f476..2ec4c40714 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs @@ -1,19 +1,21 @@ -using System.Globalization; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.Globalization; +using System.Text; using Newtonsoft.Json; -using NUnit.Framework; using Newtonsoft.Json.Linq; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors.ValueConverters; -using Umbraco.Web.Models; -using System.Text; -using Umbraco.Core.Media; using Umbraco.Extensions; -using System.Collections.Generic; +using Umbraco.Web.Models; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common { - [TestFixture] public class ImageCropperTest { @@ -25,9 +27,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void CanConvertImageCropperDataSetSrcToString() { - //cropperJson3 - has not crops - var cropperValue = CropperJson3.DeserializeImageCropperValue(); - var serialized = cropperValue.TryConvertTo(); + // cropperJson3 - has not crops + ImageCropperValue cropperValue = CropperJson3.DeserializeImageCropperValue(); + Attempt serialized = cropperValue.TryConvertTo(); Assert.IsTrue(serialized.Success); Assert.AreEqual("/media/1005/img_0672.jpg", serialized.Result); } @@ -35,9 +37,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void CanConvertImageCropperDataSetJObject() { - //cropperJson3 - has not crops - var cropperValue = CropperJson3.DeserializeImageCropperValue(); - var serialized = cropperValue.TryConvertTo(); + // cropperJson3 - has not crops + ImageCropperValue cropperValue = CropperJson3.DeserializeImageCropperValue(); + Attempt serialized = cropperValue.TryConvertTo(); Assert.IsTrue(serialized.Success); Assert.AreEqual(cropperValue, serialized.Result.ToObject()); } @@ -45,56 +47,56 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void CanConvertImageCropperDataSetJsonToString() { - var cropperValue = CropperJson1.DeserializeImageCropperValue(); - var serialized = cropperValue.TryConvertTo(); + ImageCropperValue cropperValue = CropperJson1.DeserializeImageCropperValue(); + Attempt serialized = cropperValue.TryConvertTo(); Assert.IsTrue(serialized.Success); Assert.IsTrue(serialized.Result.DetectIsJson()); - var obj = JsonConvert.DeserializeObject(CropperJson1, new JsonSerializerSettings {Culture = CultureInfo.InvariantCulture, FloatParseHandling = FloatParseHandling.Decimal}); + ImageCropperValue obj = JsonConvert.DeserializeObject(CropperJson1, new JsonSerializerSettings { Culture = CultureInfo.InvariantCulture, FloatParseHandling = FloatParseHandling.Decimal }); Assert.AreEqual(cropperValue, obj); } - // [TestCase(CropperJson1, CropperJson1, true)] - // [TestCase(CropperJson1, CropperJson2, false)] - // public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected) - // { - // try - // { - // var container = TestHelper.GetRegister(); - // var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); - // - // composition.WithCollectionBuilder(); - // - // Current.Factory = composition.CreateFactory(); - // - // var logger = Mock.Of(); - // var scheme = Mock.Of(); - // var shortStringHelper = Mock.Of(); - // - // var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, shortStringHelper); - // - // var dataTypeService = new TestObjects.TestDataTypeService( - // new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())) { Id = 1 }); - // - // var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); - // - // var converter = new ImageCropperValueConverter(); - // var result = converter.ConvertSourceToIntermediate(null, factory.CreatePropertyType("test", 1), val1, false); // does not use type for conversion - // - // var resultShouldMatch = val2.DeserializeImageCropperValue(); - // if (expected) - // { - // Assert.AreEqual(resultShouldMatch, result); - // } - // else - // { - // Assert.AreNotEqual(resultShouldMatch, result); - // } - // } - // finally - // { - // Current.Reset(); - // } - // } + //// [TestCase(CropperJson1, CropperJson1, true)] + //// [TestCase(CropperJson1, CropperJson2, false)] + //// public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected) + //// { + //// try + //// { + //// var container = TestHelper.GetRegister(); + //// var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + //// + //// composition.WithCollectionBuilder(); + //// + //// Current.Factory = composition.CreateFactory(); + //// + //// var logger = Mock.Of(); + //// var scheme = Mock.Of(); + //// var shortStringHelper = Mock.Of(); + //// + //// var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, shortStringHelper); + //// + //// var dataTypeService = new TestObjects.TestDataTypeService( + //// new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())) { Id = 1 }); + //// + //// var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); + //// + //// var converter = new ImageCropperValueConverter(); + //// var result = converter.ConvertSourceToIntermediate(null, factory.CreatePropertyType("test", 1), val1, false); // does not use type for conversion + //// + //// var resultShouldMatch = val2.DeserializeImageCropperValue(); + //// if (expected) + //// { + //// Assert.AreEqual(resultShouldMatch, result); + //// } + //// else + //// { + //// Assert.AreNotEqual(resultShouldMatch, result); + //// } + //// } + //// finally + //// { + //// Current.Reset(); + //// } + //// } [Test] public void GetCropUrl_CropAliasTest() @@ -150,7 +152,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void GetBaseCropUrlFromModelTest() { - var cropDataSet = CropperJson1.DeserializeImageCropperValue(); + ImageCropperValue cropDataSet = CropperJson1.DeserializeImageCropperValue(); var urlString = cropDataSet.GetCropUrl("thumb", new TestImageUrlGenerator()); Assert.AreEqual("?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&w=100&h=100", urlString); } @@ -161,7 +163,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void GetCropUrl_CropAliasHeightRatioModeTest() { - var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height); + var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode: ImageCropRatioMode.Height); Assert.AreEqual(MediaPath + "?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&hr=1&w=100", urlString); } @@ -171,7 +173,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void GetCropUrl_WidthHeightRatioModeTest() { - var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height); + var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Height); Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&hr=0.5&w=300", urlString); } @@ -194,7 +196,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var urlStringMin = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Min); var urlStringBoxPad = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.BoxPad); var urlStringPad = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Pad); - var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max); + var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Max); var urlStringStretch = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Stretch); Assert.AreEqual(MediaPath + "?m=min&w=300&h=150", urlStringMin); @@ -222,7 +224,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common { const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}"; - var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true); + var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint: true); Assert.AreEqual(MediaPath + "?m=defaultcrop&w=300&h=150", urlString); } @@ -340,20 +342,62 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common else { imageProcessorUrl.Append("?m=" + options.ImageCropMode.ToString().ToLower()); - if (options.ImageCropAnchor != null)imageProcessorUrl.Append("&a=" + options.ImageCropAnchor.ToString().ToLower()); + if (options.ImageCropAnchor != null) + { + imageProcessorUrl.Append("&a=" + options.ImageCropAnchor.ToString().ToLower()); + } } var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&f="); - if (options.Quality != null && hasFormat == false) imageProcessorUrl.Append("&q=" + options.Quality); - if (options.HeightRatio != null) imageProcessorUrl.Append("&hr=" + options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture)); - if (options.WidthRatio != null) imageProcessorUrl.Append("&wr=" + options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture)); - if (options.Width != null) imageProcessorUrl.Append("&w=" + options.Width); - if (options.Height != null) imageProcessorUrl.Append("&h=" + options.Height); - if (options.UpScale == false) imageProcessorUrl.Append("&u=no"); - if (options.AnimationProcessMode != null) imageProcessorUrl.Append("&apm=" + options.AnimationProcessMode); - if (options.FurtherOptions != null) imageProcessorUrl.Append(options.FurtherOptions); - if (options.Quality != null && hasFormat) imageProcessorUrl.Append("&q=" + options.Quality); - if (options.CacheBusterValue != null) imageProcessorUrl.Append("&r=").Append(options.CacheBusterValue); + if (options.Quality != null && hasFormat == false) + { + imageProcessorUrl.Append("&q=" + options.Quality); + } + + if (options.HeightRatio != null) + { + imageProcessorUrl.Append("&hr=" + options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (options.WidthRatio != null) + { + imageProcessorUrl.Append("&wr=" + options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (options.Width != null) + { + imageProcessorUrl.Append("&w=" + options.Width); + } + + if (options.Height != null) + { + imageProcessorUrl.Append("&h=" + options.Height); + } + + if (options.UpScale == false) + { + imageProcessorUrl.Append("&u=no"); + } + + if (options.AnimationProcessMode != null) + { + imageProcessorUrl.Append("&apm=" + options.AnimationProcessMode); + } + + if (options.FurtherOptions != null) + { + imageProcessorUrl.Append(options.FurtherOptions); + } + + if (options.Quality != null && hasFormat) + { + imageProcessorUrl.Append("&q=" + options.Quality); + } + + if (options.CacheBusterValue != null) + { + imageProcessorUrl.Append("&r=").Append(options.CacheBusterValue); + } return imageProcessorUrl.ToString(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs index 80a25d7fc5..e8cfa0501f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using NUnit.Framework; using Umbraco.Web.Macros; @@ -11,155 +14,129 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros [Test] public void Format_RTE_Data_For_Editor_With_No_Macros() { - var content = @"

hello world

"; - var result = MacroTagParser.FormatRichTextContentForPersistence(content); + string content = @"

hello world

"; + string result = MacroTagParser.FormatRichTextContentForPersistence(content); Assert.AreEqual(@"

hello world

", content); } [Test] public void Format_RTE_Data_For_Editor_With_Non_AlphaNumeric_Char_In_Alias() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: My.Map.isCool eh[boy!]
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary(){{"test1", "value1"},{"test2", "value2"}}); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_Closing_Tag() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params_When_MacroAlias_Not_First() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params_When_MacroAlias_Is_First() { - - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); - // Assert.AreEqual(@"

asdfasdf

- //

asdfsadf

- //
- // - //Macro alias: Map
- //

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params_When_Multiple_Macros() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfsadf

@@ -167,24 +144,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); - // Assert.AreEqual(@"

asdfasdf

- //

asdfsadf

- //
- // - //Macro alias: Map
- //

asdfsadf

- //
- // - //Macro alias: Map
- //

asdfsadf

- //
- // - //Macro alias: Map
- //

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

@@ -197,21 +160,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros
Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Multiple_Macros() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

 

 

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary()); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary()); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

Macro alias: Breadcrumb
@@ -220,13 +185,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros
Macro alias: login
-

 

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

 

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Persistence_Multiline_Parameters() { - var content = @" + string content = @"

asdfasdf

@@ -243,9 +209,10 @@ asdfsdf
"; - var result = MacroTagParser.FormatRichTextContentForPersistence(content); + string result = MacroTagParser.FormatRichTextContentForPersistence(content); - Assert.AreEqual(@" + Assert.AreEqual( + @"

asdfasdf

asdfsdf
-".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag_And_Content() { - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2" } }); -// Assert.AreEqual(@"

asdfasdf

-//

asdfsadf

-//
-// -//Macro alias: Map
-//

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } - [Test] public void Format_RTE_Data_For_Editor_With_Multiline_Parameters() { - - var content = @"

asdfasdf

+ string content = @"

asdfasdf

asdfsadf

asdfasdf

"; - var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2\r\ntest" } }); + string result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary() { { "test1", "value1" }, { "test2", "value2\r\ntest" } }); - Assert.AreEqual(@"

asdfasdf

+ Assert.AreEqual( + @"

asdfasdf

asdfsadf

Macro alias: Map
-

asdfasdf

".NoCrLf(), result.NoCrLf()); +

asdfasdf

".NoCrLf(), + result.NoCrLf()); } [Test] public void Format_RTE_Data_For_Persistence() { -// var content = @" -// -//

asdfasdf

-//
-// -//asdfasdf -//asdfas -//asdfasdfasdf -//

asdfasdf

-//
-//asdfdasf -//
-//asdfsdf -//
-// -//"; - var content = @" + string content = @"

asdfasdf

@@ -361,9 +305,10 @@ asdfsdf
"; - var result = MacroTagParser.FormatRichTextContentForPersistence(content); + string result = MacroTagParser.FormatRichTextContentForPersistence(content); - Assert.AreEqual(@" + Assert.AreEqual( + @"

asdfasdf

@@ -372,13 +317,14 @@ asdfsdf asdfsdf -".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Persistence_No_Class() { - var content = @" + string content = @"

asdfasdf

@@ -394,9 +340,10 @@ asdfsdf
"; - var result = MacroTagParser.FormatRichTextContentForPersistence(content); + string result = MacroTagParser.FormatRichTextContentForPersistence(content); - Assert.AreEqual(@" + Assert.AreEqual( + @"

asdfasdf

@@ -405,21 +352,14 @@ asdfsdf asdfsdf -".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +".Replace(Environment.NewLine, string.Empty), + result.Replace(Environment.NewLine, string.Empty)); } [Test] public void Format_RTE_Data_For_Persistence_Custom_Single_Entry() { -// var content = @"
-//
-//
-//

null

-//
-//
1089
-//
-//
"; - var content = @"
+ string content = @"

null

@@ -427,10 +367,9 @@ asdfsdf
1089
"; - var result = MacroTagParser.FormatRichTextContentForPersistence(content); + string result = MacroTagParser.FormatRichTextContentForPersistence(content); Assert.AreEqual(@"", result); } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroTests.cs index 9bb4e6e54a..d789156eb5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Web.Macros; @@ -7,11 +10,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros [TestFixture] public class MacroTests { - [SetUp] public void Setup() { - //we DO want cache enabled for these tests + // We DO want cache enabled for these tests var cacheHelper = new AppCaches( new ObjectCacheAppCache(), NoAppCache.Instance, @@ -28,23 +30,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Macros }; var filename = MacroRenderer.GetMacroFileName(model); if (expectedNonNull) + { Assert.IsNotNull(filename); + } else + { Assert.IsNull(filename); - } - - //[TestCase(-5, true)] //the cache DateTime will be older than the file date - //[TestCase(5, false)] //the cache DateTime will be newer than the file date - public void Macro_Needs_Removing_Based_On_Macro_File(int minutesToNow, bool expectedNull) - { - // macro has been refactored, and macro.GetMacroContentFromCache() will - // take care of the macro file, if any. It requires a web environment, - // so we cannot really test this anymore. - } - - public void Get_Macro_Cache_Identifier() - { - //var asdf = macro.GetCacheIdentifier() + } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs index b414e49e95..f539d25152 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; @@ -9,6 +13,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Common.ModelBinders; +using Umbraco.Web.Common.Routing; using Umbraco.Web.Models; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders @@ -16,58 +21,100 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders [TestFixture] public class ContentModelBinderTests { + private ContentModelBinder _contentModelBinder; + + [SetUp] + public void SetUp() => _contentModelBinder = new ContentModelBinder(); + [Test] - public void Does_Not_Bind_Model_When_UmbracoDataToken_Not_In_Route_Data() + [TestCase(typeof(IPublishedContent), false)] + [TestCase(typeof(ContentModel), false)] + [TestCase(typeof(ContentType1), false)] + [TestCase(typeof(ContentModel), false)] + [TestCase(typeof(NonContentModel), true)] + [TestCase(typeof(MyCustomContentModel), true)] + [TestCase(typeof(IContentModel), true)] + public void Returns_Binder_For_IPublishedContent_And_IRenderModel(Type testType, bool expectNull) + { + var binderProvider = new ContentModelBinderProvider(); + var contextMock = new Mock(); + contextMock.Setup(x => x.Metadata).Returns(new EmptyModelMetadataProvider().GetMetadataForType(testType)); + + IModelBinder found = binderProvider.GetBinder(contextMock.Object); + if (expectNull) + { + Assert.IsNull(found); + } + else + { + Assert.IsNotNull(found); + } + } + + [Test] + public async Task Does_Not_Bind_Model_When_UmbracoToken_Not_In_Route_Values() { // Arrange - var bindingContext = CreateBindingContext(typeof(ContentModel), withUmbracoDataToken: false); - var binder = new ContentModelBinder(); + IPublishedContent pc = CreatePublishedContent(); + ModelBindingContext bindingContext = CreateBindingContextForUmbracoRequest(typeof(ContentModel), pc); + bindingContext.ActionContext.RouteData.Values.Remove(Constants.Web.UmbracoRouteDefinitionDataToken); // Act - binder.BindModelAsync(bindingContext); + await _contentModelBinder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); } [Test] - public void Does_Not_Bind_Model_When_Source_Not_Of_Expected_Type() + public async Task Does_Not_Bind_Model_When_UmbracoToken_Has_Incorrect_Model() { // Arrange - var bindingContext = CreateBindingContext(typeof(ContentModel), source: new NonContentModel()); - var binder = new ContentModelBinder(); + IPublishedContent pc = CreatePublishedContent(); + ModelBindingContext bindingContext = CreateBindingContextForUmbracoRequest(typeof(ContentModel), pc); + bindingContext.ActionContext.RouteData.Values[Constants.Web.UmbracoRouteDefinitionDataToken] = new NonContentModel(); // Act - binder.BindModelAsync(bindingContext); + await _contentModelBinder.BindModelAsync(bindingContext); // Assert Assert.False(bindingContext.Result.IsModelSet); } [Test] - public void BindModel_Returns_If_Same_Type() + public async Task Bind_Model_When_UmbracoToken_Is_In_Route_Values() { // Arrange - var content = new ContentModel(CreatePublishedContent()); - var bindingContext = CreateBindingContext(typeof(ContentModel), source: content); - var binder = new ContentModelBinder(); + IPublishedContent pc = CreatePublishedContent(); + ModelBindingContext bindingContext = CreateBindingContextForUmbracoRequest(typeof(ContentModel), pc); // Act - binder.BindModelAsync(bindingContext); + await _contentModelBinder.BindModelAsync(bindingContext); // Assert - Assert.AreSame(content, bindingContext.Result.Model); + Assert.True(bindingContext.Result.IsModelSet); + } + + [Test] + public void Throws_When_Source_Not_Of_Expected_Type() + { + // Arrange + IPublishedContent pc = CreatePublishedContent(); + var bindingContext = new DefaultModelBindingContext(); + + // Act/Assert + Assert.Throws(() => _contentModelBinder.BindModel(bindingContext, new NonContentModel(), typeof(ContentModel))); } [Test] public void Binds_From_IPublishedContent_To_Content_Model() { // Arrange - var bindingContext = CreateBindingContext(typeof(ContentModel), source: CreatePublishedContent()); - var binder = new ContentModelBinder(); + IPublishedContent pc = CreatePublishedContent(); + ModelBindingContext bindingContext = new DefaultModelBindingContext(); // Act - binder.BindModelAsync(bindingContext); + _contentModelBinder.BindModel(bindingContext, pc, typeof(ContentModel)); // Assert Assert.True(bindingContext.Result.IsModelSet); @@ -77,22 +124,98 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders public void Binds_From_IPublishedContent_To_Content_Model_Of_T() { // Arrange - var bindingContext = CreateBindingContext(typeof(ContentModel), source: new ContentModel(new ContentType2(CreatePublishedContent()))); - var binder = new ContentModelBinder(); + IPublishedContent pc = CreatePublishedContent(); + ModelBindingContext bindingContext = new DefaultModelBindingContext(); // Act - binder.BindModelAsync(bindingContext); + _contentModelBinder.BindModel(bindingContext, new ContentModel(new ContentType2(pc)), typeof(ContentModel)); // Assert Assert.True(bindingContext.Result.IsModelSet); } - private ModelBindingContext CreateBindingContext(Type modelType, bool withUmbracoDataToken = true, object source = null) + [Test] + public void BindModel_Null_Source_Returns_Null() + { + var bindingContext = new DefaultModelBindingContext(); + _contentModelBinder.BindModel(bindingContext, null, typeof(ContentType1)); + Assert.IsNull(bindingContext.Result.Model); + } + + [Test] + public void BindModel_Returns_If_Same_Type() + { + var content = new ContentType1(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModel(bindingContext, content, typeof(ContentType1)); + + Assert.AreSame(content, bindingContext.Result.Model); + } + + [Test] + public void BindModel_RenderModel_To_IPublishedContent() + { + var content = new ContentType1(Mock.Of()); + var renderModel = new ContentModel(content); + + var bindingContext = new DefaultModelBindingContext(); + _contentModelBinder.BindModel(bindingContext, renderModel, typeof(IPublishedContent)); + + Assert.AreSame(content, bindingContext.Result.Model); + } + + [Test] + public void BindModel_IPublishedContent_To_RenderModel() + { + var content = new ContentType1(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModel(bindingContext, content, typeof(ContentModel)); + var bound = (IContentModel)bindingContext.Result.Model; + + Assert.AreSame(content, bound.Content); + } + + [Test] + public void BindModel_IPublishedContent_To_Generic_RenderModel() + { + var content = new ContentType1(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModel(bindingContext, content, typeof(ContentModel)); + var bound = (IContentModel)bindingContext.Result.Model; + + Assert.AreSame(content, bound.Content); + } + + [Test] + public void Null_Model_Binds_To_Null() + { + IPublishedContent pc = Mock.Of(); + var bindingContext = new DefaultModelBindingContext(); + _contentModelBinder.BindModel(bindingContext, null, typeof(ContentModel)); + Assert.IsNull(bindingContext.Result.Model); + } + + [Test] + public void Invalid_Model_Type_Throws_Exception() + { + IPublishedContent pc = Mock.Of(); + var bindingContext = new DefaultModelBindingContext(); + Assert.Throws(() => _contentModelBinder.BindModel(bindingContext, "Hello", typeof(IPublishedContent))); + } + + /// + /// Creates a binding context with the route values populated to similute an Umbraco dynamically routed request + /// + private ModelBindingContext CreateBindingContextForUmbracoRequest(Type modelType, IPublishedContent publishedContent) { var httpContext = new DefaultHttpContext(); var routeData = new RouteData(); - if (withUmbracoDataToken) - routeData.DataTokens.Add(Constants.Web.UmbracoDataToken, source); + routeData.Values.Add(Constants.Web.UmbracoRouteDefinitionDataToken, new UmbracoRouteValues(publishedContent)); + { + } var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); var metadataProvider = new EmptyModelMetadataProvider(); @@ -111,19 +234,29 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders { } - private IPublishedContent CreatePublishedContent() - { - return new ContentType2(new Mock().Object); - } + private IPublishedContent CreatePublishedContent() => new ContentType2(new Mock().Object); public class ContentType1 : PublishedContentWrapped { - public ContentType1(IPublishedContent content) : base(content) { } + public ContentType1(IPublishedContent content) + : base(content) + { + } } public class ContentType2 : ContentType1 { - public ContentType2(IPublishedContent content) : base(content) { } + public ContentType2(IPublishedContent content) + : base(content) + { + } + } + + public class MyCustomContentModel : ContentModel + { + public MyCustomContentModel(IPublishedContent content) + : base(content) + { } } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/HttpQueryStringModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/HttpQueryStringModelBinderTests.cs index 6dd3b024b3..6e06adf727 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/HttpQueryStringModelBinderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/HttpQueryStringModelBinderTests.cs @@ -1,4 +1,8 @@ -using Microsoft.AspNetCore.Http; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; @@ -16,7 +20,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders public void Binds_Query_To_FormCollection() { // Arrange - var bindingContext = CreateBindingContext("?foo=bar&baz=buzz"); + ModelBindingContext bindingContext = CreateBindingContext("?foo=bar&baz=buzz"); var binder = new HttpQueryStringModelBinder(); // Act @@ -35,7 +39,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders public void Sets_Culture_Form_Value_From_Query_If_Provided() { // Arrange - var bindingContext = CreateBindingContext("?foo=bar&baz=buzz&culture=en-gb"); + ModelBindingContext bindingContext = CreateBindingContext("?foo=bar&baz=buzz&culture=en-gb"); var binder = new HttpQueryStringModelBinder(); // Act @@ -53,7 +57,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders public void Sets_Culture_Form_Value_From_Header_If_Not_Provided_In_Query() { // Arrange - var bindingContext = CreateBindingContext("?foo=bar&baz=buzz"); + ModelBindingContext bindingContext = CreateBindingContext("?foo=bar&baz=buzz"); var binder = new HttpQueryStringModelBinder(); // Act @@ -77,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders var metadataProvider = new EmptyModelMetadataProvider(); var routeValueDictionary = new RouteValueDictionary(); var valueProvider = new RouteValueProvider(BindingSource.Path, routeValueDictionary); - var modelType = typeof(FormCollection); + Type modelType = typeof(FormCollection); return new DefaultModelBindingContext { ActionContext = actionContext, diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs deleted file mode 100644 index 501c10551d..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Routing; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Common.ModelBinders; -using Umbraco.Web.Models; - -namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders -{ - [TestFixture] - public class RenderModelBinderTests - { - private ContentModelBinder _contentModelBinder; - [SetUp] - public void SetUp() - { - _contentModelBinder = new ContentModelBinder(); - } - - [Test] - [TestCase(typeof(IPublishedContent), false)] - [TestCase(typeof(ContentModel), false)] - [TestCase(typeof(MyContent), false)] - [TestCase(typeof(ContentModel), false)] - [TestCase(typeof(MyOtherContent), true)] - [TestCase(typeof(MyCustomContentModel), true)] - [TestCase(typeof(IContentModel), true)] - public void Returns_Binder_For_IPublishedContent_And_IRenderModel(Type testType, bool expectNull) - { - var binderProvider = new ContentModelBinderProvider(); - var contextMock = new Mock(); - contextMock.Setup(x => x.Metadata).Returns(new EmptyModelMetadataProvider().GetMetadataForType(testType)); - - var found = binderProvider.GetBinder(contextMock.Object); - if (expectNull) - { - Assert.IsNull(found); - } - else - { - Assert.IsNotNull(found); - } - } - - [Test] - public void BindModel_Null_Source_Returns_Null() - { - var bindingContext = new DefaultModelBindingContext(); - _contentModelBinder.BindModelAsync(bindingContext, null, typeof(MyContent)); - Assert.IsNull(bindingContext.Result.Model); - } - - [Test] - public void BindModel_Returns_If_Same_Type() - { - var content = new MyContent(Mock.Of()); - var bindingContext = new DefaultModelBindingContext(); - - _contentModelBinder.BindModelAsync(bindingContext, content, typeof(MyContent)); - - Assert.AreSame(content, bindingContext.Result.Model); - } - - [Test] - public void BindModel_RenderModel_To_IPublishedContent() - { - var content = new MyContent(Mock.Of()); - var renderModel = new ContentModel(content); - - var bindingContext = new DefaultModelBindingContext(); - _contentModelBinder.BindModelAsync(bindingContext, renderModel, typeof(IPublishedContent)); - - Assert.AreSame(content, bindingContext.Result.Model); - } - - [Test] - public void BindModel_IPublishedContent_To_RenderModel() - { - var content = new MyContent(Mock.Of()); - var bindingContext = new DefaultModelBindingContext(); - - _contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel)); - var bound = (IContentModel) bindingContext.Result.Model; - - Assert.AreSame(content, bound.Content); - } - - [Test] - public void BindModel_IPublishedContent_To_Generic_RenderModel() - { - var content = new MyContent(Mock.Of()); - var bindingContext = new DefaultModelBindingContext(); - - _contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel)); - var bound = (IContentModel) bindingContext.Result.Model; - - Assert.AreSame(content, bound.Content); - } - - [Test] - public void No_DataToken_Returns_Null() - { - var content = new MyContent(Mock.Of()); - var bindingContext = CreateBindingContext(typeof(ContentModel), false, content); - - _contentModelBinder.BindModelAsync(bindingContext); - - Assert.IsNull(bindingContext.Result.Model); - } - - [Test] - public void Invalid_DataToken_Model_Type_Returns_Null() - { - var bindingContext = CreateBindingContext(typeof(IPublishedContent), source: "Hello"); - _contentModelBinder.BindModelAsync(bindingContext); - Assert.IsNull(bindingContext.Result.Model); - } - - [Test] - public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation() - { - var content = new MyContent(Mock.Of()); - var bindingContext = CreateBindingContext(typeof(MyContent), source: content); - - _contentModelBinder.BindModelAsync(bindingContext); - - Assert.AreEqual(content, bindingContext.Result.Model); - } - - private ModelBindingContext CreateBindingContext(Type modelType, bool withUmbracoDataToken = true, object source = null) - { - var httpContext = new DefaultHttpContext(); - var routeData = new RouteData(); - if (withUmbracoDataToken) - routeData.DataTokens.Add(Constants.Web.UmbracoDataToken, source); - - var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); - var metadataProvider = new EmptyModelMetadataProvider(); - var routeValueDictionary = new RouteValueDictionary(); - var valueProvider = new RouteValueProvider(BindingSource.Path, routeValueDictionary); - return new DefaultModelBindingContext - { - ActionContext = actionContext, - ModelMetadata = metadataProvider.GetMetadataForType(modelType), - ModelName = modelType.Name, - ValueProvider = valueProvider, - }; - } - - public class MyCustomContentModel : ContentModel - { - public MyCustomContentModel(IPublishedContent content) - : base(content) - { } - } - - public class MyOtherContent - { - - } - - public class MyContent : PublishedContentWrapped - { - public MyContent(IPublishedContent content) : base(content) - { - } - } - } -} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs index 4b1675b7f0..b106d24ed6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs @@ -1,5 +1,7 @@ -using NUnit.Framework; -using Umbraco.Web; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; using Umbraco.Web.Common.Mvc; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc @@ -10,16 +12,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc private HtmlStringUtilities _htmlStringUtilities; [SetUp] - public virtual void Initialize() - { - - _htmlStringUtilities = new HtmlStringUtilities(); - } + public virtual void Initialize() => _htmlStringUtilities = new HtmlStringUtilities(); [Test] public void TruncateWithElipsis() { - var output = _htmlStringUtilities.Truncate("hello world", 5, true, false).ToString(); + string output = _htmlStringUtilities.Truncate("hello world", 5, true, false).ToString(); var expected = "hello…"; Assert.AreEqual(expected, output); } @@ -27,7 +25,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc [Test] public void TruncateWithoutElipsis() { - var output = _htmlStringUtilities.Truncate("hello world", 5, false, false).ToString(); + string output = _htmlStringUtilities.Truncate("hello world", 5, false, false).ToString(); var expected = "hello"; Assert.AreEqual(expected, output); } @@ -35,7 +33,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc [Test] public void TruncateShorterWordThanHellip() { - //http://issues.umbraco.org/issue/U4-10478 + // http://issues.umbraco.org/issue/U4-10478 var output = _htmlStringUtilities.Truncate("hi", 5, true, false).ToString(); var expected = "hi"; Assert.AreEqual(expected, output); @@ -48,7 +46,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc var expected = "hello…"; Assert.AreEqual(expected, output); } - - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs index 40b7030ba8..e221e88dd1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs @@ -1,4 +1,7 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; @@ -17,7 +20,6 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { - [TestFixture] public class BackOfficeAreaRoutesTests { @@ -27,7 +29,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [TestCase(RuntimeLevel.Boot)] public void RuntimeState_No_Routes(RuntimeLevel level) { - var routes = GetBackOfficeAreaRoutes(level); + BackOfficeAreaRoutes routes = GetBackOfficeAreaRoutes(level); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); @@ -37,12 +39,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [Test] public void RuntimeState_Upgrade() { - var routes = GetBackOfficeAreaRoutes(RuntimeLevel.Upgrade); + BackOfficeAreaRoutes routes = GetBackOfficeAreaRoutes(RuntimeLevel.Upgrade); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(1, endpoints.DataSources.Count); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); Assert.AreEqual(2, route.Endpoints.Count); AssertMinimalBackOfficeRoutes(route); } @@ -50,18 +52,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [Test] public void RuntimeState_Run() { - var routes = GetBackOfficeAreaRoutes(RuntimeLevel.Run); + BackOfficeAreaRoutes routes = GetBackOfficeAreaRoutes(RuntimeLevel.Run); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(1, endpoints.DataSources.Count); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); Assert.AreEqual(3, route.Endpoints.Count); AssertMinimalBackOfficeRoutes(route); var endpoint4 = (RouteEndpoint)route.Endpoints[2]; - var apiControllerName = ControllerExtensions.GetControllerName(); + string apiControllerName = ControllerExtensions.GetControllerName(); Assert.AreEqual($"umbraco/backoffice/api/{apiControllerName.ToLowerInvariant()}/{{action}}/{{id?}}", endpoint4.RoutePattern.RawText); Assert.IsFalse(endpoint4.RoutePattern.Defaults.ContainsKey("area")); Assert.IsFalse(endpoint4.RoutePattern.Defaults.ContainsKey("action")); @@ -78,7 +80,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing Assert.AreEqual(endpoint1.RoutePattern.Defaults["area"], typeof(BackOfficeController).GetCustomAttribute(false).RouteValue); var endpoint2 = (RouteEndpoint)route.Endpoints[1]; - var controllerName = ControllerExtensions.GetControllerName(); + string controllerName = ControllerExtensions.GetControllerName(); Assert.AreEqual($"umbraco/backoffice/{Constants.Web.Mvc.BackOfficeApiArea.ToLowerInvariant()}/{controllerName.ToLowerInvariant()}/{{action}}/{{id?}}", endpoint2.RoutePattern.RawText); Assert.AreEqual(Constants.Web.Mvc.BackOfficeApiArea, endpoint2.RoutePattern.Defaults["area"]); Assert.IsFalse(endpoint2.RoutePattern.Defaults.ContainsKey("action")); @@ -101,7 +103,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [IsBackOffice] private class Testing1Controller : UmbracoApiController { - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/EndpointRouteBuilderExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/EndpointRouteBuilderExtensionsTests.cs index a5b7c6dae3..f5b491a8af 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/EndpointRouteBuilderExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/EndpointRouteBuilderExtensionsTests.cs @@ -1,10 +1,10 @@ -using Microsoft.AspNetCore.Http.Features; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using NUnit.Framework; -using System; -using System.Linq; -using System.Text; using Umbraco.Core; using Umbraco.Extensions; using Umbraco.Web.Common.Routing; @@ -12,7 +12,6 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { - [TestFixture] public class EndpointRouteBuilderExtensionsTests { @@ -37,31 +36,45 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var endpoints = new TestRouteBuilder(); endpoints.MapUmbracoRoute(umbracoPath, area, prefix, defaultAction, includeControllerName); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); var endpoint = (RouteEndpoint)route.Endpoints[0]; - var controllerName = ControllerExtensions.GetControllerName(); - var controllerNamePattern = controllerName.ToLowerInvariant(); + string controllerName = ControllerExtensions.GetControllerName(); + string controllerNamePattern = controllerName.ToLowerInvariant(); if (includeControllerName) { if (prefix.IsNullOrWhiteSpace()) + { Assert.AreEqual($"{umbracoPath}/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } else + { Assert.AreEqual($"{umbracoPath}/{prefix}/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } } else { if (prefix.IsNullOrWhiteSpace()) + { Assert.AreEqual($"{umbracoPath}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } else + { Assert.AreEqual($"{umbracoPath}/{prefix}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } } if (!area.IsNullOrWhiteSpace()) + { Assert.AreEqual(area, endpoint.RoutePattern.Defaults["area"]); + } + if (!defaultAction.IsNullOrWhiteSpace()) - Assert.AreEqual(defaultAction, endpoint.RoutePattern.Defaults["action"]); + { + Assert.AreEqual(defaultAction, endpoint.RoutePattern.Defaults["action"]); + } + Assert.AreEqual(controllerName, endpoint.RoutePattern.Defaults["controller"]); } @@ -78,38 +91,51 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var endpoints = new TestRouteBuilder(); endpoints.MapUmbracoApiRoute(umbracoPath, area, isBackOffice, defaultAction); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); var endpoint = (RouteEndpoint)route.Endpoints[0]; - var controllerName = ControllerExtensions.GetControllerName(); - var controllerNamePattern = controllerName.ToLowerInvariant(); - var areaPattern = area?.ToLowerInvariant(); + string controllerName = ControllerExtensions.GetControllerName(); + string controllerNamePattern = controllerName.ToLowerInvariant(); + string areaPattern = area?.ToLowerInvariant(); if (isBackOffice) { if (area.IsNullOrWhiteSpace()) + { Assert.AreEqual($"{umbracoPath}/backoffice/api/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } else + { Assert.AreEqual($"{umbracoPath}/backoffice/{areaPattern}/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } } else { if (area.IsNullOrWhiteSpace()) + { Assert.AreEqual($"{umbracoPath}/api/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } else + { Assert.AreEqual($"{umbracoPath}/{areaPattern}/{controllerNamePattern}/{{action}}/{{id?}}", endpoint.RoutePattern.RawText); + } } if (!area.IsNullOrWhiteSpace()) + { Assert.AreEqual(area, endpoint.RoutePattern.Defaults["area"]); + } + if (!defaultAction.IsNullOrWhiteSpace()) + { Assert.AreEqual(defaultAction, endpoint.RoutePattern.Defaults["action"]); + } + Assert.AreEqual(controllerName, endpoint.RoutePattern.Defaults["controller"]); } private class Testing1Controller : ControllerBase { - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs index 4035c4d2d0..74671f819a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs @@ -1,8 +1,11 @@ -using Microsoft.AspNetCore.Mvc; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Moq; using NUnit.Framework; -using System.Linq; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Extensions; @@ -18,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [TestCase(RuntimeLevel.Boot)] public void RuntimeState_No_Routes(RuntimeLevel level) { - var routes = GetInstallAreaRoutes(level); + InstallAreaRoutes routes = GetInstallAreaRoutes(level); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); @@ -29,12 +32,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [TestCase(RuntimeLevel.Upgrade)] public void RuntimeState_Install(RuntimeLevel level) { - var routes = GetInstallAreaRoutes(level); + InstallAreaRoutes routes = GetInstallAreaRoutes(level); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(2, endpoints.DataSources.Count); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); Assert.AreEqual(2, route.Endpoints.Count); var endpoint1 = (RouteEndpoint)route.Endpoints[0]; @@ -51,7 +54,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing Assert.AreEqual(ControllerExtensions.GetControllerName(), endpoint2.RoutePattern.Defaults["controller"]); Assert.AreEqual(endpoint2.RoutePattern.Defaults["area"], typeof(InstallController).GetCustomAttribute(false).RouteValue); - var fallbackRoute = endpoints.DataSources.Last(); + EndpointDataSource fallbackRoute = endpoints.DataSources.Last(); Assert.AreEqual(1, fallbackRoute.Endpoints.Count); Assert.AreEqual("Fallback {*path:nonfile}", fallbackRoute.Endpoints[0].ToString()); @@ -60,26 +63,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [Test] public void RuntimeState_Run() { - var routes = GetInstallAreaRoutes(RuntimeLevel.Run); + InstallAreaRoutes routes = GetInstallAreaRoutes(RuntimeLevel.Run); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(1, endpoints.DataSources.Count); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); Assert.AreEqual(1, route.Endpoints.Count); Assert.AreEqual("install/{controller?}/{action?} HTTP: GET", route.Endpoints[0].ToString()); - } - private InstallAreaRoutes GetInstallAreaRoutes(RuntimeLevel level) - { - var routes = new InstallAreaRoutes( + private InstallAreaRoutes GetInstallAreaRoutes(RuntimeLevel level) => + new InstallAreaRoutes( Mock.Of(x => x.Level == level), Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/install" && x.ApplicationVirtualPath == string.Empty), Mock.Of()); - - return routes; - } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs index 1fc6b092c8..32d4f41f8a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs @@ -1,4 +1,7 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; @@ -10,15 +13,10 @@ using Umbraco.Core.Hosting; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Routing; -using Umbraco.Web.BackOffice.SignalR; -using Umbraco.Web.Common.Attributes; -using Umbraco.Web.Common.Controllers; -using Umbraco.Web.WebApi; using Constants = Umbraco.Core.Constants; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { - [TestFixture] public class PreviewRoutesTests { @@ -29,31 +27,29 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing [TestCase(RuntimeLevel.Upgrade)] public void RuntimeState_No_Routes(RuntimeLevel level) { - var routes = GetRoutes(level); + PreviewRoutes routes = GetRoutes(level); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(0, endpoints.DataSources.Count); } - [Test] public void RuntimeState_Run() { - var routes = GetRoutes(RuntimeLevel.Run); + PreviewRoutes routes = GetRoutes(RuntimeLevel.Run); var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); Assert.AreEqual(2, endpoints.DataSources.Count); - var route = endpoints.DataSources.First(); + EndpointDataSource route = endpoints.DataSources.First(); Assert.AreEqual(2, route.Endpoints.Count); - var endpoint0 = (RouteEndpoint) route.Endpoints[0]; + var endpoint0 = (RouteEndpoint)route.Endpoints[0]; Assert.AreEqual($"{routes.GetPreviewHubRoute()}/negotiate", endpoint0.RoutePattern.RawText); - var endpoint1 = (RouteEndpoint) route.Endpoints[1]; + var endpoint1 = (RouteEndpoint)route.Endpoints[1]; Assert.AreEqual($"{routes.GetPreviewHubRoute()}", endpoint1.RoutePattern.RawText); - var endpoint3 = (RouteEndpoint)endpoints.DataSources.Last().Endpoints[0]; var previewControllerName = ControllerExtensions.GetControllerName(); Assert.AreEqual($"umbraco/{previewControllerName.ToLowerInvariant()}/{{action}}/{{id?}}", endpoint3.RoutePattern.RawText); @@ -61,9 +57,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing Assert.AreEqual("Index", endpoint3.RoutePattern.Defaults["action"]); Assert.AreEqual(previewControllerName, endpoint3.RoutePattern.Defaults["controller"]); Assert.AreEqual(endpoint3.RoutePattern.Defaults["area"], typeof(PreviewController).GetCustomAttribute(false).RouteValue); - - } + private PreviewRoutes GetRoutes(RuntimeLevel level) { var globalSettings = new GlobalSettings(); @@ -72,7 +67,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), Mock.Of(x => x.Level == level)); - return routes; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs index de21bc5129..c35c1a1d9e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs @@ -1,15 +1,16 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.Internal; using Microsoft.Extensions.Logging; +using Moq; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { @@ -37,6 +38,5 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing mock.Setup(x => x.Build()).Returns(httpContext => Task.CompletedTask); return mock.Object; } - } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs index db80e2cd74..0e54676f10 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs @@ -1,8 +1,9 @@ -using System.Collections.Generic; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; using Microsoft.AspNetCore.DataProtection; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web; using Umbraco.Web.Common.Security; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Security @@ -10,7 +11,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Security [TestFixture] public class EncryptionHelperTests { - private IDataProtectionProvider DataProtectionProvider { get; } = new EphemeralDataProtectionProvider(); [Test] @@ -28,9 +28,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Security DataProtectionProvider, "FormController", "FormAction", - "", - additionalRouteValues - ); + string.Empty, + additionalRouteValues); var result = EncryptionHelper.Decrypt(encryptedRouteString, DataProtectionProvider); @@ -44,19 +43,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Security { var additionalRouteValues = new Dictionary() { - {"key1", "value1"}, - {"key2", "value2"}, - {"Key3", "Value3"}, - {"keY4", "valuE4"} + { "key1", "value1" }, + { "key2", "value2" }, + { "Key3", "Value3" }, + { "keY4", "valuE4" } }; var encryptedRouteString = EncryptionHelper.CreateEncryptedRouteString( DataProtectionProvider, "FormController", "FormAction", - "", - additionalRouteValues - ); + string.Empty, + additionalRouteValues); var result = EncryptionHelper.Decrypt(encryptedRouteString, DataProtectionProvider); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs index 3b52d0701e..90f491b15f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs @@ -1,6 +1,10 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using NUnit.Framework; using Umbraco.Core.Models.PublishedContent; @@ -13,14 +17,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views [TestFixture] public class UmbracoViewPageTests { - #region RenderModel To ... [Test] public void RenderModel_To_RenderModel() { var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelTestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); view.ViewData = viewData; Assert.AreSame(model, view.Model); @@ -31,7 +34,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views { var content = new ContentType1(null); var view = new ContentType1TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); view.ViewData = viewData; @@ -44,7 +47,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType2(null); var view = new ContentType1TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); view.ViewData = viewData; Assert.IsInstanceOf(view.Model); @@ -56,9 +59,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType1(null); var model = new ContentModel(content); var view = new ContentType2TestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } [Test] @@ -67,7 +70,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary>(model); + ViewDataDictionary> viewData = GetViewDataDictionary>(model); view.ViewData = viewData; @@ -81,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType2(null); var model = new ContentModel(content); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary>(model); + ViewDataDictionary> viewData = GetViewDataDictionary>(model); view.ViewData = viewData; Assert.IsInstanceOf>(view.Model); @@ -94,22 +97,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelOfContentType2TestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } - #endregion - - #region RenderModelOf To ... - [Test] public void RenderModelOf_ContentType1_To_RenderModel() { var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelTestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); view.ViewData = viewData; @@ -117,44 +116,43 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views } [Test] - public async Task RenderModelOf_ContentType1_To_ContentType1() + public void RenderModelOf_ContentType1_To_ContentType1() { var content = new ContentType1(null); var model = new ContentModel(content); var view = new ContentType1TestPage(); - var viewData = GetViewDataDictionary>(model); + ViewDataDictionary> viewData = GetViewDataDictionary>(model); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf(view.Model); } [Test] - public async Task RenderModelOf_ContentType2_To_ContentType1() + public void RenderModelOf_ContentType2_To_ContentType1() { var content = new ContentType2(null); var model = new ContentModel(content); var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { - Model = model + Model = model }; - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf(view.Model); } [Test] - public async Task RenderModelOf_ContentType1_To_ContentType2() + public void RenderModelOf_ContentType1_To_ContentType2() { - var content = new ContentType1(null); var model = new ContentModel(content); var view = new ContentType2TestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } [Test] @@ -163,7 +161,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary>(model); + ViewDataDictionary> viewData = GetViewDataDictionary>(model); view.ViewData = viewData; @@ -172,14 +170,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views } [Test] - public async Task RenderModelOf_ContentType2_To_RenderModelOf_ContentType1() + public void RenderModelOf_ContentType2_To_RenderModelOf_ContentType1() { var content = new ContentType2(null); var model = new ContentModel(content); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary>(model); + ViewDataDictionary> viewData = GetViewDataDictionary>(model); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf>(view.Model); Assert.IsInstanceOf(view.Model.Content); @@ -191,50 +189,46 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views var content = new ContentType1(null); var model = new ContentModel(content); var view = new RenderModelOfContentType2TestPage(); - var viewData = GetViewDataDictionary(model); + ViewDataDictionary viewData = GetViewDataDictionary(model); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } - #endregion - - #region ContentType To ... - [Test] - public async Task ContentType1_To_RenderModel() + public void ContentType1_To_RenderModel() { var content = new ContentType1(null); var view = new RenderModelTestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf(view.Model); } [Test] - public async Task ContentType1_To_RenderModelOf_ContentType1() + public void ContentType1_To_RenderModelOf_ContentType1() { var content = new ContentType1(null); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary(content); - await view.SetViewDataAsyncX(viewData); + ViewDataDictionary viewData = GetViewDataDictionary(content); + view.SetViewData(viewData); Assert.IsInstanceOf>(view.Model); Assert.IsInstanceOf(view.Model.Content); } [Test] - public async Task ContentType2_To_RenderModelOf_ContentType1() + public void ContentType2_To_RenderModelOf_ContentType1() { // Same as above but with ContentModel var content = new ContentType2(null); var view = new RenderModelOfContentType1TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf>(view.Model); Assert.IsInstanceOf(view.Model.Content); @@ -245,19 +239,19 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views { var content = new ContentType1(null); var view = new RenderModelOfContentType2TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } [Test] - public async Task ContentType1_To_ContentType1() + public void ContentType1_To_ContentType1() { var content = new ContentType1(null); var view = new ContentType1TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf(view.Model); } @@ -267,27 +261,23 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views { var content = new ContentType1(null); var view = new ContentType2TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + Assert.Throws(() => view.SetViewData(viewData)); } [Test] - public async Task ContentType2_To_ContentType1() + public void ContentType2_To_ContentType1() { var content = new ContentType2(null); var view = new ContentType1TestPage(); - var viewData = GetViewDataDictionary(content); + ViewDataDictionary viewData = GetViewDataDictionary(content); - await view.SetViewDataAsyncX(viewData); + view.SetViewData(viewData); Assert.IsInstanceOf(view.Model); } - #endregion - - #region Test helpers methods - private ViewDataDictionary GetViewDataDictionary(object model) { var sourceViewDataDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()); @@ -303,48 +293,47 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views }; } - #endregion - - #region Test elements - public class ContentType1 : PublishedContentWrapped { - public ContentType1(IPublishedContent content) : base(content) {} + public ContentType1(IPublishedContent content) + : base(content) + { + } } public class ContentType2 : ContentType1 { - public ContentType2(IPublishedContent content) : base(content) { } + public ContentType2(IPublishedContent content) + : base(content) + { + } } public class TestPage : UmbracoViewPage { - public override Task ExecuteAsync() - { - throw new NotImplementedException(); - } + public override Task ExecuteAsync() => throw new NotImplementedException(); - public async Task SetViewDataAsyncX(ViewDataDictionary viewData) - { - await SetViewDataAsync(viewData); - } + public void SetViewData(ViewDataDictionary viewData) => ViewData = (ViewDataDictionary)BindViewData(viewData); } public class RenderModelTestPage : TestPage - { } + { + } public class ContentType1TestPage : TestPage - { } + { + } public class ContentType2TestPage : TestPage - { } + { + } public class RenderModelOfContentType1TestPage : TestPage> - { } + { + } public class RenderModelOfContentType2TestPage : TestPage> - { } - - #endregion + { + } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs index 1e579cc7dd..8ecd05367a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs @@ -1,11 +1,9 @@ -using System; -using AutoFixture.NUnit3; -using Moq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NUnit.Framework; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.AutoFixture; using Umbraco.Web.Common.AspNetCore; @@ -14,20 +12,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website [TestFixture] public class AspNetCoreHostingEnvironmentTests { - [InlineAutoMoqData("~/Scripts", "/Scripts", null)] [InlineAutoMoqData("/Scripts", "/Scripts", null)] [InlineAutoMoqData("../Scripts", "/Scripts", typeof(InvalidOperationException))] public void IOHelper_ResolveUrl(string input, string expected, Type expectedExceptionType, AspNetCoreHostingEnvironment sut) { - if (expectedExceptionType != null) { - Assert.Throws(expectedExceptionType, () =>sut.ToAbsolute(input)); + Assert.Throws(expectedExceptionType, () => sut.ToAbsolute(input)); } else { - var result = sut.ToAbsolute(input); Assert.AreEqual(expected, result); } @@ -36,7 +31,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website [Test] public void EnsurePathIsApplicationRootPrefixed() { - //Assert + // Assert Assert.AreEqual("~/Views/Template.cshtml", PathUtility.EnsurePathIsApplicationRootPrefixed("Views/Template.cshtml")); Assert.AreEqual("~/Views/Template.cshtml", PathUtility.EnsurePathIsApplicationRootPrefixed("/Views/Template.cshtml")); Assert.AreEqual("~/Views/Template.cshtml", PathUtility.EnsurePathIsApplicationRootPrefixed("~/Views/Template.cshtml")); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs deleted file mode 100644 index 3a987fb038..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; - -namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers -{ - [TestFixture] - public class RenderIndexActionSelectorAttributeTests - { - [Test] - public void IsValidForRequest__ensure_caching_works() - { - var sut = new RenderIndexActionSelectorAttribute(); - - var actionDescriptor = - GetRenderMvcControllerIndexMethodFromCurrentType(typeof(MatchesDefaultIndexController)).First(); - var actionDescriptorCollectionProviderMock = new Mock(); - actionDescriptorCollectionProviderMock.Setup(x => x.ActionDescriptors) - .Returns(new ActionDescriptorCollection(Array.Empty(), 1)); - - var routeContext = CreateRouteContext(actionDescriptorCollectionProviderMock.Object); - - // Call the method multiple times - for (var i = 0; i < 1; i++) - { - sut.IsValidForRequest(routeContext, actionDescriptor); - } - - //Ensure the underlying ActionDescriptors is only called once. - actionDescriptorCollectionProviderMock.Verify(x=>x.ActionDescriptors, Times.Once); - } - - [Test] - [TestCase(typeof(MatchesDefaultIndexController), - "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] - [TestCase(typeof(MatchesOverriddenIndexController), - "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] - [TestCase(typeof(MatchesCustomIndexController), - "Index", new[] { typeof(ContentModel), typeof(int) }, typeof(IActionResult), ExpectedResult = false)] - [TestCase(typeof(MatchesAsyncIndexController), - "Index", new[] { typeof(ContentModel) }, typeof(Task), ExpectedResult = false)] - public bool IsValidForRequest__must_return_the_expected_result(Type controllerType, string actionName, Type[] parameterTypes, Type returnType) - { - //Fake all IActionDescriptor's that will be returned by IActionDescriptorCollectionProvider - var actionDescriptors = GetRenderMvcControllerIndexMethodFromCurrentType(controllerType); - - // Find the one that match the current request - var actualActionDescriptor = actionDescriptors.Single(x => x.ActionName == actionName - && x.ControllerTypeInfo.Name == controllerType.Name - && x.MethodInfo.ReturnType == returnType - && x.MethodInfo.GetParameters().Select(m => m.ParameterType).SequenceEqual(parameterTypes)); - - //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext - var sut = new RenderIndexActionSelectorAttribute(); - - var routeContext = CreateRouteContext(new TestActionDescriptorCollectionProvider(actionDescriptors)); - - //Act - var result = sut.IsValidForRequest(routeContext, actualActionDescriptor); - return result; - } - - private ControllerActionDescriptor[] GetRenderMvcControllerIndexMethodFromCurrentType(Type controllerType) - { - var actions = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance) - .Where(m => !m.IsSpecialName - && m.GetCustomAttribute() is null - && m.Module.Name.Contains("Umbraco")); - - var actionDescriptors = actions - .Select(x => new ControllerActionDescriptor() - { - ControllerTypeInfo = controllerType.GetTypeInfo(), - ActionName = x.Name, - MethodInfo = x - }).ToArray(); - - return actionDescriptors; - } - - private static RouteContext CreateRouteContext(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) - { - //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext - var httpContext = new DefaultHttpContext(); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(actionDescriptorCollectionProvider); - httpContext.RequestServices = - new DefaultServiceProviderFactory(new ServiceProviderOptions()) - .CreateServiceProvider(serviceCollection); - - // Put the fake httpcontext on the route context. - var routeContext = new RouteContext(httpContext); - return routeContext; - } - - private class TestActionDescriptorCollectionProvider : IActionDescriptorCollectionProvider - { - public TestActionDescriptorCollectionProvider(IReadOnlyList items) - { - ActionDescriptors = new ActionDescriptorCollection(items, 1); - } - - public ActionDescriptorCollection ActionDescriptors { get; } - } - - private class MatchesDefaultIndexController : RenderMvcController - { - public MatchesDefaultIndexController(ILogger logger, - ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) - { - } - } - - private class MatchesOverriddenIndexController : RenderMvcController - { - public override IActionResult Index(ContentModel model) - { - return base.Index(model); - } - - public MatchesOverriddenIndexController(ILogger logger, - ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) - { - } - } - - private class MatchesCustomIndexController : RenderMvcController - { - public IActionResult Index(ContentModel model, int page) - { - return base.Index(model); - } - - public MatchesCustomIndexController(ILogger logger, - ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) - { - } - } - - private class MatchesAsyncIndexController : RenderMvcController - { - public new async Task Index(ContentModel model) - { - return await Task.FromResult(base.Index(model)); - } - - public MatchesAsyncIndexController(ILogger logger, - ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) - { - } - } - } -} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderNoContentControllerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderNoContentControllerTests.cs index 182fb94a40..9320c87949 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderNoContentControllerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderNoContentControllerTests.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Mvc; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; @@ -17,7 +20,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers [Test] public void Redirects_To_Root_When_Content_Published() { - var mockUmbracoContext = new Mock(); mockUmbracoContext.Setup(x => x.Content.HasContent()).Returns(true); var mockIOHelper = new Mock(); @@ -40,7 +42,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers var mockIOHelper = new Mock(); mockIOHelper.Setup(x => x.ResolveUrl(It.Is(y => y == UmbracoPathSetting))).Returns(UmbracoPath); - var globalSettings = Options.Create(new GlobalSettings() + IOptions globalSettings = Options.Create(new GlobalSettings() { UmbracoPath = UmbracoPathSetting, NoNodesViewPath = ViewPath, diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs index 82bd6719d4..31603eb8c0 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -14,11 +17,12 @@ using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.Testing; using Umbraco.Web; +using Umbraco.Web.Common.Routing; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Web.Security; using Umbraco.Web.Website; using Umbraco.Web.Website.Controllers; +using Umbraco.Web.Website.Routing; using CoreConstants = Umbraco.Core.Constants; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers @@ -30,16 +34,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers private IUmbracoContextAccessor _umbracoContextAccessor; [SetUp] - public void SetUp() - { - _umbracoContextAccessor = new TestUmbracoContextAccessor(); - } + public void SetUp() => _umbracoContextAccessor = new TestUmbracoContextAccessor(); [Test] public void Can_Construct_And_Get_Result() { - var hostingEnvironment = Mock.Of(); - var backofficeSecurityAccessor = Mock.Of(); + IHostingEnvironment hostingEnvironment = Mock.Of(); + IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of()); var globalSettings = new GlobalSettings(); @@ -55,14 +56,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Mock.Of(), backofficeSecurityAccessor); - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbracoContext = umbracoContextReference.UmbracoContext; + UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); + IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of(), Mock.Of()); - var result = ctrl.Index(); + IActionResult result = ctrl.Index(); Assert.IsNotNull(result); } @@ -71,8 +72,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers public void Umbraco_Context_Not_Null() { var globalSettings = new GlobalSettings(); - var hostingEnvironment = Mock.Of(); - var backofficeSecurityAccessor = Mock.Of(); + IHostingEnvironment hostingEnvironment = Mock.Of(); + IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, @@ -86,8 +87,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Mock.Of(), backofficeSecurityAccessor); - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; + UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); + IUmbracoContext umbCtx = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); @@ -103,10 +104,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); var content = new Mock(); content.Setup(x => x.Id).Returns(2); - var backofficeSecurityAccessor = Mock.Of(); + IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of()); var publishedSnapshotService = new Mock(); - var hostingEnvironment = Mock.Of(); + IHostingEnvironment hostingEnvironment = Mock.Of(); var globalSettings = new GlobalSettings(); var umbracoContextFactory = new UmbracoContextFactory( @@ -121,12 +122,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Mock.Of(), backofficeSecurityAccessor); - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbracoContext = umbracoContextReference.UmbracoContext; + UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); + IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var publishedContentQuery = Mock.Of(query => query.Content(2) == content.Object); + IPublishedContentQuery publishedContentQuery = Mock.Of(query => query.Content(2) == content.Object); var ctrl = new TestSurfaceController(umbracoContextAccessor, publishedContentQuery, Mock.Of()); var result = ctrl.GetContent(2) as PublishedContentResult; @@ -136,13 +137,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Assert.AreEqual(2, result.Content.Id); } - [Test] public void Mock_Current_Page() { var globalSettings = new GlobalSettings(); - var hostingEnvironment = Mock.Of(); - var backofficeSecurityAccessor = Mock.Of(); + IHostingEnvironment hostingEnvironment = Mock.Of(); + IBackOfficeSecurityAccessor backofficeSecurityAccessor = Mock.Of(); Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, @@ -156,29 +156,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Mock.Of(), backofficeSecurityAccessor); - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbracoContext = umbracoContextReference.UmbracoContext; + UmbracoContextReference umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); + IUmbracoContext umbracoContext = umbracoContextReference.UmbracoContext; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var content = Mock.Of(publishedContent => publishedContent.Id == 12345); + IPublishedContent content = Mock.Of(publishedContent => publishedContent.Id == 12345); - var publishedRequestMock = new Mock(); - publishedRequestMock.Setup(x => x.PublishedContent).Returns(content); - - var routeDefinition = new RouteDefinition - { - PublishedRequest = publishedRequestMock.Object - }; + var routeDefinition = new UmbracoRouteValues(content); var routeData = new RouteData(); - routeData.DataTokens.Add(CoreConstants.Web.UmbracoRouteDefinitionDataToken, routeDefinition); + routeData.Values.Add(CoreConstants.Web.UmbracoRouteDefinitionDataToken, routeDefinition); - var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of(), Mock.Of()); - ctrl.ControllerContext = new ControllerContext() + var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of(), Mock.Of()) { - HttpContext = Mock.Of(), - RouteData = routeData + ControllerContext = new ControllerContext() + { + HttpContext = Mock.Of(), + RouteData = routeData + } }; var result = ctrl.GetContentFromCurrentPage() as PublishedContentResult; @@ -186,33 +182,29 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers Assert.AreEqual(12345, result.Content.Id); } - public class TestSurfaceController : SurfaceController { private readonly IPublishedContentQuery _publishedContentQuery; public TestSurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IPublishedContentQuery publishedContentQuery, IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null, publishedUrlProvider) - { + : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null, publishedUrlProvider) => _publishedContentQuery = publishedContentQuery; - } - public IActionResult Index() - { + public IActionResult Index() => + // ReSharper disable once Mvc.ViewNotResolved - return View(); - } + View(); public IActionResult GetContent(int id) { - var content = _publishedContentQuery.Content(id); + IPublishedContent content = _publishedContentQuery.Content(id); return new PublishedContentResult(content); } public IActionResult GetContentFromCurrentPage() { - var content = CurrentPage; + IPublishedContent content = CurrentPage; return new PublishedContentResult(content); } @@ -222,15 +214,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers { public IPublishedContent Content { get; set; } - public PublishedContentResult(IPublishedContent content) - { - Content = content; - } + public PublishedContentResult(IPublishedContent content) => Content = content; - public Task ExecuteResultAsync(ActionContext context) - { - return Task.CompletedTask; - } + public Task ExecuteResultAsync(ActionContext context) => Task.CompletedTask; } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs index d021d38c15..50ff362cdc 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs @@ -1,4 +1,7 @@ -using System.Linq; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Linq; using System.Security.Claims; using System.Security.Principal; using Microsoft.AspNetCore.Http; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/ViewEngines/ProfilingViewEngineWrapperMvcViewOptionsSetupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/ViewEngines/ProfilingViewEngineWrapperMvcViewOptionsSetupTests.cs index a74431b705..ba791dd8f2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/ViewEngines/ProfilingViewEngineWrapperMvcViewOptionsSetupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/ViewEngines/ProfilingViewEngineWrapperMvcViewOptionsSetupTests.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Mvc; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.AspNetCore.Mvc; using Moq; using NUnit.Framework; using Umbraco.Core.Logging; @@ -11,6 +14,7 @@ namespace Umbraco.Tests.Runtimes { private ProfilingViewEngineWrapperMvcViewOptionsSetup Sut => new ProfilingViewEngineWrapperMvcViewOptionsSetup(Mock.Of()); + [Test] public void WrapViewEngines_HasEngines_WrapsAll() { @@ -67,9 +71,6 @@ namespace Umbraco.Tests.Runtimes } [Test] - public void WrapViewEngines_CollectionIsNull_DoesNotThrow() - { - Assert.DoesNotThrow(() => Sut.Configure(new MvcViewOptions())); - } + public void WrapViewEngines_CollectionIsNull_DoesNotThrow() => Assert.DoesNotThrow(() => Sut.Configure(new MvcViewOptions())); } } diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index 1800abc8a8..f18aacf18b 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using System; using System.Linq; using System.Threading; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs index 2bc89e0842..1b65d6c70e 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs @@ -1,14 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Models; -using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Runtime; @@ -25,7 +22,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache /// /// Implements a published snapshot service. /// - internal class XmlPublishedSnapshotService : PublishedSnapshotServiceBase + internal class XmlPublishedSnapshotService : IPublishedSnapshotService { private readonly XmlStore _xmlStore; private readonly RoutesCache _routesCache; @@ -48,13 +45,17 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache #region Constructors // used in WebBootManager + tests - public XmlPublishedSnapshotService(ServiceContext serviceContext, + public XmlPublishedSnapshotService( + ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, IAppCache requestCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, - IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, + IDocumentRepository documentRepository, + IMediaRepository mediaRepository, + IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILoggerFactory loggerFactory, GlobalSettings globalSettings, @@ -63,9 +64,9 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IShortStringHelper shortStringHelper, ISiteDomainHelper siteDomainHelper, IEntityXmlSerializer entitySerializer, - MainDom mainDom, - bool testing = false, bool enableRepositoryEvents = true) + bool testing = false, + bool enableRepositoryEvents = true) : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor, documentRepository, mediaRepository, memberRepository, @@ -76,13 +77,17 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache } // used in some tests - internal XmlPublishedSnapshotService(ServiceContext serviceContext, + internal XmlPublishedSnapshotService( + ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IScopeProvider scopeProvider, IAppCache requestCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, - IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, + IDocumentRepository documentRepository, + IMediaRepository mediaRepository, + IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILoggerFactory loggerFactory, GlobalSettings globalSettings, @@ -93,8 +98,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IEntityXmlSerializer entitySerializer, PublishedContentTypeCache contentTypeCache, MainDom mainDom, - bool testing, bool enableRepositoryEvents) - : base(publishedSnapshotAccessor, variationContextAccessor) + bool testing, + bool enableRepositoryEvents) { _routesCache = new RoutesCache(); _publishedContentTypeFactory = publishedContentTypeFactory; @@ -120,38 +125,14 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _hostingLifetime = hostingLifetime; } - public override void Dispose() + public void Dispose() { _xmlStore.Dispose(); } #endregion - #region Environment - - public override bool EnsureEnvironment(out IEnumerable errors) - { - // Test creating/saving/deleting a file in the same location as the content xml file - // NOTE: We cannot modify the xml file directly because a background thread is responsible for - // that and we might get lock issues. - try - { - XmlStore.EnsureFilePermission(); - errors = Enumerable.Empty(); - return true; - } - catch - { - errors = new[] { SystemFiles.GetContentCacheXml(_hostingEnvironment) }; - return false; - } - } - - #endregion - - #region Caches - - public override IPublishedSnapshot CreatePublishedSnapshot(string previewToken) + public IPublishedSnapshot CreatePublishedSnapshot(string previewToken) { // use _requestCache to store recursive properties lookup, etc. both in content // and media cache. Life span should be the current request. Or, ideally @@ -161,40 +142,12 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache var domainCache = new DomainCache(_domainService, _defaultCultureAccessor); return new PublishedSnapshot( - new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _contentTypeCache, _routesCache,_variationContextAccessor, previewToken), + new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _contentTypeCache, _routesCache, _variationContextAccessor, previewToken), new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer, _umbracoContextAccessor, _variationContextAccessor), new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache, _userService, _variationContextAccessor), domainCache); } - #endregion - - #region Preview - - public override string EnterPreview(IUser user, int contentId) - { - var previewContent = new PreviewContent(_xmlStore, user.Id); - previewContent.CreatePreviewSet(contentId, true); // preview branch below that content - return previewContent.Token; - //previewContent.ActivatePreviewCookie(); - } - - public override void RefreshPreview(string previewToken, int contentId) - { - if (previewToken.IsNullOrWhiteSpace()) return; - var previewContent = new PreviewContent(_xmlStore, previewToken); - previewContent.CreatePreviewSet(contentId, true); // preview branch below that content - } - - public override void ExitPreview(string previewToken) - { - if (previewToken.IsNullOrWhiteSpace()) return; - var previewContent = new PreviewContent(_xmlStore, previewToken); - previewContent.ClearPreviewSet(); - } - - #endregion - #region Xml specific /// @@ -241,12 +194,12 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache #region Change management - public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) + public void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) { _xmlStore.Notify(payloads, out draftChanged, out publishedChanged); } - public override void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) + public void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) { foreach (var payload in payloads) PublishedMediaCache.ClearCache(payload.Id); @@ -254,29 +207,28 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache anythingChanged = true; } - public override void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) + public void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) { _xmlStore.Notify(payloads); if (payloads.Any(x => x.ItemType == typeof(IContentType).Name)) _routesCache.Clear(); } - public override void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) + public void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) { _publishedContentTypeFactory.NotifyDataTypeChanges(payloads.Select(x => x.Id).ToArray()); _xmlStore.Notify(payloads); } - public override void Notify(DomainCacheRefresher.JsonPayload[] payloads) + public void Notify(DomainCacheRefresher.JsonPayload[] payloads) { _routesCache.Clear(); } #endregion - public override string GetStatus() - { - return "Test status"; - } + public void Rebuild(int groupSize = 5000, IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) { } + + public Task CollectAsync() => Task.CompletedTask; } } diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs index 41705c7774..420ddbe952 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs @@ -4,11 +4,11 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using System.Xml; using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Models; @@ -28,7 +28,6 @@ using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; using Umbraco.Web.Scheduling; using File = System.IO.File; -using Task = System.Threading.Tasks.Task; namespace Umbraco.Tests.LegacyXmlPublishedCache { @@ -761,7 +760,7 @@ AND (umbracoNode.id=@id)"; // The indenting resumes once the mixed content element is closed." - says MSDN // about XmlWriterSettings.Indent - // so ImportContent must also make sure of ignoring whitespaces! + // so ImportContentBase must also make sure of ignoring whitespaces! var sb = new StringBuilder(); using (var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 92fd58d23c..20c86d127f 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -8,7 +8,6 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -36,7 +35,7 @@ namespace Umbraco.Tests.Models var contentSettings = new ContentSettings(); var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, loggerFactory.CreateLogger(), ShortStringHelper); - var ignored = new FileUploadPropertyEditor(loggerFactory, mediaFileSystem, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties); + var ignored = new FileUploadPropertyEditor(loggerFactory, mediaFileSystem, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer); var media = MockedMedia.CreateMediaImage(mediaType, -1); media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests diff --git a/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.umb b/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.umb deleted file mode 100644 index 18449bd373..0000000000 Binary files a/src/Umbraco.Tests/Packaging/Packages/Document_Type_Picker_1.1.umb and /dev/null differ diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index a17eb71ab0..cc3325377e 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -1,15 +1,12 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Hosting; @@ -19,20 +16,21 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; +using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; using Umbraco.Web.Cache; +using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; -using Current = Umbraco.Web.Composing.Current; -using Umbraco.Core.Serialization; -using Umbraco.Net; +using Umbraco.Infrastructure.PublishedCache.Persistence; namespace Umbraco.Tests.PublishedContent { @@ -70,7 +68,7 @@ namespace Umbraco.Tests.PublishedContent var serializer = new ConfigurationEditorJsonSerializer(); // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 3 }; var dataTypes = new[] { @@ -148,11 +146,9 @@ namespace Umbraco.Tests.PublishedContent // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - var lifetime = new Mock(); - _snapshotService = new PublishedSnapshotService(options, + _snapshotService = new PublishedSnapshotService( + options, null, - lifetime.Object, - runtime, serviceContext, contentTypeFactory, _snapshotAccessor, @@ -160,23 +156,16 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), NullLoggerFactory.Instance, scopeProvider.Object, - Mock.Of(), - Mock.Of(), - Mock.Of(), - new TestDefaultCultureAccessor(), _source, + new TestDefaultCultureAccessor(), Options.Create(globalSettings), Mock.Of(), PublishedModelFactory, - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), hostingEnvironment, - Mock.Of(), - TestHelper.IOHelper, Options.Create(nuCacheSettings)); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); - lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); Mock.Get(factory).Setup(x => x.GetService(typeof(IVariationContextAccessor))).Returns(_variationAccesor); } diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index d689215081..b56c0047ed 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -1,14 +1,11 @@ -using System; +using System; using System.Collections.Generic; using System.Data; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Logging; @@ -27,10 +24,10 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; using Umbraco.Web.Cache; +using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.PublishedContent { @@ -120,7 +117,7 @@ namespace Umbraco.Tests.PublishedContent var serializer = new ConfigurationEditorJsonSerializer(); // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 3 }; var dataTypes = new[] { @@ -189,11 +186,9 @@ namespace Umbraco.Tests.PublishedContent // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - var lifetime = new Mock(); - _snapshotService = new PublishedSnapshotService(options, + _snapshotService = new PublishedSnapshotService( + options, null, - lifetime.Object, - runtime, serviceContext, contentTypeFactory, new TestPublishedSnapshotAccessor(), @@ -201,22 +196,14 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), NullLoggerFactory.Instance, scopeProvider, - Mock.Of(), - Mock.Of(), - Mock.Of(), - new TestDefaultCultureAccessor(), dataSource, + new TestDefaultCultureAccessor(), Microsoft.Extensions.Options.Options.Create(globalSettings), Mock.Of(), publishedModelFactory, - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), TestHelper.GetHostingEnvironment(), - Mock.Of(), - TestHelper.IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); - lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); - // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 37cc8911b1..7cc5bae403 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -5,8 +5,6 @@ using System.Linq; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; -using Umbraco.Web.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -14,9 +12,7 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; using Umbraco.Web; -using PublishedContentExtensions = Umbraco.Web.PublishedContentExtensions; namespace Umbraco.Tests.PublishedContent { @@ -130,7 +126,7 @@ namespace Umbraco.Tests.PublishedContent { var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var contentTypeAlias = createChildren ? "Parent" : "Child"; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index edcd199463..7392537e39 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -6,6 +6,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 75983ba41a..3387f424dd 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -6,24 +6,23 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; -using Umbraco.Core; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; using Umbraco.Tests.Common; -using Umbraco.Core.Security; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web; +using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.PublishedContent { @@ -90,7 +89,7 @@ namespace Umbraco.Tests.PublishedContent { var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var caches = new SolidPublishedSnapshot(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index b55609858b..ec8e55e2bf 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -1,25 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Umbraco.Core; +using Moq; +using Umbraco.Core.IO; +using Umbraco.Core.Media; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; -using Umbraco.Tests.TestHelpers; -using Moq; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Web.PropertyEditors; -using Umbraco.Core.Services; -using Umbraco.Web; -using Umbraco.Web.Templates; -using Umbraco.Web.Routing; -using Umbraco.Core.Media; -using System; -using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Security; using Umbraco.Core.Serialization; +using Umbraco.Core.Services; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web; +using Umbraco.Web.PropertyEditors; +using Umbraco.Web.Routing; +using Umbraco.Web.Templates; namespace Umbraco.Tests.PublishedContent { @@ -38,7 +36,7 @@ namespace Umbraco.Tests.PublishedContent Builder.WithCollectionBuilder() .Clear() .Append() - .Append() + .Append() .Append(); } @@ -67,7 +65,8 @@ namespace Umbraco.Tests.PublishedContent ShortStringHelper, IOHelper, LocalizedTextService, - Mock.Of()), + Mock.Of(), + new JsonNetSerializer()), serializer) { Id = 1 }); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 2170da2f75..af0dab8e14 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -5,31 +5,32 @@ using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PropertyEditors; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; -using Moq; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Media; using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; +using Umbraco.Web; +using Umbraco.Web.Composing; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.PropertyEditors; -using Umbraco.Web.Templates; +using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Current = Umbraco.Web.Composing.Current; -using Umbraco.Core.Media; -using Umbraco.Core.Security; -using Umbraco.Core.Serialization; +using Umbraco.Web.Templates; namespace Umbraco.Tests.PublishedContent { @@ -64,12 +65,12 @@ namespace Umbraco.Tests.PublishedContent var localizationService = Mock.Of(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper), serializer) { Id = 1 }, - new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(loggerFactory,backOfficeSecurityAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of()), serializer) { Id = 1002 }, - new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService), serializer) { Id = 1003 }, - new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1004 }, - new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1005 }); + new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper, JsonNetSerializer), serializer) { Id = 1 }, + new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService, JsonNetSerializer), serializer) { Id = 1001 }, + new DataType(new RichTextPropertyEditor(loggerFactory,backOfficeSecurityAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of(), JsonNetSerializer), serializer) { Id = 1002 }, + new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService, JsonNetSerializer), serializer) { Id = 1003 }, + new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService, JsonNetSerializer), serializer) { Id = 1004 }, + new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService, JsonNetSerializer), serializer) { Id = 1005 }); Builder.Services.AddUnique(f => dataTypeService); } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 9262c72dfa..912d1e4995 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -25,6 +25,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.Common; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index 6bdca6f0f6..58b6ea7c4d 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -5,13 +5,13 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.PublishedContent @@ -415,7 +415,7 @@ namespace Umbraco.Tests.PublishedContent var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of()), serializer) + Mock.Of(), Mock.Of(), Mock.Of(), new JsonNetSerializer()), serializer) { Id = 666 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs index 84d0ea17f6..047b7205bf 100644 --- a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs @@ -39,8 +39,8 @@ namespace Umbraco.Tests.Routing var dataTypeService = Mock.Of(); var propertyEditors = new MediaUrlGeneratorCollection(new IMediaUrlGenerator[] { - new FileUploadPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties), - new ImageCropperPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, UploadAutoFillProperties), + new FileUploadPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer), + new ImageCropperPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, UploadAutoFillProperties, JsonNetSerializer), }); _mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors, UriUtility); } diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 9332dc894a..a8d017e3cb 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -26,6 +26,7 @@ using Umbraco.Web.Mvc; using Umbraco.Web.Runtime; using Umbraco.Web.WebApi; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs index 50b1597cca..de8ddfd201 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -1,10 +1,10 @@ using NUnit.Framework; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Tests.Common; using Umbraco.Tests.Testing; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs index 4c658379cd..649f63f09e 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs @@ -2,8 +2,8 @@ using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index aaf3b0de96..a18d12351f 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -5,8 +5,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; diff --git a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs index af2ffad6e5..46d67eb9bd 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -13,6 +12,7 @@ using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index 4e1540a525..b1851694bc 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -1,11 +1,10 @@ -using System; +using System; using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.IO; @@ -35,11 +34,11 @@ namespace Umbraco.Tests.Scoping DoThing2 = null; DoThing3 = null; - var services = TestHelper.GetRegister(); + var services = TestHelper.GetRegister(); var composition = new UmbracoBuilder(services, Mock.Of(), TestHelper.GetMockedTypeLoader()); - _testObjects = new TestObjects(services); + _testObjects = new TestObjects(); var globalSettings = new GlobalSettings(); composition.Services.AddUnique(factory => new FileSystems(factory, factory.GetService>(), factory.GetService(), TestHelper.IOHelper, Microsoft.Extensions.Options.Options.Create(globalSettings), TestHelper.GetHostingEnvironment())); @@ -47,7 +46,7 @@ namespace Umbraco.Tests.Scoping Current.Factory = composition.CreateServiceProvider(); } - + [TestCase(false, true, true)] [TestCase(false, true, false)] [TestCase(false, false, true)] @@ -140,7 +139,7 @@ namespace Umbraco.Tests.Scoping { //content1 will be filtered from the args - scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(new[]{ content1 , content3})); + scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(new[] { content1, content3 })); scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs(content1), "DoDeleteForContent"); scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(content2)); //this entire event will be filtered @@ -156,7 +155,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(content3.Id, ((SaveEventArgs)events[0].Args).SavedEntities.First().Id); Assert.AreEqual(typeof(DeleteEventArgs), events[1].Args.GetType()); - Assert.AreEqual(content1.Id, ((DeleteEventArgs) events[1].Args).DeletedEntities.First().Id); + Assert.AreEqual(content1.Id, ((DeleteEventArgs)events[1].Args).DeletedEntities.First().Id); Assert.AreEqual(typeof(SaveEventArgs), events[2].Args.GetType()); Assert.AreEqual(content2.Id, ((SaveEventArgs)events[2].Args).SavedEntities.First().Id); @@ -177,8 +176,8 @@ namespace Umbraco.Tests.Scoping var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { - scope.Events.Dispatch(Test_Unpublished, contentService, new PublishEventArgs(new [] { content }), "Unpublished"); - scope.Events.Dispatch(Test_Deleted, contentService, new DeleteEventArgs(new [] { content }), "Deleted"); + scope.Events.Dispatch(Test_Unpublished, contentService, new PublishEventArgs(new[] { content }), "Unpublished"); + scope.Events.Dispatch(Test_Deleted, contentService, new DeleteEventArgs(new[] { content }), "Deleted"); // see U4-10764 var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray(); @@ -258,9 +257,9 @@ namespace Umbraco.Tests.Scoping // events have been queued var events = scope.Events.GetEvents(EventDefinitionFilter.FirstIn).ToArray(); Assert.AreEqual(1, events.Length); - Assert.AreEqual(content1, ((SaveEventArgs) events[0].Args).SavedEntities.First()); + Assert.AreEqual(content1, ((SaveEventArgs)events[0].Args).SavedEntities.First()); Assert.IsTrue(object.ReferenceEquals(content1, ((SaveEventArgs)events[0].Args).SavedEntities.First())); - Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs) events[0].Args).SavedEntities.First().UpdateDate); + Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs)events[0].Args).SavedEntities.First().UpdateDate); } } diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 1a8e485634..71809d063a 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Web.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -8,7 +8,9 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; +using Umbraco.Core.Hosting; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; @@ -17,7 +19,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; -using Umbraco.Net; +using Umbraco.Infrastructure.PublishedCache.Persistence; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -45,7 +47,7 @@ namespace Umbraco.Tests.Scoping // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess Builder.Services.AddUnique(); - Builder.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); Builder.WithCollectionBuilder() .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } @@ -71,7 +73,7 @@ namespace Umbraco.Tests.Scoping protected override IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) { var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); + var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Current.UmbracoContextAccessor); var runtimeStateMock = new Mock(); runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run); @@ -85,28 +87,23 @@ namespace Umbraco.Tests.Scoping var nuCacheSettings = new NuCacheSettings(); var lifetime = new Mock(); + var repository = new NuCacheContentRepository(ScopeProvider, AppCaches.Disabled, Mock.Of>(), memberRepository, documentRepository, mediaRepository, Mock.Of(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) })); var snapshotService = new PublishedSnapshotService( options, null, - lifetime.Object, - runtimeStateMock.Object, ServiceContext, contentTypeFactory, publishedSnapshotAccessor, Mock.Of(), - ProfilingLogger, + base.ProfilingLogger, NullLoggerFactory.Instance, ScopeProvider, - documentRepository, mediaRepository, memberRepository, + new NuCacheContentService(repository, ScopeProvider, NullLoggerFactory.Instance, Mock.Of()), DefaultCultureAccessor, - new DatabaseDataSource(Mock.Of>()), Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettings()), Factory.GetRequiredService(), new NoopPublishedModelFactory(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), hostingEnvironment, - Mock.Of(), - IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 6814210cc4..af94f6b2e1 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Xml; using Microsoft.Extensions.DependencyInjection; @@ -8,6 +8,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -39,7 +40,7 @@ namespace Umbraco.Tests.Scoping // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess Builder.Services.AddUnique(); - Builder.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); Builder.WithCollectionBuilder() .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } @@ -299,6 +300,10 @@ namespace Umbraco.Tests.Scoping : base(false) { } + public override void SendMessages() { } + + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { throw new NotImplementedException(); diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs deleted file mode 100644 index c0f070d1e9..0000000000 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs +++ /dev/null @@ -1,383 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Umbraco.Tests.Services.Importing { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ImportResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ImportResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.Services.Importing.ImportResources", typeof(ImportResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>CheckboxListTest</name> - /// <version>1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>1</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>1</name> - /// <website>1</website> - /// </author> - /// <r [rest of string was truncated]";. - /// - internal static string CheckboxList_Content_Package { - get { - return ResourceManager.GetString("CheckboxList_Content_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Compositions Packaged</name> - /// <version>1.0</version> - /// <license url="http://opensource.org/licenses/MIT">MIT License</license> - /// <url>http://blog.sitereactor.dk</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// <website>h [rest of string was truncated]";. - /// - internal static string CompositionsTestPackage { - get { - return ResourceManager.GetString("CompositionsTestPackage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Composite Test</name> - /// <version>dfsfd</version> - /// <license url="http://opensource.org/licenses/MIT">MIT License</license> - /// <url>ddsff</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>fsdfds</name> - /// <website>sfdf</website> - /// </author> - /// <rea [rest of string was truncated]";. - /// - internal static string CompositionsTestPackage_Random { - get { - return ResourceManager.GetString("CompositionsTestPackage_Random", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Dictionary-Package</name> - /// <version>1.0</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>http://not.available</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Test</name> - /// <website>http://not.available</w [rest of string was truncated]";. - /// - internal static string Dictionary_Package { - get { - return ResourceManager.GetString("Dictionary_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>bootstrap.min.js</guid> - /// <orgPath>/js</orgPath> - /// <orgName>bootstrap.min.js</orgName> - /// </file> - /// <file> - /// <guid>jquery.min.js</guid> - /// <orgPath>/js</orgPath> - /// <orgName>jquery.min.js</orgName> - /// </file> - /// <file> - /// <guid>top-image.jpg</guid> - /// <orgPath>/Media/1001</orgPath> - /// <orgName>top-image.jpg</orgName> - /// </file> - /// <file> - /// <guid>top-im [rest of string was truncated]";. - /// - internal static string Fanoe_Package { - get { - return ResourceManager.GetString("Fanoe_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>DocTypeError</name> - /// <version>1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">Personal license</license> - /// <url>http://www.iseli-webconsulting.de</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Iseli Webconsulting</name> [rest of string was truncated]";. - /// - internal static string InheritedDocTypes_Package { - get { - return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<DocumentType> - /// <Info> - /// <Name>test</Name> - /// <Alias>test</Alias> - /// <Icon>folder.gif</Icon> - /// <Thumbnail>folder.png</Thumbnail> - /// <Description> - /// </Description> - /// <AllowAtRoot>False</AllowAtRoot> - /// <AllowedTemplates> - /// <Template>test</Template> - /// </AllowedTemplates> - /// <DefaultTemplate>test</DefaultTemplate> - /// </Info> - /// <Structure> - /// <DocumentType>test</DocumentType> - /// </Structure> - /// <GenericProperties> - /// <GenericProperty> [rest of string was truncated]";. - /// - internal static string SingleDocType { - get { - return ResourceManager.GetString("SingleDocType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>Map.cshtml</guid> - /// <orgPath>/macroScripts</orgPath> - /// <orgName>Map.cshtml</orgName> - /// </file> - /// <file> - /// <guid>AccountController.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>AccountController.cs</orgName> - /// </file> - /// <file> - /// <guid>ContactController.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>ContactController.cs</orgName> - /// </file> - /// [rest of string was truncated]";. - /// - internal static string StandardMvc_Package { - get { - return ResourceManager.GetString("StandardMvc_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Template-Update</name> - /// <version>0.1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>https://our.umbraco.com/projects</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// [rest of string was truncated]";. - /// - internal static string TemplateOnly_Package { - get { - return ResourceManager.GetString("TemplateOnly_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Template-Update</name> - /// <version>0.1</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>https://our.umbraco.com/projects</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Morten Christensen</name> - /// [rest of string was truncated]";. - /// - internal static string TemplateOnly_Updated_Package { - get { - return ResourceManager.GetString("TemplateOnly_Updated_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>uBlogsy.BusinessLogic.dll</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.BusinessLogic.dll</orgName> - /// </file> - /// <file> - /// <guid>uBlogsy.BusinessLogic.pdb</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.BusinessLogic.pdb</orgName> - /// </file> - /// <file> - /// <guid>uBlogsy.Common.dll</guid> - /// <orgPath>/bin</orgPath> - /// <orgName>uBlogsy.Common.dll</orgNam [rest of string was truncated]";. - /// - internal static string uBlogsy_Package { - get { - return ResourceManager.GetString("uBlogsy_Package", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> - ///<umbPackage> - /// <files> - /// <file> - /// <guid>XSLTsearch.xslt</guid> - /// <orgPath>/xslt</orgPath> - /// <orgName>XSLTsearch.xslt</orgName> - /// </file> - /// <file> - /// <guid>XSLTsearch.cs</guid> - /// <orgPath>/App_Code</orgPath> - /// <orgName>XSLTsearch.cs</orgName> - /// </file> - /// </files> - /// <info> - /// <package> - /// <name>XSLTsearch</name> - /// <version>3.0.4</version> - /// <license url="http://www.opensource.org/licenses/mit-li [rest of string was truncated]";. - /// - internal static string XsltSearch_Package { - get { - return ResourceManager.GetString("XsltSearch_Package", resourceCulture); - } - } - } -} diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.resx b/src/Umbraco.Tests/Services/Importing/ImportResources.resx deleted file mode 100644 index 97fb2469be..0000000000 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.resx +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - inheriteddoctypes-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - standardmvc-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - ublogsy-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - xsltsearch-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - singledoctype.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - templateonly-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - templateonly-updated-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - checkboxlist-content-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - dictionary-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - compositionstestpackage.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - compositionstestpackage-random.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - - fanoe-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index adc076caec..23df962238 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.TestHelpers protected ISqlContext SqlContext { get; private set; } - internal TestObjects TestObjects = new TestObjects(null); + internal TestObjects TestObjects = new TestObjects(); protected Sql Sql() { diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index c6587f6ad8..103d361fc5 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -6,10 +6,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -18,7 +16,6 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Common.Builders; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; @@ -50,7 +47,7 @@ namespace Umbraco.Tests.TestHelpers var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of()), serializer) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of(), JsonNetSerializer), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var type = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", new PublishedPropertyType[] { }); diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs deleted file mode 100644 index 34b649d3bb..0000000000 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestRunner.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using System.Web.Http; -using Microsoft.Owin.Testing; -using Newtonsoft.Json; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web; -using Umbraco.Web.WebApi; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - public class TestRunner - { - private readonly Func _controllerFactory; - - public TestRunner(Func controllerFactory) - { - _controllerFactory = controllerFactory; - } - - public async Task> Execute(string controllerName, string actionName, HttpMethod method, - HttpContent content = null, - MediaTypeWithQualityHeaderValue mediaTypeHeader = null, - bool assertOkResponse = true, object routeDefaults = null, string url = null) - { - if (mediaTypeHeader == null) - { - mediaTypeHeader = new MediaTypeWithQualityHeaderValue("application/json"); - } - if (routeDefaults == null) - { - routeDefaults = new { controller = controllerName, action = actionName, id = RouteParameter.Optional }; - } - - var startup = new TestStartup( - configuration => - { - configuration.Routes.MapHttpRoute("Default", - routeTemplate: "{controller}/{action}/{id}", - defaults: routeDefaults); - }, - _controllerFactory); - - using (var server = TestServer.Create(builder => startup.Configuration(builder))) - { - var request = new HttpRequestMessage - { - RequestUri = new Uri("https://testserver/" + (url ?? "")), - Method = method - }; - - if (content != null) - request.Content = content; - - request.Headers.Accept.Add(mediaTypeHeader); - - Console.WriteLine(request); - var response = await server.HttpClient.SendAsync(request); - Console.WriteLine(response); - - if (response.IsSuccessStatusCode == false) - { - WriteResponseError(response); - } - - var json = (await ((StreamContent)response.Content).ReadAsStringAsync()).TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix); - if (!json.IsNullOrWhiteSpace()) - { - var deserialized = JsonConvert.DeserializeObject(json); - Console.Write(JsonConvert.SerializeObject(deserialized, Formatting.Indented)); - } - - if (assertOkResponse) - { - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - } - - return Tuple.Create(response, json); - } - } - - private static void WriteResponseError(HttpResponseMessage response) - { - var result = response.Content.ReadAsStringAsync().Result; - Console.Out.WriteLine("Http operation unsuccessfull"); - Console.Out.WriteLine($"Status: '{response.StatusCode}'"); - Console.Out.WriteLine($"Reason: '{response.ReasonPhrase}'"); - Console.Out.WriteLine(result); - } - } -} diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index e91c2fdf4d..8c89905c97 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -38,6 +38,8 @@ using Umbraco.Tests.Common.Builders; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Mail; namespace Umbraco.Tests.TestHelpers { diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 91b82caccb..3b17861fb3 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -1,7 +1,5 @@ -using System; +using System; using System.Configuration; -using System.IO; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; @@ -9,20 +7,14 @@ using Moq; using NPoco; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Events; -using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; using Umbraco.Persistance.SqlCe; -using Umbraco.Tests.Common.Builders; -using Umbraco.Tests.TestHelpers.Stubs; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.TestHelpers @@ -32,11 +24,9 @@ namespace Umbraco.Tests.TestHelpers /// internal partial class TestObjects { - private readonly IServiceCollection _register; - public TestObjects(IServiceCollection register) + public TestObjects() { - _register = register; } /// @@ -69,19 +59,7 @@ namespace Umbraco.Tests.TestHelpers return new UmbracoDatabase(connection, sqlContext, logger, TestHelper.BulkSqlInsertProvider); } - private Lazy GetLazyService(IServiceProvider container, Func ctor) - where T : class - { - return new Lazy(() => container?.GetService() ?? ctor(container)); - } - - private T GetRepo(IServiceProvider container) - where T : class, IRepository - { - return container?.GetService() ?? Mock.Of(); - } - - public IScopeProvider GetScopeProvider(ILoggerFactory loggerFactory, ITypeFinder typeFinder = null, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) + public IScopeProvider GetScopeProvider(ILoggerFactory loggerFactory, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) { var globalSettings = new GlobalSettings(); var connectionString = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName].ConnectionString; @@ -103,11 +81,10 @@ namespace Umbraco.Tests.TestHelpers TestHelper.DbProviderFactoryCreator); } - typeFinder ??= new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); fileSystems ??= new FileSystems(Current.Factory, loggerFactory.CreateLogger(), loggerFactory, TestHelper.IOHelper, Options.Create(globalSettings), TestHelper.GetHostingEnvironment()); var coreDebug = TestHelper.CoreDebugSettings; var mediaFileSystem = Mock.Of(); - return new ScopeProvider(databaseFactory, fileSystems, Microsoft.Extensions.Options.Options.Create(coreDebugSettings), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, typeFinder, NoAppCache.Instance); + return new ScopeProvider(databaseFactory, fileSystems, Options.Create(coreDebugSettings), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance); } } diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index faf387528d..302e1198a8 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Configuration; using System.Data.SqlServerCe; using System.Threading; @@ -32,6 +32,7 @@ using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web.WebApi; using Umbraco.Tests.Common; using Umbraco.Core.Security; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.TestHelpers { @@ -91,7 +92,6 @@ namespace Umbraco.Tests.TestHelpers var lazyMappers = new Lazy(f.GetRequiredService); var factory = new UmbracoDatabaseFactory(f.GetRequiredService>(), f.GetRequiredService(), GetDbConnectionString(), GetDbProviderName(), lazyMappers, TestHelper.DbProviderFactoryCreator); - factory.ResetForTests(); return factory; }); } diff --git a/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs b/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs index fc8a48581a..d8a413fab9 100644 --- a/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs +++ b/src/Umbraco.Tests/Testing/Objects/TestDataSource.cs @@ -1,16 +1,17 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Scoping; +using Umbraco.Infrastructure.PublishedCache.Persistence; using Umbraco.Web; using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.PublishedCache.NuCache.DataSource; namespace Umbraco.Tests.Testing.Objects { - internal class TestDataSource : IDataSource + internal class TestDataSource : INuCacheContentService { private IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory(); @@ -19,27 +20,23 @@ namespace Umbraco.Tests.Testing.Objects : this((IEnumerable) kits) { } - public TestDataSource(IEnumerable kits) - { - Kits = kits.ToDictionary(x => x.Node.Id, x => x); - } + public TestDataSource(IEnumerable kits) => Kits = kits.ToDictionary(x => x.Node.Id, x => x); public Dictionary Kits { get; } // note: it is important to clone the returned kits, as the inner // ContentNode is directly reused and modified by the snapshot service + public ContentNodeKit GetContentSource(int id) + => Kits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default; - public ContentNodeKit GetContentSource(IScope scope, int id) - => Kits.TryGetValue(id, out var kit) ? kit.Clone(PublishedModelFactory) : default; - - public IEnumerable GetAllContentSources(IScope scope) + public IEnumerable GetAllContentSources() => Kits.Values .OrderBy(x => x.Node.Level) .ThenBy(x => x.Node.ParentContentId) .ThenBy(x => x.Node.SortOrder) .Select(x => x.Clone(PublishedModelFactory)); - public IEnumerable GetBranchContentSources(IScope scope, int id) + public IEnumerable GetBranchContentSources(int id) => Kits.Values .Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ",")) .OrderBy(x => x.Node.Level) @@ -47,7 +44,7 @@ namespace Umbraco.Tests.Testing.Objects .ThenBy(x => x.Node.SortOrder) .Select(x => x.Clone(PublishedModelFactory)); - public IEnumerable GetTypeContentSources(IScope scope, IEnumerable ids) + public IEnumerable GetTypeContentSources(IEnumerable ids) => Kits.Values .Where(x => ids.Contains(x.ContentTypeId)) .OrderBy(x => x.Node.Level) @@ -55,24 +52,19 @@ namespace Umbraco.Tests.Testing.Objects .ThenBy(x => x.Node.SortOrder) .Select(x => x.Clone(PublishedModelFactory)); - public ContentNodeKit GetMediaSource(IScope scope, int id) - { - return default; - } + public ContentNodeKit GetMediaSource(int id) => default; - public IEnumerable GetAllMediaSources(IScope scope) - { - return Enumerable.Empty(); - } + public IEnumerable GetAllMediaSources() => Enumerable.Empty(); - public IEnumerable GetBranchMediaSources(IScope scope, int id) - { - return Enumerable.Empty(); - } + public IEnumerable GetBranchMediaSources(int id) => Enumerable.Empty(); - public IEnumerable GetTypeMediaSources(IScope scope, IEnumerable ids) - { - return Enumerable.Empty(); - } + public IEnumerable GetTypeMediaSources(IEnumerable ids) => Enumerable.Empty(); + public void DeleteContentItem(IContentBase item) => throw new NotImplementedException(); + public void RefreshContent(IContent content) => throw new NotImplementedException(); + public void RefreshEntity(IContentBase content) => throw new NotImplementedException(); + public bool VerifyContentDbCache() => throw new NotImplementedException(); + public bool VerifyMediaDbCache() => throw new NotImplementedException(); + public bool VerifyMemberDbCache() => throw new NotImplementedException(); + public void Rebuild(int groupSize = 5000, IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) => throw new NotImplementedException(); } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 533966f5a9..433ef1de02 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -1,11 +1,3 @@ -using Examine; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using NUnit.Framework; -using Serilog; using System; using System.Collections.Generic; using System.Globalization; @@ -15,10 +7,17 @@ using System.Reflection; using System.Web.Routing; using System.Web.Security; using System.Xml.Linq; +using Examine; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using NUnit.Framework; +using Serilog; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; @@ -28,6 +27,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; +using Umbraco.Core.Mail; using Umbraco.Core.Manifest; using Umbraco.Core.Mapping; using Umbraco.Core.Media; @@ -43,6 +43,7 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; @@ -50,6 +51,7 @@ using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; using Umbraco.Web.Actions; using Umbraco.Web.AspNet; +using Umbraco.Web.Composing; using Umbraco.Web.ContentApps; using Umbraco.Web.Hosting; using Umbraco.Web.Install; @@ -63,7 +65,6 @@ using Umbraco.Web.Security.Providers; using Umbraco.Web.Services; using Umbraco.Web.Templates; using Umbraco.Web.Trees; -using Current = Umbraco.Web.Composing.Current; using FileSystems = Umbraco.Core.IO.FileSystems; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -235,10 +236,7 @@ namespace Umbraco.Tests.Testing services.AddUnique(membershipHelper); - - - - TestObjects = new TestObjects(services); + TestObjects = new TestObjects(); Compose(); Current.Factory = Factory = Builder.CreateServiceProvider(); Initialize(); @@ -315,6 +313,8 @@ namespace Umbraco.Tests.Testing Builder.Services.AddUnique(); Builder.Services.AddUnique(); Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); Builder.SetCultureDictionaryFactory(); Builder.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); // register back office sections in the order we want them rendered @@ -383,7 +383,7 @@ namespace Umbraco.Tests.Testing if (configure == false) return; Builder - .ComposeCoreMappingProfiles(); + .AddCoreMappingProfiles(); } protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IHostingEnvironment hostingEnvironment, ILogger logger, IProfilingLogger profilingLogger, UmbracoTestOptions.TypeLoader option) @@ -452,7 +452,7 @@ namespace Umbraco.Tests.Testing if (withApplication == false) return; // default Datalayer/Repositories/SQL/Database/etc... - Builder.ComposeRepositories(); + Builder.AddRepositories(); Builder.Services.AddUnique(); @@ -494,10 +494,10 @@ namespace Umbraco.Tests.Testing Builder.WithCollectionBuilder(); // empty Builder.Services.AddUnique(factory - => TestObjects.GetScopeProvider(_loggerFactory, factory.GetService(), factory.GetService(), factory.GetService())); + => TestObjects.GetScopeProvider(_loggerFactory, factory.GetService(), factory.GetService())); Builder.Services.AddUnique(factory => (IScopeAccessor)factory.GetRequiredService()); - Builder.ComposeServices(); + Builder.AddServices(); // composition root is doing weird things, fix Builder.Services.AddUnique(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 807c64f315..cb3df3b905 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -174,7 +174,6 @@ - @@ -200,7 +199,6 @@ - @@ -217,12 +215,6 @@ - - - True - True - ImportResources.resx - @@ -250,7 +242,6 @@ - @@ -271,7 +262,6 @@ Designer - Designer @@ -311,11 +301,6 @@ - - ResXFileCodeGenerator - ImportResources.Designer.cs - Designer - ResXFileCodeGenerator TestFiles.Designer.cs @@ -323,23 +308,8 @@ - - Designer - - - - - - - - Designer - - - - - diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 59b453cc5b..61b5141856 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -2,9 +2,9 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index cdc2bfed00..52e1c3a5a3 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -12,7 +12,6 @@ using System.Web.Http; using Moq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; @@ -37,6 +36,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Persistance.SqlCe; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Web.Controllers { diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index a2bcb4928a..6afc75e931 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Web; using System.Web.Mvc; using System.Web.Routing; @@ -161,7 +161,7 @@ namespace Umbraco.Tests.Web.Mvc }; var routeData = new RouteData(); - routeData.DataTokens.Add(Core.Constants.Web.UmbracoRouteDefinitionDataToken, routeDefinition); + routeData.Values.Add(Core.Constants.Web.UmbracoRouteDefinitionDataToken, routeDefinition); var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of()); ctrl.ControllerContext = new ControllerContext(Mock.Of(), routeData, ctrl); diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs deleted file mode 100644 index 4e52617e6c..0000000000 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System.IO; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using Moq; -using NUnit.Framework; -using Umbraco.Core.Security; -using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; -using Umbraco.Web.Mvc; -using Umbraco.Web.PublishedCache; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.Web -{ - [TestFixture] - [UmbracoTest(WithApplication = true)] - public class WebExtensionMethodTests : UmbracoTestBase - { - [Test] - public void RouteDataExtensions_GetUmbracoContext() - { - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbCtx = new UmbracoContext( - httpContextAccessor, - Mock.Of(), - Mock.Of(), - TestObjects.GetGlobalSettings(), - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - var r1 = new RouteData(); - r1.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); - - Assert.IsTrue(r1.DataTokens.ContainsKey(Core.Constants.Web.UmbracoContextDataToken)); - Assert.AreSame(umbCtx, r1.DataTokens[Core.Constants.Web.UmbracoContextDataToken]); - } - - [Test] - public void ControllerContextExtensions_GetUmbracoContext_From_RouteValues() - { - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbCtx = new UmbracoContext( - httpContextAccessor, - Mock.Of(), - Mock.Of(), - TestObjects.GetGlobalSettings(), - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - var r1 = new RouteData(); - r1.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); - var ctx1 = CreateViewContext(new ControllerContext(Mock.Of(), r1, new MyController())); - var r2 = new RouteData(); - r2.DataTokens.Add("ParentActionViewContext", ctx1); - var ctx2 = CreateViewContext(new ControllerContext(Mock.Of(), r2, new MyController())); - var r3 = new RouteData(); - r3.DataTokens.Add("ParentActionViewContext", ctx2); - var ctx3 = CreateViewContext(new ControllerContext(Mock.Of(), r3, new MyController())); - - var result = ctx3.GetUmbracoContext(); - - Assert.IsNotNull(result); - Assert.AreSame(umbCtx, result); - } - - [Test] - public void ControllerContextExtensions_GetUmbracoContext_From_Current() - { - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbCtx = new UmbracoContext( - httpContextAccessor, - Mock.Of(), - Mock.Of(), - TestObjects.GetGlobalSettings(), - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - var httpContext = Mock.Of(); - - var r1 = new RouteData(); - var ctx1 = CreateViewContext(new ControllerContext(httpContext, r1, new MyController())); - var r2 = new RouteData(); - r2.DataTokens.Add("ParentActionViewContext", ctx1); - var ctx2 = CreateViewContext(new ControllerContext(httpContext, r2, new MyController())); - var r3 = new RouteData(); - r3.DataTokens.Add("ParentActionViewContext", ctx2); - var ctx3 = CreateViewContext(new ControllerContext(httpContext, r3, new MyController())); - - Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - Current.UmbracoContextAccessor.UmbracoContext = umbCtx; - - var result = ctx3.GetUmbracoContext(); - - Assert.IsNotNull(result); - Assert.AreSame(umbCtx, result); - } - - [Test] - public void ControllerContextExtensions_GetDataTokenInViewContextHierarchy() - { - var r1 = new RouteData(); - r1.DataTokens.Add("hello", "world"); - r1.DataTokens.Add("r", "1"); - var ctx1 = CreateViewContext(new ControllerContext(Mock.Of(), r1, new MyController())); - var r2 = new RouteData(); - r2.DataTokens.Add("ParentActionViewContext", ctx1); - r2.DataTokens.Add("r", "2"); - var ctx2 = CreateViewContext(new ControllerContext(Mock.Of(), r2, new MyController())); - var r3 = new RouteData(); - r3.DataTokens.Add("ParentActionViewContext", ctx2); - r3.DataTokens.Add("r", "3"); - var ctx3 = CreateViewContext(new ControllerContext(Mock.Of(), r3, new MyController())); - - var result = ctx3.GetDataTokenInViewContextHierarchy("hello"); - - Assert.IsNotNull(result as string); - Assert.AreEqual((string) result, "world"); - } - - private static ViewContext CreateViewContext(ControllerContext ctx) - { - return new ViewContext(ctx, Mock.Of(), new ViewDataDictionary(), new TempDataDictionary(), new StringWriter()); - } - - private class MyController : Controller - { } - } -} diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 36e5c2b6fe..502ffbcba2 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Mail; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 19fb6aa2df..34d3a96ca3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -30,10 +30,10 @@ using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.ActionsResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Authorization; +using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.Security; using Umbraco.Web.Models; -using Umbraco.Web.Mvc; using Umbraco.Web.WebAssets; using Constants = Umbraco.Core.Constants; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index a6f6bc8fb8..4a9bf52605 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -127,20 +127,6 @@ namespace Umbraco.Web.BackOffice.Controllers _logger = loggerFactory.CreateLogger(); _allLangs = new Lazy>(() => _localizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase)); - - } - - /// - /// Returns true if any content types have culture variation enabled - /// - /// - [HttpGet] - // TODO: We need to move this since we are going to delete OverrideAuthorization - [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess), OverrideAuthorization] - public bool AllowsCultureVariation() - { - var contentTypes = _contentTypeService.GetAll(); - return contentTypes.Any(contentType => contentType.VariesByCulture()); } /// @@ -636,19 +622,20 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Saves content /// - /// [FileUploadCleanupFilter] [ContentSaveValidation] public async Task PostSaveBlueprint([ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem) { - var contentItemDisplay = await PostSaveInternal(contentItem, + var contentItemDisplay = await PostSaveInternal( + contentItem, content => { EnsureUniqueName(content.Name, content, "Name"); _contentService.SaveBlueprint(contentItem.PersistedContent, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id); - //we need to reuse the underlying logic so return the result that it wants - return OperationResult.Succeed(new EventMessages()); + + // we need to reuse the underlying logic so return the result that it wants + return OperationResult.Succeed(new EventMessages()); }, content => { @@ -663,7 +650,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Saves content /// - /// [FileUploadCleanupFilter] [ContentSaveValidation] [OutgoingEditorModelEvent] @@ -679,9 +665,9 @@ namespace Umbraco.Web.BackOffice.Controllers private async Task PostSaveInternal(ContentItemSave contentItem, Func saveMethod, Func mapToDisplay) { - //Recent versions of IE/Edge may send in the full client side file path instead of just the file name. - //To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all - //uploaded files to being *only* the actual file name (as it should be). + // Recent versions of IE/Edge may send in the full client side file path instead of just the file name. + // To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all + // uploaded files to being *only* the actual file name (as it should be). if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any()) { foreach (var file in contentItem.UploadedFiles) @@ -690,7 +676,7 @@ namespace Umbraco.Web.BackOffice.Controllers } } - //If we've reached here it means: + // If we've reached here it means: // * Our model has been bound // * and validated // * any file attachments have been saved to their temporary location for us to use @@ -700,20 +686,20 @@ namespace Umbraco.Web.BackOffice.Controllers var passesCriticalValidationRules = ValidateCriticalData(contentItem, out var variantCount); - //we will continue to save if model state is invalid, however we cannot save if critical data is missing. + // we will continue to save if model state is invalid, however we cannot save if critical data is missing. if (!ModelState.IsValid) { - //check for critical data validation issues, we can't continue saving if this data is invalid + // check for critical data validation issues, we can't continue saving if this data is invalid if (!passesCriticalValidationRules) { - //ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue! + // ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue! // add the model state to the outgoing object and throw a validation message var forDisplay = mapToDisplay(contentItem.PersistedContent); forDisplay.Errors = ModelState.ToErrorDictionary(); throw HttpResponseException.CreateValidationErrorResponse(forDisplay); } - //if there's only one variant and the model state is not valid we cannot publish so change it to save + // if there's only one variant and the model state is not valid we cannot publish so change it to save if (variantCount == 1) { switch (contentItem.Action) diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs index ec8f09bc17..260d0b01a0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -24,14 +24,12 @@ namespace Umbraco.Web.BackOffice.Controllers [JsonDateTimeFormat] public abstract class ContentControllerBase : BackOfficeNotificationsController { - protected ICultureDictionary CultureDictionary { get; } - protected ILoggerFactory LoggerFactory { get; } - protected IShortStringHelper ShortStringHelper { get; } - protected IEventMessagesFactory EventMessages { get; } - protected ILocalizedTextService LocalizedTextService { get; } private readonly ILogger _logger; private readonly IJsonSerializer _serializer; + /// + /// Initializes a new instance of the class. + /// protected ContentControllerBase( ICultureDictionary cultureDictionary, ILoggerFactory loggerFactory, @@ -49,6 +47,31 @@ namespace Umbraco.Web.BackOffice.Controllers _serializer = serializer; } + /// + /// Gets the + /// + protected ICultureDictionary CultureDictionary { get; } + + /// + /// Gets the + /// + protected ILoggerFactory LoggerFactory { get; } + + /// + /// Gets the + /// + protected IShortStringHelper ShortStringHelper { get; } + + /// + /// Gets the + /// + protected IEventMessagesFactory EventMessages { get; } + + /// + /// Gets the + /// + protected ILocalizedTextService LocalizedTextService { get; } + /// /// Handles if the content for the specified ID isn't found /// diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index f11ed373cd..50be27a108 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -7,49 +7,41 @@ using System.Net.Mime; using System.Text; using System.Xml; using System.Xml.Linq; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Dictionary; using Umbraco.Core.Hosting; +using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Scoping; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Web.Models; -using Umbraco.Web.Models.ContentEditing; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Mapping; -using Umbraco.Core.Security; -using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; +using Umbraco.Web.Common.Authorization; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Editors; +using Umbraco.Web.Models; +using Umbraco.Web.Models.ContentEditing; using ContentType = Umbraco.Core.Models.ContentType; -using Umbraco.Core.Configuration.Models; -using Microsoft.Extensions.Options; -using Umbraco.Core.Serialization; -using Microsoft.AspNetCore.Authorization; -using Umbraco.Web.Common.Authorization; namespace Umbraco.Web.BackOffice.Controllers { /// /// An API controller used for dealing with content types /// - [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] + [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class ContentTypeController : ContentTypeControllerBase { // TODO: Split this controller apart so that authz is consistent, currently we need to authz each action individually. // It would be possible to have something like a ContentTypeInfoController for the GetAllPropertyTypeAliases/GetCount/GetAllowedChildren/etc... actions private readonly IEntityXmlSerializer _serializer; - private readonly GlobalSettings _globalSettings; private readonly PropertyEditorCollection _propertyEditors; - private readonly IScopeProvider _scopeProvider; private readonly IContentTypeService _contentTypeService; private readonly UmbracoMapper _umbracoMapper; private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; @@ -58,14 +50,10 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ILocalizedTextService _localizedTextService; private readonly IFileService _fileService; private readonly ILogger _logger; - private readonly ILoggerFactory _loggerFactory; private readonly IContentService _contentService; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; - private readonly ILocalizationService _LocalizationService; - private readonly IMacroService _macroService; - private readonly IEntityService _entityService; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IConfigurationEditorJsonSerializer _jsonSerializer; + private readonly PackageDataInstallation _packageDataInstallation; public ContentTypeController( ICultureDictionary cultureDictionary, @@ -75,23 +63,17 @@ namespace Umbraco.Web.BackOffice.Controllers UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, IEntityXmlSerializer serializer, - IOptions globalSettings, PropertyEditorCollection propertyEditors, - IScopeProvider scopeProvider, IBackOfficeSecurityAccessor backofficeSecurityAccessor, IDataTypeService dataTypeService, IShortStringHelper shortStringHelper, IFileService fileService, ILogger logger, - ILoggerFactory loggerFactory, IContentService contentService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, - ILocalizationService localizationService, - IMacroService macroService, - IEntityService entityService, IHostingEnvironment hostingEnvironment, EditorValidatorCollection editorValidatorCollection, - IConfigurationEditorJsonSerializer jsonSerializer) + PackageDataInstallation packageDataInstallation) : base(cultureDictionary, editorValidatorCollection, contentTypeService, @@ -101,9 +83,7 @@ namespace Umbraco.Web.BackOffice.Controllers localizedTextService) { _serializer = serializer; - _globalSettings = globalSettings.Value; _propertyEditors = propertyEditors; - _scopeProvider = scopeProvider; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; _backofficeSecurityAccessor = backofficeSecurityAccessor; @@ -112,14 +92,10 @@ namespace Umbraco.Web.BackOffice.Controllers _localizedTextService = localizedTextService; _fileService = fileService; _logger = logger; - _loggerFactory = loggerFactory; _contentService = contentService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; - _LocalizationService = localizationService; - _macroService = macroService; - _entityService = entityService; _hostingEnvironment = hostingEnvironment; - _jsonSerializer = jsonSerializer; + _packageDataInstallation = packageDataInstallation; } [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] @@ -138,8 +114,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Gets the document type a given id /// - /// - /// [DetermineAmbiguousActionByPassingParameters] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public DocumentTypeDisplay GetById(int id) @@ -157,8 +131,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Gets the document type a given guid /// - /// - /// [DetermineAmbiguousActionByPassingParameters] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public DocumentTypeDisplay GetById(Guid id) @@ -176,8 +148,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Gets the document type a given udi /// - /// - /// [DetermineAmbiguousActionByPassingParameters] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public DocumentTypeDisplay GetById(Udi id) @@ -199,8 +169,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Deletes a document type with a given ID /// - /// - /// [HttpDelete] [HttpPost] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] @@ -219,8 +187,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Gets all user defined properties. /// - /// - [Authorize(Policy = AuthorizationPolicies.TreeAccessAnyContentOrTypes)] + [Authorize(Policy = AuthorizationPolicies.TreeAccessAnyContentOrTypes)] public IEnumerable GetAllPropertyTypeAliases() { return _contentTypeService.GetAllPropertyTypeAliases(); @@ -229,7 +196,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Gets all the standard fields. /// - /// [Authorize(Policy = AuthorizationPolicies.TreeAccessAnyContentOrTypes)] public IEnumerable GetAllStandardFields() { @@ -241,8 +207,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// Returns the available compositions for this content type /// This has been wrapped in a dto instead of simple parameters to support having multiple parameters in post request body /// - /// - /// [HttpPost] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public IActionResult GetAvailableCompositeContentTypes(GetAvailableCompositionsFilter filter) @@ -255,12 +219,22 @@ namespace Umbraco.Web.BackOffice.Controllers }); return Ok(result); } + + /// + /// Returns true if any content types have culture variation enabled + /// + [HttpGet] + [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] + public bool AllowsCultureVariation() + { + IEnumerable contentTypes = _contentTypeService.GetAll(); + return contentTypes.Any(contentType => contentType.VariesByCulture()); + } + /// /// Returns where a particular composition has been used /// This has been wrapped in a dto instead of simple parameters to support having multiple parameters in post request body /// - /// - /// [HttpPost] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] public IActionResult GetWhereCompositionIsUsedInContentTypes(GetAvailableCompositionsFilter filter) @@ -298,8 +272,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Deletes a document type container with a given ID /// - /// - /// [HttpDelete] [HttpPost] [Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)] @@ -626,15 +598,13 @@ namespace Umbraco.Web.BackOffice.Controllers return NotFound(); } - var dataInstaller = new PackageDataInstallation(_loggerFactory.CreateLogger(), _loggerFactory, _fileService, _macroService, _LocalizationService, - _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, Options.Create(_globalSettings), _localizedTextService, _jsonSerializer); var xd = new XmlDocument {XmlResolver = null}; xd.Load(filePath); var userId = _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0); var element = XElement.Parse(xd.InnerXml); - dataInstaller.ImportDocumentType(element, userId); + _packageDataInstallation.ImportDocumentType(element, userId); // Try to clean up the temporary file. try diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index b2a6300cc9..219ca694e8 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -31,6 +31,7 @@ using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; using Umbraco.Web.Security; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Controllers { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index 49a20f1150..67cd41ff29 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -6,6 +6,7 @@ using System.Net; using System.Net.Mime; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -22,7 +23,6 @@ using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Validation; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; @@ -32,17 +32,15 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; +using Umbraco.Web.BackOffice.ActionResults; +using Umbraco.Web.BackOffice.Authorization; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.ModelBinders; -using Umbraco.Web.BackOffice.ActionResults; using Umbraco.Web.Common.Attributes; +using Umbraco.Web.Common.Authorization; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.ContentApps; using Umbraco.Web.Models.ContentEditing; -using Constants = Umbraco.Core.Constants; -using Microsoft.AspNetCore.Authorization; -using Umbraco.Web.Common.Authorization; -using Umbraco.Web.BackOffice.Authorization; namespace Umbraco.Web.BackOffice.Controllers { @@ -481,7 +479,7 @@ namespace Umbraco.Web.BackOffice.Controllers { // Authorize... var requirement = new MediaPermissionsResourceRequirement(); - var authorizationResult = await _authorizationService.AuthorizeAsync(User, _mediaService.GetById(move.Id), requirement); + var authorizationResult = await _authorizationService.AuthorizeAsync(User, new MediaPermissionsResource(_mediaService.GetById(move.Id)), requirement); if (!authorizationResult.Succeeded) { return Forbid(); @@ -702,7 +700,7 @@ namespace Umbraco.Web.BackOffice.Controllers return NotFound("The passed id doesn't exist"); } var tempFiles = new PostedFiles(); - + //in case we pass a path with a folder in it, we will create it and upload media to it. if (!string.IsNullOrEmpty(path)) @@ -882,7 +880,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (validatePermissions) { var requirement = new MediaPermissionsResourceRequirement(); - var authorizationResult = await _authorizationService.AuthorizeAsync(User, _mediaService.GetById(intParentId), requirement); + var authorizationResult = await _authorizationService.AuthorizeAsync(User, new MediaPermissionsResource(_mediaService.GetById(intParentId)), requirement); if (!authorizationResult.Succeeded) { throw new HttpResponseException( @@ -893,7 +891,7 @@ namespace Umbraco.Web.BackOffice.Controllers NotificationStyle.Warning))); } } - + return intParentId; } @@ -909,7 +907,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - + var toMove = _mediaService.GetById(model.Id); if (toMove == null) { @@ -957,7 +955,7 @@ namespace Umbraco.Web.BackOffice.Controllers return toMove; } - + public PagedResult GetPagedReferences(int id, string entityType, int pageNumber = 1, int pageSize = 100) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs index 36bf4d2fca..7f6bfe781f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs @@ -13,11 +13,9 @@ using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Authorization; using Umbraco.Web.Common.Exceptions; -using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Controllers { @@ -105,7 +103,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (package == null) return NotFound(); - var fullPath = _hostingEnvironment.MapPathContentRoot(package.PackagePath); + var fullPath = _hostingEnvironment.MapPathWebRoot(package.PackagePath); if (!System.IO.File.Exists(fullPath)) throw HttpResponseException.CreateNotificationValidationErrorResponse("No file found for path " + package.PackagePath); diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs index 961ec388f7..d1f5d36b0f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs @@ -11,7 +11,6 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; -using Umbraco.Net; using Umbraco.Core.Packaging; using Umbraco.Core.Security; using Umbraco.Core.Services; diff --git a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs index 3dd4191c2e..0405012898 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.Extensions.Options; @@ -108,7 +108,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// The endpoint that is loaded within the preview iframe /// - /// [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] public ActionResult Frame(int id, string culture) { @@ -119,22 +118,17 @@ namespace Umbraco.Web.BackOffice.Controllers return RedirectPermanent($"../../{id}.aspx{query}"); } + public ActionResult EnterPreview(int id) { var user = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser; - - var previewToken = _publishedSnapshotService.EnterPreview(user, id); - - _cookieManager.SetCookieValue(Constants.Web.PreviewCookieName, previewToken); + _cookieManager.SetCookieValue(Constants.Web.PreviewCookieName, "preview"); return null; } + public ActionResult End(string redir = null) { - var previewToken = _cookieManager.GetPreviewCookieValue(); - - _publishedSnapshotService.ExitPreview(previewToken); - _cookieManager.ExpireCookie(Constants.Web.PreviewCookieName); // Expire Client-side cookie that determines whether the user has accepted to be in Preview Mode when visiting the website. diff --git a/src/Umbraco.Web.BackOffice/Controllers/PublishedSnapshotCacheStatusController.cs b/src/Umbraco.Web.BackOffice/Controllers/PublishedSnapshotCacheStatusController.cs index c9c420f254..90db13227f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PublishedSnapshotCacheStatusController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PublishedSnapshotCacheStatusController.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Reflection.Metadata; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Web.Cache; @@ -8,43 +9,54 @@ using Umbraco.Web.PublishedCache; namespace Umbraco.Web.BackOffice.Controllers { - [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] + [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class PublishedSnapshotCacheStatusController : UmbracoAuthorizedApiController { private readonly IPublishedSnapshotService _publishedSnapshotService; + private readonly IPublishedSnapshotStatus _publishedSnapshotStatus; private readonly DistributedCache _distributedCache; - public PublishedSnapshotCacheStatusController(IPublishedSnapshotService publishedSnapshotService, DistributedCache distributedCache) + /// + /// Initializes a new instance of the class. + /// + public PublishedSnapshotCacheStatusController( + IPublishedSnapshotService publishedSnapshotService, + IPublishedSnapshotStatus publishedSnapshotStatus, + DistributedCache distributedCache) { _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); + _publishedSnapshotStatus = publishedSnapshotStatus; _distributedCache = distributedCache; } + /// + /// Rebuilds the Database cache + /// [HttpPost] public string RebuildDbCache() { _publishedSnapshotService.Rebuild(); - return _publishedSnapshotService.GetStatus(); + return _publishedSnapshotStatus.GetStatus(); } + /// + /// Gets a status report + /// [HttpGet] - public string GetStatus() - { - return _publishedSnapshotService.GetStatus(); - } + public string GetStatus() => _publishedSnapshotStatus.GetStatus(); + /// + /// Cleans up unused snapshots + /// [HttpGet] - public string Collect() + public async Task Collect() { GC.Collect(); - _publishedSnapshotService.Collect(); - return _publishedSnapshotService.GetStatus(); + await _publishedSnapshotService.CollectAsync(); + return _publishedSnapshotStatus.GetStatus(); } [HttpPost] - public void ReloadCache() - { - _distributedCache.RefreshAllPublishedSnapshot(); - } + public void ReloadCache() => _distributedCache.RefreshAllPublishedSnapshot(); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PublishedStatusController.cs b/src/Umbraco.Web.BackOffice/Controllers/PublishedStatusController.cs index f63c2d5e6a..5c41d54cb8 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PublishedStatusController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PublishedStatusController.cs @@ -1,4 +1,4 @@ -using System; +using System; using Microsoft.AspNetCore.Mvc; using Umbraco.Web.PublishedCache; @@ -6,22 +6,22 @@ namespace Umbraco.Web.BackOffice.Controllers { public class PublishedStatusController : UmbracoAuthorizedApiController { - private readonly IPublishedSnapshotService _publishedSnapshotService; + private readonly IPublishedSnapshotStatus _publishedSnapshotStatus; - public PublishedStatusController(IPublishedSnapshotService publishedSnapshotService) + public PublishedStatusController(IPublishedSnapshotStatus publishedSnapshotStatus) { - _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); + _publishedSnapshotStatus = publishedSnapshotStatus ?? throw new ArgumentNullException(nameof(publishedSnapshotStatus)); } [HttpGet] public string GetPublishedStatusUrl() { - if (!string.IsNullOrWhiteSpace(_publishedSnapshotService.StatusUrl)) + if (!string.IsNullOrWhiteSpace(_publishedSnapshotStatus.StatusUrl)) { - return _publishedSnapshotService.StatusUrl; + return _publishedSnapshotStatus.StatusUrl; } - throw new NotSupportedException("Not supported: " + _publishedSnapshotService.GetType().FullName); + throw new NotSupportedException("Not supported: " + _publishedSnapshotStatus.GetType().FullName); } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index 9d7999b9f7..fca8c49004 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -18,6 +18,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; +using Umbraco.Core.Mail; using Umbraco.Core.Mapping; using Umbraco.Core.Media; using Umbraco.Core.Models; diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/ServiceCollectionExtensions.cs similarity index 94% rename from src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs rename to src/Umbraco.Web.BackOffice/DependencyInjection/ServiceCollectionExtensions.cs index 9ad448a603..7a40c03f9f 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/ServiceCollectionExtensions.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Core; using Umbraco.Core.Security; using Umbraco.Core.Serialization; +using Umbraco.Extensions; +using Umbraco.Infrastructure.Security; using Umbraco.Net; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Authorization; @@ -13,15 +15,13 @@ using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Authorization; using Umbraco.Web.Common.Security; -namespace Umbraco.Extensions +namespace Umbraco.Web.BackOffice.DependencyInjection { - public static class BackOfficeServiceCollectionExtensions + public static class ServiceCollectionExtensions { - /// /// Adds the services required for using Umbraco back office Identity /// - /// public static void AddUmbracoBackOfficeIdentity(this IServiceCollection services) { services.AddDataProtection(); @@ -38,6 +38,15 @@ namespace Umbraco.Extensions services.ConfigureOptions(); } + /// + /// Adds the services required for using Members Identity + /// + public static void AddMembersIdentity(this IServiceCollection services) => + services.BuildMembersIdentity() + .AddDefaultTokenProviders() + .AddUserStore() + .AddMembersUserManager(); + private static BackOfficeIdentityBuilder BuildUmbracoBackOfficeIdentity(this IServiceCollection services) { // Borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/IdentityServiceCollectionExtensions.cs#L33 @@ -76,15 +85,22 @@ namespace Umbraco.Extensions return new BackOfficeIdentityBuilder(services); } + private static MembersIdentityBuilder BuildMembersIdentity(this IServiceCollection services) + { + // Services used by Umbraco members identity + services.TryAddScoped, UserValidator>(); + services.TryAddScoped, PasswordValidator>(); + services.TryAddScoped, PasswordHasher>(); + return new MembersIdentityBuilder(services); + } + /// /// Add authorization handlers and policies /// - /// public static void AddBackOfficeAuthorizationPolicies(this IServiceCollection services, string backOfficeAuthenticationScheme = Constants.Security.BackOfficeAuthenticationType) { // NOTE: Even though we are registering these handlers globally they will only actually execute their logic for - // any auth defining a matching requirement and scheme. - + // any auth defining a matching requirement and scheme. services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -247,7 +263,7 @@ namespace Umbraco.Extensions policy.Requirements.Add(new SectionRequirement(Constants.Applications.Settings)); }); - //We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered + // We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered // this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here. options.AddPolicy(AuthorizationPolicies.SectionAccessForContentTree, policy => { diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..b903935860 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -0,0 +1,184 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Services; +using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; +using Umbraco.Web.BackOffice.Authorization; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Filters; +using Umbraco.Web.BackOffice.Middleware; +using Umbraco.Web.BackOffice.Routing; +using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.BackOffice.Services; +using Umbraco.Web.BackOffice.Trees; +using Umbraco.Web.Common.Authorization; +using Umbraco.Web.Common.DependencyInjection; + +namespace Umbraco.Web.BackOffice.DependencyInjection +{ + /// + /// Extension methods for for the Umbraco back office + /// + public static class UmbracoBuilderExtensions + { + /// + /// Adds all required components to run the Umbraco back office + /// + public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder) => builder + .AddConfiguration() + .AddUmbracoCore() + .AddWebComponents() + .AddRuntimeMinifier() + .AddBackOfficeCore() + .AddBackOfficeAuthentication() + .AddBackOfficeIdentity() + .AddMembersIdentity() + .AddBackOfficeAuthorizationPolicies() + .AddMiniProfiler() + .AddMvcAndRazor() + .AddWebServer() + .AddPreviewSupport() + .AddHostedServices() + .AddDistributedCache(); + + /// + /// Adds Umbraco back office authentication requirements + /// + public static IUmbracoBuilder AddBackOfficeAuthentication(this IUmbracoBuilder builder) + { + builder.Services.AddAntiforgery(); + + builder.Services + + // This just creates a builder, nothing more + .AddAuthentication() + + // Add our custom schemes which are cookie handlers + .AddCookie(Core.Constants.Security.BackOfficeAuthenticationType) + .AddCookie(Core.Constants.Security.BackOfficeExternalAuthenticationType, o => + { + o.Cookie.Name = Core.Constants.Security.BackOfficeExternalAuthenticationType; + o.ExpireTimeSpan = TimeSpan.FromMinutes(5); + }) + + // Although we don't natively support this, we add it anyways so that if end-users implement the required logic + // they don't have to worry about manually adding this scheme or modifying the sign in manager + .AddCookie(Core.Constants.Security.BackOfficeTwoFactorAuthenticationType, o => + { + o.Cookie.Name = Core.Constants.Security.BackOfficeTwoFactorAuthenticationType; + o.ExpireTimeSpan = TimeSpan.FromMinutes(5); + }); + + builder.Services.ConfigureOptions(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + return builder; + } + + /// + /// Adds Identity support for Umbraco back office + /// + public static IUmbracoBuilder AddBackOfficeIdentity(this IUmbracoBuilder builder) + { + builder.Services.AddUmbracoBackOfficeIdentity(); + + return builder; + } + + /// + /// Adds Identity support for Umbraco members + /// + public static IUmbracoBuilder AddMembersIdentity(this IUmbracoBuilder builder) + { + builder.Services.AddMembersIdentity(); + + return builder; + } + + /// + /// Adds Umbraco back office authorization policies + /// + public static IUmbracoBuilder AddBackOfficeAuthorizationPolicies(this IUmbracoBuilder builder, string backOfficeAuthenticationScheme = Core.Constants.Security.BackOfficeAuthenticationType) + { + builder.Services.AddBackOfficeAuthorizationPolicies(backOfficeAuthenticationScheme); + + builder.Services.AddSingleton(); + + builder.Services.AddAuthorization(options + => options.AddPolicy(AuthorizationPolicies.UmbracoFeatureEnabled, policy + => policy.Requirements.Add(new FeatureAuthorizeRequirement()))); + + return builder; + } + + /// + /// Adds Umbraco preview support + /// + public static IUmbracoBuilder AddPreviewSupport(this IUmbracoBuilder builder) + { + builder.Services.AddSignalR(); + + return builder; + } + + /// + /// Adds support for external login providers in Umbraco + /// + public static IUmbracoBuilder AddBackOfficeExternalLogins(this IUmbracoBuilder umbracoBuilder, Action builder) + { + builder(new BackOfficeExternalLoginsBuilder(umbracoBuilder.Services)); + return umbracoBuilder; + } + + /// + /// Gets the back office tree collection builder + /// + public static TreeCollectionBuilder Trees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + public static IUmbracoBuilder AddBackOfficeCore(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // register back office trees + // the collection builder only accepts types inheriting from TreeControllerBase + // and will filter out those that are not attributed with TreeAttribute + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.Trees() + .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); + + builder.AddWebMappingProfiles(); + + builder.Services.AddUnique(factory => + { + var path = "~/"; + var hostingEnvironment = factory.GetRequiredService(); + return new PhysicalFileSystem( + factory.GetRequiredService(), + hostingEnvironment, + factory.GetRequiredService>(), + hostingEnvironment.MapPathContentRoot(path), + hostingEnvironment.ToAbsolute(path) + ); + }); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + return builder; + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Extensions/AuthenticationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/AuthenticationBuilderExtensions.cs deleted file mode 100644 index 8145cb4278..0000000000 --- a/src/Umbraco.Web.BackOffice/Extensions/AuthenticationBuilderExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Umbraco.Core.DependencyInjection; -using Umbraco.Web.BackOffice.Security; - -namespace Umbraco.Extensions -{ - public static class AuthenticationBuilderExtensions - { - public static IUmbracoBuilder AddBackOfficeExternalLogins(this IUmbracoBuilder umbracoBuilder, Action builder) - { - builder(new BackOfficeExternalLoginsBuilder(umbracoBuilder.Services)); - return umbracoBuilder; - } - } - -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs index 6ff42a5737..71cb14eb78 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs @@ -1,67 +1,55 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.DependencyInjection; using Umbraco.Web.BackOffice.Middleware; using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Security; namespace Umbraco.Extensions { + /// + /// extensions for Umbraco + /// public static class BackOfficeApplicationBuilderExtensions { - public static IApplicationBuilder UseUmbraco(this IApplicationBuilder app) - { - if (app == null) throw new ArgumentNullException(nameof(app)); - app.UseStatusCodePages(); - app.UseRouting(); - - app.UseUmbracoCore(); - app.UseUmbracoRouting(); - app.UseRequestLocalization(); - app.UseUmbracoRequestLogging(); - app.UseUmbracoBackOffice(); - app.UseUmbracoPreview(); - app.UseUmbracoInstaller(); - - return app; - } - public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + // NOTE: This method will have been called after UseRouting, UseAuthentication, UseAuthorization + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } app.UseBackOfficeUserManagerAuditing(); - // Important we handle image manipulations before the static files, otherwise the querystring is just ignored. - // TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoBackOffice too? - app.UseImageSharp(); - app.UseStaticFiles(); - - // Must be called after UseRouting and before UseEndpoints - app.UseSession(); - - if (!app.UmbracoCanBoot()) return app; + if (!app.UmbracoCanBoot()) + { + return app; + } app.UseEndpoints(endpoints => { - var backOfficeRoutes = app.ApplicationServices.GetRequiredService(); + BackOfficeAreaRoutes backOfficeRoutes = app.ApplicationServices.GetRequiredService(); backOfficeRoutes.CreateRoutes(endpoints); }); app.UseUmbracoRuntimeMinification(); - app.UseMiddleware(); app.UseMiddleware(); + app.UseUmbracoPreview(); + return app; } public static IApplicationBuilder UseUmbracoPreview(this IApplicationBuilder app) { + // TODO: I'm unsure this middleware will execute before the endpoint, we'll have to see + app.UseMiddleware(); + app.UseEndpoints(endpoints => { - var previewRoutes = app.ApplicationServices.GetRequiredService(); + PreviewRoutes previewRoutes = app.ApplicationServices.GetRequiredService(); previewRoutes.CreateRoutes(endpoints); }); diff --git a/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs deleted file mode 100644 index 2c14e33e2b..0000000000 --- a/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Web.BackOffice.Trees; - -// the namespace here is intentional - although defined in Umbraco.Web assembly, -// this class should be visible when using Umbraco.Core.Components, alongside -// Umbraco.Core's own CompositionExtensions class - -// ReSharper disable once CheckNamespace -namespace Umbraco.Extensions -{ - /// - /// Provides extension methods to the class. - /// - public static class WebCompositionExtensions - { - #region Collection Builders - - /// - /// Gets the back office tree collection builder - /// - /// - /// - public static TreeCollectionBuilder Trees(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - #endregion - } -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs index e6385e6bf9..7c576f2858 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs @@ -1,32 +1,52 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Security; +using Umbraco.Infrastructure.Security; namespace Umbraco.Extensions { + /// + /// Extension methods for + /// public static class IdentityBuilderExtensions { /// /// Adds a implementation for /// - /// The type of the user manager to add. - /// + /// The usermanager interface + /// The usermanager type + /// The /// The current instance. - public static IdentityBuilder AddUserManager(this IdentityBuilder identityBuilder) where TUserManager : UserManager, TInterface + public static IdentityBuilder AddUserManager(this IdentityBuilder identityBuilder) + where TUserManager : UserManager, TInterface { identityBuilder.AddUserManager(); identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TUserManager)); return identityBuilder; } + /// + /// Adds a for the . + /// + /// The usermanager interface + /// The usermanager type + /// The current instance. + public static IdentityBuilder AddMembersUserManager(this IdentityBuilder identityBuilder) + where TUserManager : UserManager, TInterface + { + identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TUserManager)); + return identityBuilder; + } + /// /// Adds a implementation for /// - /// - /// - /// - /// - public static IdentityBuilder AddSignInManager(this IdentityBuilder identityBuilder) where TSignInManager : SignInManager, TInterface + /// The sign in manager interface + /// The sign in manager type + /// The + /// The current instance. + public static IdentityBuilder AddSignInManager(this IdentityBuilder identityBuilder) + where TSignInManager : SignInManager, TInterface { identityBuilder.AddSignInManager(); identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TSignInManager)); diff --git a/src/Umbraco.Web.BackOffice/Extensions/MemberIdentityBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/MemberIdentityBuilderExtensions.cs deleted file mode 100644 index e3551aa363..0000000000 --- a/src/Umbraco.Web.BackOffice/Extensions/MemberIdentityBuilderExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Infrastructure.Security; - -namespace Umbraco.Web.BackOffice.Extensions -{ - public static class MemberIdentityBuilderExtensions - { - /// - /// Adds a for the . - /// - /// The type of the user manager to add. - /// - /// The current instance. - public static IdentityBuilder AddUserManager(this IdentityBuilder identityBuilder) - where TUserManager : UserManager, TInterface - { - identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TUserManager)); - return identityBuilder; - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/MembersUserServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/MembersUserServiceCollectionExtensions.cs deleted file mode 100644 index 64e583b4b9..0000000000 --- a/src/Umbraco.Web.BackOffice/Extensions/MembersUserServiceCollectionExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Umbraco.Infrastructure.Security; -using Umbraco.Web.Common.Security; - -namespace Umbraco.Web.BackOffice.Extensions -{ - public static class MembersUserServiceCollectionExtensions - { - /// - /// Adds the services required for using Members Identity - /// - /// - public static void AddMembersIdentity(this IServiceCollection services) - { - services.BuildMembersIdentity() - .AddDefaultTokenProviders() - .AddUserStore() - .AddUserManager(); - } - - private static MembersIdentityBuilder BuildMembersIdentity(this IServiceCollection services) - { - // Services used by Umbraco members identity - services.TryAddScoped, UserValidator>(); - services.TryAddScoped, PasswordValidator>(); - services.TryAddScoped, PasswordHasher>(); - return new MembersIdentityBuilder(services); - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs deleted file mode 100644 index 82b2e88d5f..0000000000 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.DependencyInjection; -using Umbraco.Web.BackOffice.Extensions; -using Umbraco.Web.BackOffice.Filters; -using Umbraco.Web.BackOffice.Security; - -namespace Umbraco.Extensions -{ - public static class UmbracoBuilderExtensions - { - public static IUmbracoBuilder AddAllBackOfficeComponents(this IUmbracoBuilder builder) - { - return builder - .AddConfiguration() - .AddUmbracoCore() - .AddWebComponents() - .AddRuntimeMinifier() - .AddBackOffice() - .AddBackOfficeIdentity() - .AddMembersIdentity() - .AddBackOfficeAuthorizationPolicies() - .AddMiniProfiler() - .AddMvcAndRazor() - .AddWebServer() - .AddPreviewSupport() - .AddHostedServices() - .AddHttpClients(); - } - - public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder) - { - builder.Services.AddAntiforgery(); - builder.Services.AddSingleton(); - - builder.Services - .AddAuthentication() // This just creates a builder, nothing more - // Add our custom schemes which are cookie handlers - .AddCookie(Core.Constants.Security.BackOfficeAuthenticationType) - .AddCookie(Core.Constants.Security.BackOfficeExternalAuthenticationType, o => - { - o.Cookie.Name = Core.Constants.Security.BackOfficeExternalAuthenticationType; - o.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }) - // Although we don't natively support this, we add it anyways so that if end-users implement the required logic - // they don't have to worry about manually adding this scheme or modifying the sign in manager - .AddCookie(Core.Constants.Security.BackOfficeTwoFactorAuthenticationType, o => - { - o.Cookie.Name = Core.Constants.Security.BackOfficeTwoFactorAuthenticationType; - o.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }); - - builder.Services.ConfigureOptions(); - return builder; - } - - public static IUmbracoBuilder AddMembersIdentity(this IUmbracoBuilder builder) - { - builder.Services.AddMembersIdentity(); - - return builder; - } - - public static IUmbracoBuilder AddBackOfficeIdentity(this IUmbracoBuilder builder) - { - builder.Services.AddUmbracoBackOfficeIdentity(); - - return builder; - } - - public static IUmbracoBuilder AddBackOfficeAuthorizationPolicies(this IUmbracoBuilder builder, string backOfficeAuthenticationScheme = Umbraco.Core.Constants.Security.BackOfficeAuthenticationType) - { - builder.Services.AddBackOfficeAuthorizationPolicies(backOfficeAuthenticationScheme); - // TODO: See other TODOs in things like UmbracoApiControllerBase ... AFAIK all of this is only used for the back office - // so IMO these controllers and the features auth policies should just be moved to the back office project and then this - // ext method can be removed. - builder.Services.AddUmbracoCommonAuthorizationPolicies(); - - return builder; - } - - public static IUmbracoBuilder AddPreviewSupport(this IUmbracoBuilder builder) - { - builder.Services.AddSignalR(); - - return builder; - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs index eeb0903e88..f66c175f29 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs @@ -7,7 +7,7 @@ namespace Umbraco.Extensions { public static class WebMappingProfiles { - public static IUmbracoBuilder ComposeWebMappingProfiles(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddWebMappingProfiles(this IUmbracoBuilder builder) { builder.WithCollectionBuilder() .Add() diff --git a/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationAttribute.cs deleted file mode 100644 index 3d7b68cc80..0000000000 --- a/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc.Filters; - -namespace Umbraco.Web.BackOffice.Filters -{ - // TODO: This should probably be deleted, anything requiring this should move to a different controller - public class OverrideAuthorizationAttribute : ActionFilterAttribute - { - /// - /// Ensures a special type of authorization filter is ignored. Defaults to . - /// - /// The type of authorization filter to override. if null then is used. - /// - /// https://stackoverflow.com/questions/33558095/overrideauthorizationattribute-in-asp-net-5 - /// - public OverrideAuthorizationAttribute(Type filtersToOverride = null) - { - FiltersToOverride = filtersToOverride ?? typeof(IAuthorizationFilter); - } - - public Type FiltersToOverride { get;} - - - } -} diff --git a/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationFilterProvider.cs b/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationFilterProvider.cs deleted file mode 100644 index 39f691e190..0000000000 --- a/src/Umbraco.Web.BackOffice/Filters/OverrideAuthorizationFilterProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Linq; -using Microsoft.AspNetCore.Mvc.Filters; -using Umbraco.Core; - -namespace Umbraco.Web.BackOffice.Filters -{ - // TODO: This should be deleted, anything requiring this should move to a different controller - public class OverrideAuthorizationFilterProvider : IFilterProvider, IFilterMetadata - { - public void OnProvidersExecuted(FilterProviderContext context) - { - - } - - public void OnProvidersExecuting(FilterProviderContext context) - { - if (context.ActionContext.ActionDescriptor.FilterDescriptors != null) - { - //Does the action have any UmbracoAuthorizeFilter? - var overrideFilters = context.Results.Where(filterItem => filterItem.Filter is OverrideAuthorizationAttribute).ToArray(); - foreach (var overrideFilter in overrideFilters) - { - context.Results.RemoveAll(filterItem => - //Remove any filter for the type indicated in the UmbracoAuthorizeFilter attribute - filterItem.Descriptor.Filter.GetType() == ((OverrideAuthorizationAttribute)overrideFilter.Filter).FiltersToOverride && - //Remove filters with lower scope (ie controller) than the override filter (ie action method) - filterItem.Descriptor.Scope < overrideFilter.Descriptor.Scope); - } - } - } - - //all framework providers have negative orders, so ours will come later - public int Order => 1; - } -} diff --git a/src/Umbraco.Web.BackOffice/Middleware/PreviewAuthenticationMiddleware.cs b/src/Umbraco.Web.BackOffice/Middleware/PreviewAuthenticationMiddleware.cs index 284dbbc913..06715b4ad1 100644 --- a/src/Umbraco.Web.BackOffice/Middleware/PreviewAuthenticationMiddleware.cs +++ b/src/Umbraco.Web.BackOffice/Middleware/PreviewAuthenticationMiddleware.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -45,7 +45,7 @@ namespace Umbraco.Web.BackOffice.Middleware if (cookieOptions == null) throw new InvalidOperationException("No cookie options found with name " + Constants.Security.BackOfficeAuthenticationType); - //If we've gotten this far it means a preview cookie has been set and a front-end umbraco document request is executing. + // If we've gotten this far it means a preview cookie has been set and a front-end umbraco document request is executing. // In this case, authentication will not have occurred for an Umbraco back office User, however we need to perform the authentication // for the user here so that the preview capability can be authorized otherwise only the non-preview page will be rendered. if (request.Cookies.TryGetValue(cookieOptions.Cookie.Name, out var cookie)) @@ -55,7 +55,7 @@ namespace Umbraco.Web.BackOffice.Middleware { var backOfficeIdentity = unprotected.Principal.GetUmbracoIdentity(); if (backOfficeIdentity != null) - //Ok, we've got a real ticket, now we can add this ticket's identity to the current + // Ok, we've got a real ticket, now we can add this ticket's identity to the current // Principal, this means we'll have 2 identities assigned to the principal which we can // use to authorize the preview and allow for a back office User. diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs deleted file mode 100644 index 44896016cd..0000000000 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Services; -using Umbraco.Extensions; -using Umbraco.Web.BackOffice.Controllers; -using Umbraco.Web.BackOffice.Filters; -using Umbraco.Web.BackOffice.Middleware; -using Umbraco.Web.BackOffice.Routing; -using Umbraco.Web.BackOffice.Security; -using Umbraco.Web.BackOffice.Services; -using Umbraco.Web.BackOffice.Trees; -using Umbraco.Web.Common.Runtime; - -namespace Umbraco.Web.BackOffice.Runtime -{ - [ComposeBefore(typeof(ICoreComposer))] - [ComposeAfter(typeof(AspNetCoreComposer))] - public class BackOfficeComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // register back office trees - // the collection builder only accepts types inheriting from TreeControllerBase - // and will filter out those that are not attributed with TreeAttribute - var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); - builder.Trees() - .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); - - builder.ComposeWebMappingProfiles(); - - builder.Services.AddUnique(factory => - { - var path = "~/"; - var hostingEnvironment = factory.GetRequiredService(); - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - hostingEnvironment.MapPathContentRoot(path), - hostingEnvironment.ToAbsolute(path) - ); - }); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs index 2b9370fedd..000740e27e 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -46,13 +46,13 @@ namespace Umbraco.Web.BackOffice.Trees IControllerFactory controllerFactory, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider ) - { + { _treeService = treeService; _sectionService = sectionService; _localizedTextService = localizedTextService; _controllerFactory = controllerFactory; _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; - } + } /// /// Returns the tree nodes for an application @@ -62,7 +62,7 @@ namespace Umbraco.Web.BackOffice.Trees /// /// Tree use. /// - public async Task GetApplicationTrees(string application, string tree, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormCollection queryStrings, TreeUse use = TreeUse.Main) + public async Task GetApplicationTrees(string application, string tree, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormCollection queryStrings, TreeUse use = TreeUse.Main) { application = application.CleanForXss(); @@ -165,7 +165,8 @@ namespace Umbraco.Web.BackOffice.Trees /// private async Task TryGetRootNode(Tree tree, FormCollection querystring) { - if (tree == null) throw new ArgumentNullException(nameof(tree)); + if (tree == null) + throw new ArgumentNullException(nameof(tree)); try { @@ -185,7 +186,8 @@ namespace Umbraco.Web.BackOffice.Trees /// private async Task GetTreeRootNode(Tree tree, int id, FormCollection querystring) { - if (tree == null) throw new ArgumentNullException(nameof(tree)); + if (tree == null) + throw new ArgumentNullException(nameof(tree)); var children = await GetChildren(tree, id, querystring); var rootNode = await GetRootNode(tree, querystring); @@ -214,9 +216,10 @@ namespace Umbraco.Web.BackOffice.Trees /// private async Task GetRootNode(Tree tree, FormCollection querystring) { - if (tree == null) throw new ArgumentNullException(nameof(tree)); + if (tree == null) + throw new ArgumentNullException(nameof(tree)); - var controller = (TreeControllerBase) await GetApiControllerProxy(tree.TreeControllerType, "GetRootNode", querystring); + var controller = (TreeControllerBase)await GetApiControllerProxy(tree.TreeControllerType, "GetRootNode", querystring); var rootNode = controller.GetRootNode(querystring); if (rootNode == null) throw new InvalidOperationException($"Failed to get root node for tree \"{tree.TreeAlias}\"."); @@ -228,7 +231,8 @@ namespace Umbraco.Web.BackOffice.Trees /// private async Task GetChildren(Tree tree, int id, FormCollection querystring) { - if (tree == null) throw new ArgumentNullException(nameof(tree)); + if (tree == null) + throw new ArgumentNullException(nameof(tree)); // the method we proxy has an 'id' parameter which is *not* in the querystring, // we need to add it for the proxy to work (else, it does not find the method, @@ -237,7 +241,7 @@ namespace Umbraco.Web.BackOffice.Trees d["id"] = StringValues.Empty; var proxyQuerystring = new FormCollection(d); - var controller = (TreeControllerBase) await GetApiControllerProxy(tree.TreeControllerType, "GetNodes", proxyQuerystring); + var controller = (TreeControllerBase)await GetApiControllerProxy(tree.TreeControllerType, "GetNodes", proxyQuerystring); return controller.GetNodes(id.ToInvariantString(), querystring); } @@ -267,7 +271,7 @@ namespace Umbraco.Web.BackOffice.Trees }); if (!(querystring is null)) { - foreach (var (key,value) in querystring) + foreach (var (key, value) in querystring) { routeData.Values[key] = value; } @@ -281,11 +285,11 @@ namespace Umbraco.Web.BackOffice.Trees var actionContext = new ActionContext(HttpContext, routeData, actionDescriptor); var proxyControllerContext = new ControllerContext(actionContext); - var controller = (TreeController) _controllerFactory.CreateController(proxyControllerContext); + var controller = (TreeController)_controllerFactory.CreateController(proxyControllerContext); - var isAllowed = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(actionContext); - if (!isAllowed) - throw new HttpResponseException(HttpStatusCode.Forbidden); + var isAllowed = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(actionContext); + if (!isAllowed) + throw new HttpResponseException(HttpStatusCode.Forbidden); return controller; } diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 16dd446d49..404ebfdb3a 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -22,6 +22,7 @@ using Microsoft.Extensions.Options; using Umbraco.Web.Trees; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 8b5286bdd2..25c48b94bd 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index ab2bfdb8d4..30389fb1be 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -16,6 +16,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index ece4013d0b..d284624999 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -22,6 +22,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index cd64e23067..424a0b2451 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -15,6 +15,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs index 395b242b56..4d2d23f8bd 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs @@ -22,6 +22,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs index be400bef39..8a8fe7b11e 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Attributes; diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs index b648bd797f..a5707968ee 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs @@ -1,11 +1,8 @@ -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Umbraco.Core.IO; using Umbraco.Core.Services; -using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Authorization; -using Umbraco.Web.Composing; -using Umbraco.Web.Mvc; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Constants = Umbraco.Core.Constants; diff --git a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs index 361875a41b..eb08dbe629 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Extensions; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Filters; diff --git a/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs index e469cd4a25..ad4266e5e5 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.Trees; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Filters; diff --git a/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs b/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs index 42d23b33b3..5a9e3ff90d 100644 --- a/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs +++ b/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs @@ -1,10 +1,10 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Umbraco.Web.Common.ModelBinding; using System.Linq; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Actions; using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.ModelBinders; namespace Umbraco.Web.Common.ApplicationModels { diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs index 57ad83d4ba..93347ddaa0 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs @@ -13,10 +13,11 @@ namespace Umbraco.Web.Common.AspNetCore private readonly ConcurrentDictionary _registeredObjects = new ConcurrentDictionary(); + /// + /// Initializes a new instance of the class. + /// public AspNetCoreApplicationShutdownRegistry(IHostApplicationLifetime hostApplicationLifetime) - { - _hostApplicationLifetime = hostApplicationLifetime; - } + => _hostApplicationLifetime = hostApplicationLifetime; public void RegisterObject(IRegisteredObject registeredObject) { @@ -43,17 +44,11 @@ namespace Umbraco.Web.Common.AspNetCore { private readonly IRegisteredObject _inner; - public RegisteredObjectWrapper(IRegisteredObject inner) - { - _inner = inner; - } + public RegisteredObjectWrapper(IRegisteredObject inner) => _inner = inner; public CancellationTokenRegistration CancellationTokenRegistration { get; set; } - public void Stop(bool immediate) - { - _inner.Stop(immediate); - } + public void Stop(bool immediate) => _inner.Stop(immediate); } } } diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs index 38d78860b0..cdba8273a0 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs @@ -1,36 +1,24 @@ using System; -using System.Threading; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; -using Umbraco.Net; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Common.AspNetCore { public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime, IUmbracoApplicationLifetimeManager { - private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostApplicationLifetime _hostApplicationLifetime; - public AspNetCoreUmbracoApplicationLifetime(IHttpContextAccessor httpContextAccessor, IHostApplicationLifetime hostApplicationLifetime) + public AspNetCoreUmbracoApplicationLifetime(IHostApplicationLifetime hostApplicationLifetime) { - _httpContextAccessor = httpContextAccessor; _hostApplicationLifetime = hostApplicationLifetime; } public bool IsRestarting { get; set; } + public void Restart() { IsRestarting = true; - - var httpContext = _httpContextAccessor.HttpContext; - if (httpContext != null) - { - // unload app domain - we must null out all identities otherwise we get serialization errors - // http://www.zpqrtbnk.net/posts/custom-iidentity-serialization-issue - httpContext.User = null; - } - - Thread.CurrentPrincipal = null; _hostApplicationLifetime.StopApplication(); } @@ -38,6 +26,8 @@ namespace Umbraco.Web.Common.AspNetCore { ApplicationInit?.Invoke(this, EventArgs.Empty); } + + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications public event EventHandler ApplicationInit; } } diff --git a/src/Umbraco.Web.Common/AspNetCore/UmbracoMvcConfigureOptions.cs b/src/Umbraco.Web.Common/AspNetCore/UmbracoMvcConfigureOptions.cs new file mode 100644 index 0000000000..6c8420cd03 --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/UmbracoMvcConfigureOptions.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.ModelBinders; + +namespace Umbraco.Web.Common.AspNetCore +{ + /// + /// Options for globally configuring MVC for Umbraco + /// + /// + /// We generally don't want to change the global MVC settings since we want to be unobtrusive as possible but some + /// global mods are needed - so long as they don't interfere with normal user usages of MVC. + /// + public class UmbracoMvcConfigureOptions : IConfigureOptions + { + /// + public void Configure(MvcOptions options) + { + options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); + } + } +} diff --git a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs index 4b8f730e45..3afc8978b6 100644 --- a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs @@ -1,10 +1,11 @@ -using System; +using System; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -16,9 +17,11 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Web.Common.ModelBinders; +using Umbraco.Web.Models; namespace Umbraco.Web.Common.AspNetCore { + // TODO: Should be in Views namespace? public abstract class UmbracoViewPage : UmbracoViewPage { @@ -27,23 +30,44 @@ namespace Umbraco.Web.Common.AspNetCore public abstract class UmbracoViewPage : RazorPage { - private IUmbracoContext _umbracoContext; + private IUmbracoContextAccessor UmbracoContextAccessor => Context.RequestServices.GetRequiredService(); + private GlobalSettings GlobalSettings => Context.RequestServices.GetRequiredService>().Value; + private ContentSettings ContentSettings => Context.RequestServices.GetRequiredService>().Value; + private IProfilerHtml ProfilerHtml => Context.RequestServices.GetRequiredService(); + private IIOHelper IOHelper => Context.RequestServices.GetRequiredService(); + private ContentModelBinder ContentModelBinder => new ContentModelBinder(); + /// + /// Gets the + /// protected IUmbracoContext UmbracoContext => _umbracoContext ??= UmbracoContextAccessor.UmbracoContext; + /// + public override ViewContext ViewContext + { + get => base.ViewContext; + set + { + // Here we do the magic model swap + ViewContext ctx = value; + ctx.ViewData = BindViewData(ctx.ViewData); + base.ViewContext = ctx; + } + } + /// public override void Write(object value) { if (value is IHtmlEncodedString htmlEncodedString) { - base.WriteLiteral(htmlEncodedString.ToHtmlString()); + WriteLiteral(htmlEncodedString.ToHtmlString()); } else { @@ -51,10 +75,12 @@ namespace Umbraco.Web.Common.AspNetCore } } + /// public override void WriteLiteral(object value) { // filter / add preview banner - if (Context.Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value + // ASP.NET default value is text/html + if (Context.Response.ContentType.InvariantEquals("text/html")) { if (UmbracoContext.IsDebug || UmbracoContext.InPreviewMode) { @@ -69,7 +95,8 @@ namespace Umbraco.Web.Common.AspNetCore { // creating previewBadge markup markupToInject = - string.Format(ContentSettings.PreviewBadge, + string.Format( + ContentSettings.PreviewBadge, IOHelper.ResolveUrl(GlobalSettings.UmbracoPath), Context.Request.GetEncodedUrl(), UmbracoContext.PublishedRequest.PublishedContent.Id); @@ -83,7 +110,7 @@ namespace Umbraco.Web.Common.AspNetCore var sb = new StringBuilder(text); sb.Insert(pos, markupToInject); - base.WriteLiteral(sb.ToString()); + WriteLiteral(sb.ToString()); return; } } @@ -92,70 +119,93 @@ namespace Umbraco.Web.Common.AspNetCore base.WriteLiteral(value); } - // maps model - protected async Task SetViewDataAsync(ViewDataDictionary viewData) + /// + /// Dynamically binds the incoming to the required + /// + /// + /// This is used in order to provide the ability for an Umbraco view to either have a model of type + /// or . This will use the to bind the models + /// to the correct output type. + /// + protected ViewDataDictionary BindViewData(ViewDataDictionary viewData) { + // check if it's already the correct type and continue if it is + if (viewData is ViewDataDictionary vdd) + { + return vdd; + } + + // Here we hand the default case where we know the incoming model is ContentModel and the + // outgoing model is IPublishedContent. This is a fast conversion that doesn't require doing the full + // model binding, allocating classes, etc... + if (viewData.ModelMetadata.ModelType == typeof(ContentModel) + && typeof(TModel) == typeof(IPublishedContent)) + { + var contentModel = (ContentModel)viewData.Model; + viewData.Model = contentModel.Content; + return viewData; + } + // capture the model before we tinker with the viewData var viewDataModel = viewData.Model; // map the view data (may change its type, may set model to null) - viewData = MapViewDataDictionary(viewData, typeof (TModel)); + viewData = MapViewDataDictionary(viewData, typeof(TModel)); // bind the model var bindingContext = new DefaultModelBindingContext(); - await ContentModelBinder.BindModelAsync(bindingContext, viewDataModel, typeof (TModel)); + ContentModelBinder.BindModel(bindingContext, viewDataModel, typeof(TModel)); viewData.Model = bindingContext.Result.Model; - // set the view data - ViewData = (ViewDataDictionary) viewData; + // return the new view data + return (ViewDataDictionary)viewData; } - - // viewData is the ViewDataDictionary (maybe ) that we have // modelType is the type of the model that we need to bind to - // // figure out whether viewData can accept modelType else replace it - // private static ViewDataDictionary MapViewDataDictionary(ViewDataDictionary viewData, Type modelType) { - var viewDataType = viewData.GetType(); - + Type viewDataType = viewData.GetType(); if (viewDataType.IsGenericType) { // ensure it is the proper generic type - var def = viewDataType.GetGenericTypeDefinition(); + Type def = viewDataType.GetGenericTypeDefinition(); if (def != typeof(ViewDataDictionary<>)) + { throw new Exception("Could not map viewData of type \"" + viewDataType.FullName + "\"."); + } // get the viewData model type and compare with the actual view model type: // viewData is ViewDataDictionary and we will want to assign an // object of type modelType to the Model property of type viewDataModelType, we // need to check whether that is possible - var viewDataModelType = viewDataType.GenericTypeArguments[0]; + Type viewDataModelType = viewDataType.GenericTypeArguments[0]; if (viewDataModelType.IsAssignableFrom(modelType)) + { return viewData; + } } // if not possible or it is not generic then we need to create a new ViewDataDictionary - var nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType); + Type nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType); var tViewData = new ViewDataDictionary(viewData) { Model = null }; // temp view data to copy values var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData); return nViewData; } - public HtmlString RenderSection(string name, HtmlString defaultContents) - { - return RazorPageExtensions.RenderSection(this, name, defaultContents); - } + /// + /// Renders a section with default content if the section isn't defined + /// + public HtmlString RenderSection(string name, HtmlString defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); - public HtmlString RenderSection(string name, string defaultContents) - { - return RazorPageExtensions.RenderSection(this, name, defaultContents); - } + /// + /// Renders a section with default content if the section isn't defined + /// + public HtmlString RenderSection(string name, string defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); } } diff --git a/src/Umbraco.Web.Common/Controllers/IRenderController.cs b/src/Umbraco.Web.Common/Controllers/IRenderController.cs index 7534abc9b4..26a1286afa 100644 --- a/src/Umbraco.Web.Common/Controllers/IRenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/IRenderController.cs @@ -1,9 +1,11 @@ -namespace Umbraco.Web.Mvc +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Common.Controllers { /// /// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking /// - public interface IRenderController + public interface IRenderController : IDiscoverable { } diff --git a/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs b/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs deleted file mode 100644 index 8727918bf4..0000000000 --- a/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Umbraco.Core.Composing; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Mvc -{ - /// - /// The interface that must be implemented for a controller to be designated to execute for route hijacking - /// - public interface IRenderMvcController : IRenderController, IDiscoverable - { - /// - /// The default action to render the front-end view - /// - /// - /// - IActionResult Index(ContentModel model); - } -} diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs index b95859ccbe..099dfd59cd 100644 --- a/src/Umbraco.Web.Common/Controllers/RenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs @@ -1,10 +1,99 @@ -using Microsoft.AspNetCore.Mvc; -using Umbraco.Web.Mvc; +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.Extensions.Logging; +using Umbraco.Core; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.Routing; +using Umbraco.Web.Models; +using Umbraco.Web.Routing; namespace Umbraco.Web.Common.Controllers { - public abstract class RenderController : Controller, IRenderController - { + /// + /// Represents the default front-end rendering controller. + /// + [ModelBindingException] + public class RenderController : UmbracoController, IRenderController + { + private readonly ILogger _logger; + private readonly ICompositeViewEngine _compositeViewEngine; + private UmbracoRouteValues _umbracoRouteValues; + + /// + /// Initializes a new instance of the class. + /// + public RenderController(ILogger logger, ICompositeViewEngine compositeViewEngine) + { + _logger = logger; + _compositeViewEngine = compositeViewEngine; + } + + /// + /// Gets the current content item. + /// + protected IPublishedContent CurrentPage => UmbracoRouteValues.PublishedContent; + + /// + /// Gets the + /// + protected UmbracoRouteValues UmbracoRouteValues + { + get + { + if (_umbracoRouteValues != null) + { + return _umbracoRouteValues; + } + + if (!ControllerContext.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var def)) + { + throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}"); + } + + _umbracoRouteValues = (UmbracoRouteValues)def; + return _umbracoRouteValues; + } + } + + /// + /// Ensures that a physical view file exists on disk. + /// + /// The view name. + protected bool EnsurePhsyicalViewExists(string template) + { + ViewEngineResult result = _compositeViewEngine.FindView(ControllerContext, template, false); + if (result.View != null) + { + return true; + } + + _logger.LogWarning("No physical template file was found for template {Template}", template); + return false; + } + + /// + /// Gets an action result based on the template name found in the route values and a model. + /// + /// The type of the model. + /// The model. + /// The action result. + /// If the template found in the route values doesn't physically exist and exception is thrown + protected IActionResult CurrentTemplate(T model) + { + if (EnsurePhsyicalViewExists(UmbracoRouteValues.TemplateName) == false) + { + throw new InvalidOperationException("No physical template file was found for template " + UmbracoRouteValues.TemplateName); + } + + return View(UmbracoRouteValues.TemplateName, model); + } + + /// + /// The default action to render the front-end view. + /// + public virtual IActionResult Index() => CurrentTemplate(new ContentModel(CurrentPage)); } } diff --git a/src/Umbraco.Web.Common/Controllers/UmbracoController.cs b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs index 50ec620741..22bef0da69 100644 --- a/src/Umbraco.Web.Common/Controllers/UmbracoController.cs +++ b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs @@ -1,14 +1,7 @@ -using System; +using System; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Services; -using Umbraco.Web.Security; -namespace Umbraco.Web.Mvc +namespace Umbraco.Web.Common.Controllers { /// /// Provides a base class for Umbraco controllers. diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/ServiceCollectionExtensions.cs similarity index 67% rename from src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs rename to src/Umbraco.Web.Common/DependencyInjection/ServiceCollectionExtensions.cs index 2b077fe840..dd7eda895e 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,37 +1,22 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Web.Caching; using SixLabors.ImageSharp.Web.Commands; using SixLabors.ImageSharp.Web.DependencyInjection; using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; -using Smidge; -using Smidge.Nuglify; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.Models.Validation; -using Umbraco.Web.Common.ApplicationModels; -namespace Umbraco.Extensions +namespace Umbraco.Web.Common.DependencyInjection { - public static class UmbracoWebServiceCollectionExtensions + public static class ServiceCollectionExtensions { - - - /// /// Adds Image Sharp with Umbraco settings /// - /// - /// - /// public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IConfiguration configuration) { var imagingSettings = configuration.GetSection(Core.Constants.Configuration.ConfigImaging) @@ -50,7 +35,7 @@ namespace Umbraco.Extensions return Task.CompletedTask; }; - options.OnBeforeSaveAsync = _ => Task.CompletedTask; + options.OnBeforeSaveAsync = _ => Task.CompletedTask; options.OnProcessedAsync = _ => Task.CompletedTask; options.OnPrepareResponseAsync = _ => Task.CompletedTask; }) @@ -70,7 +55,6 @@ namespace Umbraco.Extensions return services; } - private static void RemoveIntParamenterIfValueGreatherThen(IDictionary commands, string parameter, int maxValue) { if (commands.TryGetValue(parameter, out var command)) @@ -84,30 +68,5 @@ namespace Umbraco.Extensions } } } - - /// - /// Options for globally configuring MVC for Umbraco - /// - /// - /// We generally don't want to change the global MVC settings since we want to be unobtrusive as possible but some - /// global mods are needed - so long as they don't interfere with normal user usages of MVC. - /// - public class UmbracoMvcConfigureOptions : IConfigureOptions - { - - // TODO: we can inject params with DI here - public UmbracoMvcConfigureOptions() - { - } - - // TODO: we can configure global mvc options here if we need to - public void Configure(MvcOptions options) - { - - } - } - - } - } diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs similarity index 57% rename from src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs rename to src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index e72089b8fe..a2dde620b9 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,13 +1,14 @@ using System; +using System.Collections.Generic; using System.Data.Common; using System.Data.SqlClient; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; @@ -25,28 +26,53 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; +using Umbraco.Core.Security; using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.HostedServices; using Umbraco.Infrastructure.HostedServices.ServerRegistration; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Infrastructure.Runtime; +using Umbraco.Net; +using Umbraco.Web.Cache; using Umbraco.Web.Common.ApplicationModels; using Umbraco.Web.Common.AspNetCore; -using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Common.DependencyInjection; +using Umbraco.Web.Common.Install; +using Umbraco.Web.Common.Lifetime; +using Umbraco.Web.Common.Macros; +using Umbraco.Web.Common.Middleware; using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.Common.Profiler; +using Umbraco.Web.Common.Routing; +using Umbraco.Web.Common.Security; +using Umbraco.Web.Common.Templates; +using Umbraco.Web.Macros; +using Umbraco.Web.Security; using Umbraco.Web.Telemetry; +using Umbraco.Web.Templates; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; -namespace Umbraco.Core.DependencyInjection +namespace Umbraco.Web.Common.DependencyInjection { // TODO: We could add parameters to configure each of these for flexibility + + /// + /// Extension methods for for the common Umbraco functionality + /// public static class UmbracoBuilderExtensions { + /// + /// Creates an and registers basic Umbraco services + /// public static IUmbracoBuilder AddUmbraco( this IServiceCollection services, IWebHostEnvironment webHostEnvironment, @@ -64,7 +90,7 @@ namespace Umbraco.Core.DependencyInjection IHostingEnvironment tempHostingEnvironment = GetTemporaryHostingEnvironment(webHostEnvironment, config); - var loggingDir = tempHostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.LogFiles); + var loggingDir = tempHostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.LogFiles); var loggingConfig = new LoggingConfiguration(loggingDir); services.AddLogger(tempHostingEnvironment, loggingConfig, config); @@ -74,10 +100,10 @@ namespace Umbraco.Core.DependencyInjection var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); var appCaches = AppCaches.Create(requestCache); - services.AddUnique(appCaches); + services.AddUnique(appCaches); IProfiler profiler = GetWebProfiler(config); - services.AddUnique(profiler); + services.AddUnique(profiler); ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); TypeLoader typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, tempHostingEnvironment, loggerFactory, appCaches, config, profiler); @@ -85,18 +111,29 @@ namespace Umbraco.Core.DependencyInjection return new UmbracoBuilder(services, config, typeLoader, loggerFactory); } - /// Composes Composers + /// + /// Adds core Umbraco services + /// + /// + /// This will not add any composers/components + /// public static IUmbracoBuilder AddUmbracoCore(this IUmbracoBuilder builder) { if (builder is null) + { throw new ArgumentNullException(nameof(builder)); + } - builder.Services.AddLazySupport(); + // Add ASP.NET specific services + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddHostedService(factory => factory.GetRequiredService()); // Add supported databases builder.AddUmbracoSqlCeSupport(); builder.AddUmbracoSqlServerSupport(); + // Must be added here because DbProviderFactories is netstandard 2.1 so cannot exist in Infra for now builder.Services.AddSingleton(factory => new DbProviderFactoryCreator( DbProviderFactories.GetFactory, factory.GetServices(), @@ -104,102 +141,18 @@ namespace Umbraco.Core.DependencyInjection factory.GetServices() )); - builder.Services.AddUnique(factory => - { - var globalSettings = factory.GetRequiredService>().Value; - var connectionStrings = factory.GetRequiredService>().Value; - var hostingEnvironment = factory.GetRequiredService(); + builder.AddCoreInitialServices(); - var dbCreator = factory.GetRequiredService(); - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var loggerFactory = factory.GetRequiredService(); - - return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment) - : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); - }); - - builder.Services.AddUnique(factory => - { - var hostingEnvironment = factory.GetRequiredService(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return new IOHelperLinux(hostingEnvironment); - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return new IOHelperOSX(hostingEnvironment); - } - - return new IOHelperWindows(hostingEnvironment); - } - - ); - builder.Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); - builder.Services.AddUnique(factory => factory.GetRequiredService().RequestCache); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(factory => factory.GetRequiredService().CreateDatabase()); - builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.AddComposers(); + // aspnet app lifetime mgmt + builder.Services.AddMultipleUnique(); + builder.Services.AddUnique(); return builder; } - public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) - { - var composerTypes = builder.TypeLoader.GetTypes(); - var enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); - new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); - - return builder; - } - - public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder) - { - // Register configuration validators. - builder.Services.AddSingleton, ContentSettingsValidator>(); - builder.Services.AddSingleton, GlobalSettingsValidator>(); - builder.Services.AddSingleton, HealthChecksSettingsValidator>(); - builder.Services.AddSingleton, RequestHandlerSettingsValidator>(); - - // Register configuration sections. - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigActiveDirectory)); - builder.Services.Configure(builder.Config.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigContent)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigCoreDebug)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExceptionFilter)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHealthChecks)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHosting)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigImaging)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExamine)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigKeepAlive)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigLogging)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigMemberPassword)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigNuCache)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRequestHandler)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntime)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigSecurity)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTours)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigUserPassword)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigWebRouting)); - - return builder; - } - - + /// + /// Add Umbraco hosted services + /// public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder) { builder.Services.AddHostedService(); @@ -213,40 +166,43 @@ namespace Umbraco.Core.DependencyInjection return builder; } - public static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) + private static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) { builder.Services.AddHttpClient(); return builder; } + /// + /// Adds mini profiler services for Umbraco + /// public static IUmbracoBuilder AddMiniProfiler(this IUmbracoBuilder builder) { builder.Services.AddMiniProfiler(options => - { - options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile - }); + + // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile + options.ShouldProfile = request => false); return builder; } - public static IUmbracoBuilder AddMvcAndRazor(this IUmbracoBuilder builder, Action mvcOptions = null, Action mvcBuilding = null) + public static IUmbracoBuilder AddMvcAndRazor(this IUmbracoBuilder builder, Action mvcBuilding = null) { // TODO: We need to figure out if we can work around this because calling AddControllersWithViews modifies the global app and order is very important // this will directly affect developers who need to call that themselves. - //We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. - //But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. - var mvcBuilder = builder.Services.AddControllersWithViews(options => - { - options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + // We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. + // But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. + IMvcBuilder mvcBuilder = builder.Services + .AddControllersWithViews() + .AddRazorRuntimeCompilation(); - options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); - mvcOptions?.Invoke(options); - }).AddRazorRuntimeCompilation(); mvcBuilding?.Invoke(mvcBuilder); return builder; } + /// + /// Add runtime minifier support for Umbraco + /// public static IUmbracoBuilder AddRuntimeMinifier(this IUmbracoBuilder builder) { builder.Services.AddSmidge(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification)); @@ -255,6 +211,9 @@ namespace Umbraco.Core.DependencyInjection return builder; } + /// + /// Adds all web based services required for Umbraco to run + /// public static IUmbracoBuilder AddWebComponents(this IUmbracoBuilder builder) { // Add service session @@ -266,17 +225,68 @@ namespace Umbraco.Core.DependencyInjection options.Cookie.HttpOnly = true; }); - builder.Services.ConfigureOptions(); + builder.Services.ConfigureOptions(); builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); builder.Services.AddUmbracoImageSharp(builder.Config); + // AspNetCore specific services + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // The umbraco request lifetime + builder.Services.AddMultipleUnique(); + + // Password hasher + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddTransient(); + builder.Services.AddUnique(); + + builder.Services.AddMultipleUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // register the umbraco context factory + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.WithCollectionBuilder() + .Add(umbracoApiControllerTypes); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.AddHttpClients(); + + // TODO: Does this belong in web components?? + builder.AddNuCache(); + return builder; } + // TODO: Does this need to exist and/or be public? public static IUmbracoBuilder AddWebServer(this IUmbracoBuilder builder) { - // TODO: We need to figure out why thsi is needed and fix those endpoints to not need them, we don't want to change global things + // TODO: We need to figure out why this is needed and fix those endpoints to not need them, we don't want to change global things // If using Kestrel: https://stackoverflow.com/a/55196057 builder.Services.Configure(options => { @@ -353,7 +363,7 @@ namespace Umbraco.Core.DependencyInjection { // should let it be null, that's how MiniProfiler is meant to work, // but our own IProfiler expects an instance so let's get one - return new VoidProfiler(); + return new NoopProfiler(); } var webProfiler = new WebProfiler(); diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index caf4132664..5dee7d10e1 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -1,75 +1,121 @@ using System; +using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Serilog.Context; +using SixLabors.ImageSharp.Web.DependencyInjection; using Smidge; using Smidge.Nuglify; using StackExchange.Profiling; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Infrastructure.Logging.Serilog.Enrichers; using Umbraco.Web.Common.Middleware; +using Umbraco.Web.Common.Plugins; namespace Umbraco.Extensions { + /// + /// extensions for Umbraco + /// public static class ApplicationBuilderExtensions { /// - /// Returns true if Umbraco is greater than + /// Configures and use services required for using Umbraco /// - /// - /// - public static bool UmbracoCanBoot(this IApplicationBuilder app) + public static IApplicationBuilder UseUmbraco(this IApplicationBuilder app) { - var runtime = app.ApplicationServices.GetRequiredService(); - // can't continue if boot failed - return runtime.State.Level > RuntimeLevel.BootFailed; + // TODO: Should we do some checks like this to verify that the corresponding "Add" methods have been called for the + // corresponding "Use" methods? + // https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Mvc/Mvc.Core/src/Builder/MvcApplicationBuilderExtensions.cs#L132 + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + app.UseUmbracoCore(); + app.UseUmbracoRequestLogging(); + + // We need to add this before UseRouting so that the UmbracoContext and other middlewares are executed + // before endpoint routing middleware. + app.UseUmbracoRouting(); + + app.UseStatusCodePages(); + + // Important we handle image manipulations before the static files, otherwise the querystring is just ignored. + // TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoBackOffice too? + app.UseImageSharp(); + app.UseStaticFiles(); + app.UseUmbracoPlugins(); + + // UseRouting adds endpoint routing middleware, this means that middlewares registered after this one + // will execute after endpoint routing. The ordering of everything is quite important here, see + // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-5.0 + // where we need to have UseAuthentication and UseAuthorization proceeding this call but before + // endpoints are defined. + app.UseRouting(); + app.UseRequestLocalization(); + app.UseAuthentication(); + app.UseAuthorization(); + + // Must be called after UseRouting and before UseEndpoints + app.UseSession(); + + // Must come after the above! + app.UseUmbracoInstaller(); + + return app; } /// - /// Start Umbraco + /// Returns true if Umbraco is greater than + /// + public static bool UmbracoCanBoot(this IApplicationBuilder app) + { + var state = app.ApplicationServices.GetRequiredService(); + + // can't continue if boot failed + return state.Level > RuntimeLevel.BootFailed; + } + + /// + /// Enables core Umbraco functionality /// - /// - /// public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } - if (!app.UmbracoCanBoot()) return app; - - var hostingEnvironment = app.ApplicationServices.GetRequiredService(); - AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Core.Constants.SystemDirectories.Data)); - - var runtime = app.ApplicationServices.GetRequiredService(); - - // Register a listener for application shutdown in order to terminate the runtime - var hostLifetime = app.ApplicationServices.GetRequiredService(); - var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime); - hostLifetime.RegisterObject(runtimeShutdown); + if (!app.UmbracoCanBoot()) + { + return app; + } // Register our global threadabort enricher for logging - var threadAbortEnricher = app.ApplicationServices.GetRequiredService(); + ThreadAbortExceptionEnricher threadAbortEnricher = app.ApplicationServices.GetRequiredService(); LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context - StaticApplicationLogging.Initialize(app.ApplicationServices.GetRequiredService()); - - // Start the runtime! - runtime.Start(); - return app; } /// /// Enables middlewares required to run Umbraco /// - /// - /// - // TODO: Could be internal or part of another call - this is a required system so should't be 'opt-in' + /// + /// Must occur before UseRouting + /// public static IApplicationBuilder UseUmbracoRouting(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + // TODO: This method could be internal or part of another call - this is a required system so should't be 'opt-in' + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } if (!app.UmbracoCanBoot()) { @@ -79,11 +125,6 @@ namespace Umbraco.Extensions { app.UseMiddleware(); app.UseMiddleware(); - - // TODO: Both of these need to be done before any endpoints but after UmbracoRequestMiddleware - // because they rely on an UmbracoContext. But should they be here? - app.UseAuthentication(); - app.UseAuthorization(); } return app; @@ -92,11 +133,12 @@ namespace Umbraco.Extensions /// /// Adds request based serilog enrichers to the LogContext for each request /// - /// - /// public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } if (!app.UmbracoCanBoot()) return app; @@ -108,13 +150,17 @@ namespace Umbraco.Extensions /// /// Enables runtime minification for Umbraco /// - /// - /// public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } - if (!app.UmbracoCanBoot()) return app; + if (!app.UmbracoCanBoot()) + { + return app; + } app.UseSmidge(); app.UseSmidgeNuglify(); @@ -122,31 +168,27 @@ namespace Umbraco.Extensions return app; } - /// - /// Ensures the runtime is shutdown when the application is shutting down - /// - private class CoreRuntimeShutdown : IRegisteredObject + public static IApplicationBuilder UseUmbracoPlugins(this IApplicationBuilder app) { - public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime) + var hostingEnvironment = app.ApplicationServices.GetRequiredService(); + var umbracoPluginSettings = app.ApplicationServices.GetRequiredService>(); + + var pluginFolder = hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins); + + // Ensure the plugin folder exists + Directory.CreateDirectory(pluginFolder); + + var fileProvider = new UmbracoPluginPhysicalFileProvider( + pluginFolder, + umbracoPluginSettings); + + app.UseStaticFiles(new StaticFileOptions { - _runtime = runtime; - _hostLifetime = hostLifetime; - } + FileProvider = fileProvider, + RequestPath = Constants.SystemDirectories.AppPlugins + }); - private bool _completed = false; - private readonly IRuntime _runtime; - private readonly IApplicationShutdownRegistry _hostLifetime; - - public void Stop(bool immediate) - { - if (!_completed) - { - _completed = true; - _runtime.Terminate(); - _hostLifetime.UnregisterObject(this); - } - - } + return app; } } diff --git a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs index 69fae56d32..fe61941e5c 100644 --- a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Net; using System.Text; @@ -18,27 +18,20 @@ namespace Umbraco.Extensions /// /// Check if a preview cookie exist /// - /// - /// public static bool HasPreviewCookie(this HttpRequest request) - { - return request.Cookies.TryGetValue(Constants.Web.PreviewCookieName, out var cookieVal) && !cookieVal.IsNullOrWhiteSpace(); - } + => request.Cookies.TryGetValue(Constants.Web.PreviewCookieName, out var cookieVal) && !cookieVal.IsNullOrWhiteSpace(); public static bool IsBackOfficeRequest(this HttpRequest request, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) - { - return new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsBackOfficeRequest(globalSettings, hostingEnvironment); - } + => new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsBackOfficeRequest(globalSettings, hostingEnvironment); public static bool IsClientSideRequest(this HttpRequest request) - { - return new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest(); - } + => new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest(); + + public static bool IsDefaultBackOfficeRequest(this HttpRequest request, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + => new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsDefaultBackOfficeRequest(globalSettings, hostingEnvironment); public static string ClientCulture(this HttpRequest request) - { - return request.Headers.TryGetValue("X-UMB-CULTURE", out var values) ? values[0] : null; - } + => request.Headers.TryGetValue("X-UMB-CULTURE", out var values) ? values[0] : null; /// /// Determines if a request is local. diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs index f2babdb07c..6bfa402154 100644 --- a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -9,7 +9,6 @@ using Umbraco.Web.Common.Install; using Umbraco.Core.Hosting; using System.Linq.Expressions; using Umbraco.Web.Common.Controllers; -using System.Linq; namespace Umbraco.Extensions { diff --git a/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs index 884e2bbdbc..d6c3fb5715 100644 --- a/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs @@ -1,19 +1,24 @@ -using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Razor; namespace Umbraco.Extensions { + /// + /// Extension methods for + /// public static class RazorPageExtensions { + /// + /// Renders a section with default content if the section isn't defined + /// public static HtmlString RenderSection(this RazorPage webPage, string name, HtmlString defaultContents) - { - return webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : defaultContents; - } + => webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : defaultContents; + /// + /// Renders a section with default content if the section isn't defined + /// public static HtmlString RenderSection(this RazorPage webPage, string name, string defaultContents) - { - return webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : new HtmlString(defaultContents); - } + => webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : new HtmlString(defaultContents); } } diff --git a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index e8e3e2c329..0000000000 --- a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Web.BackOffice.Authorization; -using Umbraco.Web.Common.Authorization; - -namespace Umbraco.Extensions -{ - public static class ServiceCollectionExtensions - { - public static void AddUmbracoCommonAuthorizationPolicies(this IServiceCollection services) - { - // TODO: Should this only exist in the back office project? These really are only ever used for the back office AFAIK - // If it is moved it should only target the back office scheme - - services.AddSingleton(); - - services.AddAuthorization(options => - { - options.AddPolicy(AuthorizationPolicies.UmbracoFeatureEnabled, policy => - policy.Requirements.Add(new FeatureAuthorizeRequirement())); - }); - } - } - -} diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index f42fc274f0..4161cafd91 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -7,10 +7,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Serilog; using Serilog.Extensions.Hosting; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Runtime; diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs index 3350af756e..ac5d787911 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs @@ -1,30 +1,31 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Umbraco.Web.Common.Install; namespace Umbraco.Extensions { + /// + /// extensions for Umbraco installer + /// public static class UmbracoInstallApplicationBuilderExtensions { /// /// Enables the Umbraco installer /// - /// - /// public static IApplicationBuilder UseUmbracoInstaller(this IApplicationBuilder app) { - if (!app.UmbracoCanBoot()) return app; + if (!app.UmbracoCanBoot()) + { + return app; + } app.UseEndpoints(endpoints => { - var installerRoutes = app.ApplicationServices.GetRequiredService(); + InstallAreaRoutes installerRoutes = app.ApplicationServices.GetRequiredService(); installerRoutes.CreateRoutes(endpoints); }); return app; } - - } - } diff --git a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs index 360396fe04..c53c367689 100644 --- a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Umbraco.Web.Common.Constants; using Umbraco.Web.Common.Controllers; -using Umbraco.Web.Mvc; namespace Umbraco.Web.Common.Filters { @@ -35,13 +34,18 @@ namespace Umbraco.Web.Common.Filters /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still /// render any PartialViewMacro with a form and maintain ModelState /// - /// public override void OnActionExecuting(ActionExecutingContext context) { - if (!(context.Controller is Controller controller)) return; + if (!(context.Controller is Controller controller)) + { + return; + } - //ignore anything that is not IRenderController - if (!(controller is IRenderController)) return; + // ignore anything that is not IRenderController + if (!(controller is IRenderController)) + { + return; + } SetViewContext(context, controller); } @@ -54,10 +58,16 @@ namespace Umbraco.Web.Common.Filters /// The filter context. public override void OnResultExecuting(ResultExecutingContext context) { - if (!(context.Controller is Controller controller)) return; + if (!(context.Controller is Controller controller)) + { + return; + } - //ignore anything that is not IRenderController - if (!(controller is RenderController)) return; + // ignore anything that is not IRenderController + if (!(controller is IRenderController)) + { + return; + } SetViewContext(context, controller); } @@ -72,16 +82,13 @@ namespace Umbraco.Web.Common.Filters new StringWriter(), new HtmlHelperOptions()); - //set the special data token + // set the special data token context.RouteData.DataTokens[ViewConstants.DataTokenCurrentViewContext] = viewCtx; } private class DummyView : IView { - public Task RenderAsync(ViewContext context) - { - return Task.CompletedTask; - } + public Task RenderAsync(ViewContext context) => Task.CompletedTask; public string Path { get; } } diff --git a/src/Umbraco.Web.Common/Filters/JsonDateTimeFormatAttribute.cs b/src/Umbraco.Web.Common/Filters/JsonDateTimeFormatAttribute.cs index 9c9496b282..edf8489f12 100644 --- a/src/Umbraco.Web.Common/Filters/JsonDateTimeFormatAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/JsonDateTimeFormatAttribute.cs @@ -1,4 +1,4 @@ -using System.Buffers; +using System.Buffers; using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -13,27 +13,28 @@ namespace Umbraco.Web.Common.Filters /// /// Applying this attribute to any controller will ensure that it only contains one json formatter compatible with the angular json vulnerability prevention. /// - public class JsonDateTimeFormatAttribute : TypeFilterAttribute + public sealed class JsonDateTimeFormatAttribute : TypeFilterAttribute { - public JsonDateTimeFormatAttribute() : base(typeof(JsonDateTimeFormatFilter)) - { - Order = 2; //must be higher than AngularJsonOnlyConfigurationAttribute.Order - } + /// + /// Initializes a new instance of the class. + /// + public JsonDateTimeFormatAttribute() + : base(typeof(JsonDateTimeFormatFilter)) => + Order = 2; // must be higher than AngularJsonOnlyConfigurationAttribute.Order private class JsonDateTimeFormatFilter : IResultFilter { private readonly string _format = "yyyy-MM-dd HH:mm:ss"; - private readonly IOptions _mvcNewtonsoftJsonOptions; private readonly ArrayPool _arrayPool; private readonly IOptions _options; - public JsonDateTimeFormatFilter(IOptions mvcNewtonsoftJsonOptions, ArrayPool arrayPool, IOptions options) + public JsonDateTimeFormatFilter(ArrayPool arrayPool, IOptions options) { - _mvcNewtonsoftJsonOptions = mvcNewtonsoftJsonOptions; _arrayPool = arrayPool; _options = options; } + public void OnResultExecuted(ResultExecutedContext context) { } diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs new file mode 100644 index 0000000000..6e9d6d29a7 --- /dev/null +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs @@ -0,0 +1,88 @@ +using System; +using System.Net; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.ModelBinders; + +namespace Umbraco.Web.Common.Filters +{ + /// + /// An exception filter checking if we get a or with the same model. + /// In which case it returns a redirect to the same page after 1 sec if not in debug mode. + /// + /// + /// This is only enabled when running PureLive + /// + public sealed class ModelBindingExceptionAttribute : TypeFilterAttribute + { + /// + /// Initializes a new instance of the class. + /// + public ModelBindingExceptionAttribute() + : base(typeof(ModelBindingExceptionFilter)) + { + } + + private class ModelBindingExceptionFilter : IExceptionFilter + { + private static readonly Regex s_getPublishedModelsTypesRegex = new Regex("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); + + private readonly ExceptionFilterSettings _exceptionFilterSettings; + private readonly IPublishedModelFactory _publishedModelFactory; + + public ModelBindingExceptionFilter(IOptions exceptionFilterSettings, IPublishedModelFactory publishedModelFactory) + { + _exceptionFilterSettings = exceptionFilterSettings.Value; + _publishedModelFactory = publishedModelFactory ?? throw new ArgumentNullException(nameof(publishedModelFactory)); + } + + public void OnException(ExceptionContext filterContext) + { + var disabled = _exceptionFilterSettings?.Disabled ?? false; + if (_publishedModelFactory.IsLiveFactory() + && !disabled + && !filterContext.ExceptionHandled + && (filterContext.Exception is ModelBindingException || filterContext.Exception is InvalidCastException) + && IsMessageAboutTheSameModelType(filterContext.Exception.Message)) + { + filterContext.HttpContext.Response.Headers.Add(HttpResponseHeader.RetryAfter.ToString(), "1"); + filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.GetEncodedUrl(), false); + + filterContext.ExceptionHandled = true; + } + } + + /// + /// Returns true if the message is about two models with the same name. + /// + /// + /// Message could be something like: + /// + /// InvalidCastException: + /// [A]Umbraco.Web.PublishedModels.Home cannot be cast to [B]Umbraco.Web.PublishedModels.Home. Type A originates from 'App_Web_all.generated.cs.8f9494c4.rtdigm_z, Version=0.0.0.3, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Users\User\AppData\Local\Temp\Temporary ASP.NET Files\root\c5c63f4d\c168d9d4\App_Web_all.generated.cs.8f9494c4.rtdigm_z.dll'. Type B originates from 'App_Web_all.generated.cs.8f9494c4.rbyqlplu, Version=0.0.0.5, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Users\User\AppData\Local\Temp\Temporary ASP.NET Files\root\c5c63f4d\c168d9d4\App_Web_all.generated.cs.8f9494c4.rbyqlplu.dll'. + /// + /// + /// ModelBindingException: + /// Cannot bind source content type Umbraco.Web.PublishedModels.Home to model type Umbraco.Web.PublishedModels.Home. Both view and content models are PureLive, with different versions. The application is in an unstable state and is going to be restarted. The application is restarting now. + /// + /// + private bool IsMessageAboutTheSameModelType(string exceptionMessage) + { + MatchCollection matches = s_getPublishedModelsTypesRegex.Matches(exceptionMessage); + + if (matches.Count >= 2) + { + return string.Equals(matches[0].Value, matches[1].Value, StringComparison.InvariantCulture); + } + + return false; + } + } + } +} diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs deleted file mode 100644 index 6cec04e0b6..0000000000 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Net; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Common.ModelBinders; - -namespace Umbraco.Web.Common.Filters -{ - /// - /// An exception filter checking if we get a or with the same model. - /// In which case it returns a redirect to the same page after 1 sec if not in debug mode. - /// - /// - /// This is only enabled when running PureLive - /// - public class ModelBindingExceptionFilter : ActionFilterAttribute, IExceptionFilter - { - private static readonly Regex _getPublishedModelsTypesRegex = new Regex("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); - - private readonly ExceptionFilterSettings _exceptionFilterSettings; - private readonly IPublishedModelFactory _publishedModelFactory; - - public ModelBindingExceptionFilter(IOptions exceptionFilterSettings, IPublishedModelFactory publishedModelFactory) - { - _exceptionFilterSettings = exceptionFilterSettings.Value; - _publishedModelFactory = publishedModelFactory ?? throw new ArgumentNullException(nameof(publishedModelFactory)); - } - - public void OnException(ExceptionContext filterContext) - { - var disabled = _exceptionFilterSettings?.Disabled ?? false; - if (_publishedModelFactory.IsLiveFactory() - && !disabled - && !filterContext.ExceptionHandled - && ((filterContext.Exception is ModelBindingException || filterContext.Exception is InvalidCastException) - && IsMessageAboutTheSameModelType(filterContext.Exception.Message))) - { - filterContext.HttpContext.Response.Headers.Add(HttpResponseHeader.RetryAfter.ToString(), "1"); - filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.GetEncodedUrl(), false); - - filterContext.ExceptionHandled = true; - } - } - - /// - /// Returns true if the message is about two models with the same name. - /// - /// - /// Message could be something like: - /// - /// InvalidCastException: - /// [A]Umbraco.Web.PublishedModels.Home cannot be cast to [B]Umbraco.Web.PublishedModels.Home. Type A originates from 'App_Web_all.generated.cs.8f9494c4.rtdigm_z, Version=0.0.0.3, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Users\User\AppData\Local\Temp\Temporary ASP.NET Files\root\c5c63f4d\c168d9d4\App_Web_all.generated.cs.8f9494c4.rtdigm_z.dll'. Type B originates from 'App_Web_all.generated.cs.8f9494c4.rbyqlplu, Version=0.0.0.5, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Users\User\AppData\Local\Temp\Temporary ASP.NET Files\root\c5c63f4d\c168d9d4\App_Web_all.generated.cs.8f9494c4.rbyqlplu.dll'. - /// - /// - /// ModelBindingException: - /// Cannot bind source content type Umbraco.Web.PublishedModels.Home to model type Umbraco.Web.PublishedModels.Home. Both view and content models are PureLive, with different versions. The application is in an unstable state and is going to be restarted. The application is restarting now. - /// - /// - private bool IsMessageAboutTheSameModelType(string exceptionMessage) - { - var matches = _getPublishedModelsTypesRegex.Matches(exceptionMessage); - - if (matches.Count >= 2) - { - return string.Equals(matches[0].Value, matches[1].Value, StringComparison.InvariantCulture); - } - - return false; - } - } -} diff --git a/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs deleted file mode 100644 index 2ba58a8fd7..0000000000 --- a/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Umbraco.Web.Common.Events; - -namespace Umbraco.Web.Common.Filters -{ - public class PreRenderViewActionFilterAttribute : ActionFilterAttribute - { - public override void OnActionExecuted(ActionExecutedContext context) - { - if (!(context.Controller is Controller umbController) || !(context.Result is ViewResult result)) - { - return; - } - - var model = result.Model; - if (model == null) - { - return; - } - - var args = new ActionExecutedEventArgs(umbController, model); - OnActionExecuted(args); - - if (args.Model != model) - { - result.ViewData.Model = args.Model; - } - - base.OnActionExecuted(context); - } - - - public static event EventHandler ActionExecuted; - - private static void OnActionExecuted(ActionExecutedEventArgs e) - { - var handler = ActionExecuted; - handler?.Invoke(null, e); - } - } -} diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs index 8c32796ad8..6deecc2ce5 100644 --- a/src/Umbraco.Web.Common/Install/InstallApiController.cs +++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs @@ -7,9 +7,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; -using Umbraco.Net; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index c79c5229fc..9a9e46eefc 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -38,7 +38,7 @@ namespace Umbraco.Web.Macros private readonly IHttpContextAccessor _httpContextAccessor; public MacroRenderer( - IProfilingLogger profilingLogger , + IProfilingLogger profilingLogger, ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, @@ -53,7 +53,7 @@ namespace Umbraco.Web.Macros IRequestAccessor requestAccessor, IHttpContextAccessor httpContextAccessor) { - _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger )); + _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger)); _logger = logger; _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _backOfficeSecurityAccessor = backOfficeSecurityAccessor; @@ -111,12 +111,14 @@ namespace Umbraco.Web.Macros private MacroContent GetMacroContentFromCache(MacroModel model) { // only if cache is enabled - if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return null; + if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) + return null; var cache = _appCaches.RuntimeCache; var macroContent = cache.GetCacheItem(CacheKeys.MacroContentCacheKey + model.CacheIdentifier); - if (macroContent == null) return null; + if (macroContent == null) + return null; _logger.LogDebug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier); @@ -145,16 +147,19 @@ namespace Umbraco.Web.Macros private void AddMacroContentToCache(MacroModel model, MacroContent macroContent) { // only if cache is enabled - if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return; + if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) + return; // just make sure... - if (macroContent == null) return; + if (macroContent == null) + return; // do not cache if it should cache by member and there's not member if (model.CacheByMember) { var key = _memberUserKeyProvider.GetMemberProviderUserKey(); - if (key is null) return; + if (key is null) + return; } // remember when we cache the content @@ -184,10 +189,12 @@ namespace Umbraco.Web.Macros private FileInfo GetMacroFile(MacroModel model) { var filename = GetMacroFileName(model); - if (filename == null) return null; + if (filename == null) + return null; var mapped = _hostingEnvironment.MapPathContentRoot(filename); - if (mapped == null) return null; + if (mapped == null) + return null; var file = new FileInfo(mapped); return file.Exists ? file : null; @@ -223,7 +230,8 @@ namespace Umbraco.Web.Macros private MacroContent Render(MacroModel macro, IPublishedContent content) { - if (content == null) throw new ArgumentNullException(nameof(content)); + if (content == null) + throw new ArgumentNullException(nameof(content)); var macroInfo = $"Render Macro: {macro.Name}, cache: {macro.CacheDuration}"; using (_profilingLogger.DebugDuration(macroInfo, "Rendered Macro.")) @@ -328,7 +336,8 @@ namespace Umbraco.Web.Macros /// should not be cached. In that case the attempt may also contain an exception. private Attempt ExecuteMacroOfType(MacroModel model, IPublishedContent content) { - if (model == null) throw new ArgumentNullException(nameof(model)); + if (model == null) + throw new ArgumentNullException(nameof(model)); // ensure that we are running against a published node (ie available in XML) // that may not be the case if the macro is embedded in a RTE of an unpublished document @@ -356,7 +365,7 @@ namespace Umbraco.Web.Macros /// The text output of the macro execution. private MacroContent ExecutePartialView(MacroModel macro, IPublishedContent content) { - var engine = new PartialViewMacroEngine(_umbracoContextAccessor, _httpContextAccessor, _hostingEnvironment); + var engine = new PartialViewMacroEngine(_httpContextAccessor, _hostingEnvironment); return engine.Execute(macro, content); } diff --git a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs index db1658e962..790e437148 100644 --- a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Text.Encodings.Web; @@ -27,56 +27,71 @@ namespace Umbraco.Web.Common.Macros { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostingEnvironment _hostingEnvironment; - private readonly Func _getUmbracoContext; + //private readonly Func _getUmbracoContext; public PartialViewMacroEngine( - IUmbracoContextAccessor umbracoContextAccessor, + //IUmbracoContextAccessor umbracoContextAccessor, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment) { _httpContextAccessor = httpContextAccessor; _hostingEnvironment = hostingEnvironment; - _getUmbracoContext = () => - { - var context = umbracoContextAccessor.UmbracoContext; - if (context == null) - throw new InvalidOperationException( - $"The {GetType()} cannot execute with a null UmbracoContext.Current reference."); - return context; - }; + //_getUmbracoContext = () => + //{ + // var context = umbracoContextAccessor.UmbracoContext; + // if (context == null) + // { + // throw new InvalidOperationException( + // $"The {GetType()} cannot execute with a null UmbracoContext.Current reference."); + // } + + // return context; + //}; } - public bool Validate(string code, string tempFileName, IPublishedContent currentPage, out string errorMessage) - { - var temp = GetVirtualPathFromPhysicalPath(tempFileName); - try - { - CompileAndInstantiate(temp); - } - catch (Exception exception) - { - errorMessage = exception.Message; - return false; - } + //public bool Validate(string code, string tempFileName, IPublishedContent currentPage, out string errorMessage) + //{ + // var temp = GetVirtualPathFromPhysicalPath(tempFileName); + // try + // { + // CompileAndInstantiate(temp); + // } + // catch (Exception exception) + // { + // errorMessage = exception.Message; + // return false; + // } - errorMessage = string.Empty; - return true; - } + // errorMessage = string.Empty; + // return true; + //} public MacroContent Execute(MacroModel macro, IPublishedContent content) { - if (macro == null) throw new ArgumentNullException(nameof(macro)); - if (content == null) throw new ArgumentNullException(nameof(content)); + if (macro == null) + { + throw new ArgumentNullException(nameof(macro)); + } + + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + if (string.IsNullOrWhiteSpace(macro.MacroSource)) + { throw new ArgumentException("The MacroSource property of the macro object cannot be null or empty"); + } var httpContext = _httpContextAccessor.GetRequiredHttpContext(); - var umbCtx = _getUmbracoContext(); + //var umbCtx = _getUmbracoContext(); var routeVals = new RouteData(); routeVals.Values.Add("controller", "PartialViewMacro"); routeVals.Values.Add("action", "Index"); - routeVals.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); //required for UmbracoViewPage + + //TODO: Was required for UmbracoViewPage need to figure out if we still need that, i really don't think this is necessary + //routeVals.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); var modelMetadataProvider = httpContext.RequestServices.GetRequiredService(); var tempDataProvider = httpContext.RequestServices.GetRequiredService(); @@ -109,6 +124,7 @@ namespace Umbraco.Web.Common.Macros return new MacroContent { Text = output }; } + private class FakeView : IView { /// @@ -120,29 +136,30 @@ namespace Umbraco.Web.Common.Macros /// public string Path { get; } = "View"; } - private string GetVirtualPathFromPhysicalPath(string physicalPath) - { - var rootpath = _hostingEnvironment.MapPathContentRoot("~/"); - physicalPath = physicalPath.Replace(rootpath, ""); - physicalPath = physicalPath.Replace("\\", "/"); - return "~/" + physicalPath; - } - private static PartialViewMacroPage CompileAndInstantiate(string virtualPath) - { - // //Compile Razor - We Will Leave This To ASP.NET Compilation Engine & ASP.NET WebPages - // //Security in medium trust is strict around here, so we can only pass a virtual file path - // //ASP.NET Compilation Engine caches returned types - // //Changed From BuildManager As Other Properties Are Attached Like Context Path/ - // var webPageBase = WebPageBase.CreateInstanceFromVirtualPath(virtualPath); - // var webPage = webPageBase as PartialViewMacroPage; - // if (webPage == null) - // throw new InvalidCastException("All Partial View Macro views must inherit from " + typeof(PartialViewMacroPage).FullName); - // return webPage; + //private string GetVirtualPathFromPhysicalPath(string physicalPath) + //{ + // var rootpath = _hostingEnvironment.MapPathContentRoot("~/"); + // physicalPath = physicalPath.Replace(rootpath, ""); + // physicalPath = physicalPath.Replace("\\", "/"); + // return "~/" + physicalPath; + //} - //TODO? How to check this - return null; - } + //private static PartialViewMacroPage CompileAndInstantiate(string virtualPath) + //{ + // // //Compile Razor - We Will Leave This To ASP.NET Compilation Engine & ASP.NET WebPages + // // //Security in medium trust is strict around here, so we can only pass a virtual file path + // // //ASP.NET Compilation Engine caches returned types + // // //Changed From BuildManager As Other Properties Are Attached Like Context Path/ + // // var webPageBase = WebPageBase.CreateInstanceFromVirtualPath(virtualPath); + // // var webPage = webPageBase as PartialViewMacroPage; + // // if (webPage == null) + // // throw new InvalidCastException("All Partial View Macro views must inherit from " + typeof(PartialViewMacroPage).FullName); + // // return webPage; + + // //TODO? How to check this + // return null; + //} } } diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index e274e479b7..0474f2445c 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -1,15 +1,15 @@ -using System; +using System; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; -using Umbraco.Web.Common.Lifetime; using Umbraco.Core; -using Umbraco.Core.Logging; -using System.Threading; using Umbraco.Core.Cache; -using System.Collections.Generic; -using Umbraco.Core.Security; +using Umbraco.Core.Logging; +using Umbraco.Web.Common.Lifetime; +using Umbraco.Web.PublishedCache.NuCache; namespace Umbraco.Web.Common.Middleware { @@ -18,7 +18,12 @@ namespace Umbraco.Web.Common.Middleware /// Manages Umbraco request objects and their lifetime /// /// + /// + /// This is responsible for initializing the content cache + /// + /// /// This is responsible for creating and assigning an + /// /// public class UmbracoRequestMiddleware : IMiddleware { @@ -27,21 +32,31 @@ namespace Umbraco.Web.Common.Middleware private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly IRequestCache _requestCache; private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory; + private readonly PublishedSnapshotServiceEventHandler _publishedSnapshotServiceEventHandler; + private static bool s_cacheInitialized = false; + private static bool s_cacheInitializedFlag = false; + private static object s_cacheInitializedLock = new object(); + /// + /// Initializes a new instance of the class. + /// public UmbracoRequestMiddleware( ILogger logger, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager, IUmbracoContextFactory umbracoContextFactory, IRequestCache requestCache, - IBackOfficeSecurityFactory backofficeSecurityFactory) + IBackOfficeSecurityFactory backofficeSecurityFactory, + PublishedSnapshotServiceEventHandler publishedSnapshotServiceEventHandler) { _logger = logger; _umbracoRequestLifetimeManager = umbracoRequestLifetimeManager; _umbracoContextFactory = umbracoContextFactory; _requestCache = requestCache; _backofficeSecurityFactory = backofficeSecurityFactory; + _publishedSnapshotServiceEventHandler = publishedSnapshotServiceEventHandler; } + /// public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute); @@ -52,16 +67,20 @@ namespace Umbraco.Web.Common.Middleware await next(context); return; } - _backofficeSecurityFactory.EnsureBackOfficeSecurity(); // Needs to be before UmbracoContext - var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); + EnsureContentCacheInitialized(); + + _backofficeSecurityFactory.EnsureBackOfficeSecurity(); // Needs to be before UmbracoContext, TODO: Why? + UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); + + bool isFrontEndRequest = umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest(); try { - if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) + if (isFrontEndRequest) { - LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); - _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); + LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache); + _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); } try @@ -87,7 +106,7 @@ namespace Umbraco.Web.Common.Middleware } finally { - if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) + if (isFrontEndRequest) { LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); @@ -107,16 +126,15 @@ namespace Umbraco.Web.Common.Middleware /// /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request /// - /// - /// - /// private static void DisposeRequestCacheItems(ILogger logger, IRequestCache requestCache, Uri requestUri) { // do not process if client-side request if (requestUri.IsClientSideRequest()) + { return; + } - //get a list of keys to dispose + // get a list of keys to dispose var keys = new HashSet(); foreach (var i in requestCache) { @@ -125,7 +143,7 @@ namespace Umbraco.Web.Common.Middleware keys.Add(i.Key); } } - //dispose each item and key that was found as disposable. + // dispose each item and key that was found as disposable. foreach (var k in keys) { try @@ -147,6 +165,17 @@ namespace Umbraco.Web.Common.Middleware } } - + /// + /// Initializes the content cache one time + /// + private void EnsureContentCacheInitialized() => LazyInitializer.EnsureInitialized( + ref s_cacheInitialized, + ref s_cacheInitializedFlag, + ref s_cacheInitializedLock, + () => + { + _publishedSnapshotServiceEventHandler.Initialize(); + return true; + }); } } diff --git a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs index 113f411c6f..d747a4ff86 100644 --- a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs +++ b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs @@ -1,40 +1,33 @@ -using System; +using System; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ModelBinding; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.Routing; using Umbraco.Web.Models; namespace Umbraco.Web.Common.ModelBinders { /// - /// Maps view models, supporting mapping to and from any IPublishedContent or IContentModel. + /// Maps view models, supporting mapping to and from any or . /// public class ContentModelBinder : IModelBinder { + /// public Task BindModelAsync(ModelBindingContext bindingContext) { - if (bindingContext.ActionContext.RouteData.DataTokens.TryGetValue(Core.Constants.Web.UmbracoDataToken, out var source) == false) + // Although this model binder is built to work both ways between IPublishedContent and IContentModel in reality + // only IPublishedContent will ever exist in the request so when this model binder is used as an IModelBinder + // in the aspnet pipeline it will really only support converting from IPublishedContent which is contained + // in the UmbracoRouteValues --> IContentModel + if (!bindingContext.ActionContext.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var source) + || !(source is UmbracoRouteValues umbracoRouteValues)) { return Task.CompletedTask; } - // This model binder deals with IContentModel and IPublishedContent by extracting the model from the route's - // datatokens. This data token is set in 2 places: RenderRouteHandler, UmbracoVirtualNodeRouteHandler - // and both always set the model to an instance of `ContentModel`. - - // No need for type checks to ensure we have the appropriate binder, as in .NET Core this is handled in the provider, - // in this case ContentModelBinderProvider. - - // Being defensive though.... if for any reason the model is not either IContentModel or IPublishedContent, - // then we return since those are the only types this binder is dealing with. - if (source is IContentModel == false && source is IPublishedContent == false) - { - return Task.CompletedTask; - } - - BindModelAsync(bindingContext, source, bindingContext.ModelType); + BindModel(bindingContext, umbracoRouteValues.PublishedContent, bindingContext.ModelType); return Task.CompletedTask; } @@ -45,33 +38,42 @@ namespace Umbraco.Web.Common.ModelBinders // { ContentModel, ContentModel, IPublishedContent } // to // { ContentModel, ContentModel, IPublishedContent } - // - public Task BindModelAsync(ModelBindingContext bindingContext, object source, Type modelType) + + /// + /// Attempts to bind the model + /// + public void BindModel(ModelBindingContext bindingContext, object source, Type modelType) { // Null model, return if (source == null) { - return Task.CompletedTask; + return; } // If types already match, return - var sourceType = source.GetType(); - if (sourceType. Inherits(modelType)) // includes == + Type sourceType = source.GetType(); + if (sourceType.Inherits(modelType)) { bindingContext.Result = ModelBindingResult.Success(source); - return Task.CompletedTask; + return; } // Try to grab the content var sourceContent = source as IPublishedContent; // check if what we have is an IPublishedContent if (sourceContent == null && sourceType.Implements()) + { // else check if it's an IContentModel, and get the content sourceContent = ((IContentModel)source).Content; + } + if (sourceContent == null) { // else check if we can convert it to a content - var attempt1 = source.TryConvertTo(); - if (attempt1.Success) sourceContent = attempt1.Result; + Attempt attempt1 = source.TryConvertTo(); + if (attempt1.Success) + { + sourceContent = attempt1.Result; + } } // If we have a content @@ -86,41 +88,41 @@ namespace Umbraco.Web.Common.ModelBinders } bindingContext.Result = ModelBindingResult.Success(sourceContent); - return Task.CompletedTask; + return; } // If model is ContentModel, create and return if (modelType == typeof(ContentModel)) { bindingContext.Result = ModelBindingResult.Success(new ContentModel(sourceContent)); - return Task.CompletedTask; + return; } // If model is ContentModel, check content type, then create and return if (modelType.IsGenericType && modelType.GetGenericTypeDefinition() == typeof(ContentModel<>)) { - var targetContentType = modelType.GetGenericArguments()[0]; + Type targetContentType = modelType.GetGenericArguments()[0]; if (sourceContent.GetType().Inherits(targetContentType) == false) { ThrowModelBindingException(true, true, sourceContent.GetType(), targetContentType); } bindingContext.Result = ModelBindingResult.Success(Activator.CreateInstance(modelType, sourceContent)); - return Task.CompletedTask; + return; } } // Last chance : try to convert - var attempt2 = source.TryConvertTo(modelType); + Attempt attempt2 = source.TryConvertTo(modelType); if (attempt2.Success) { bindingContext.Result = ModelBindingResult.Success(attempt2.Result); - return Task.CompletedTask; + return; } // Fail ThrowModelBindingException(false, false, sourceType, modelType); - return Task.CompletedTask; + return; } private void ThrowModelBindingException(bool sourceContent, bool modelContent, Type sourceType, Type modelType) @@ -129,11 +131,19 @@ namespace Umbraco.Web.Common.ModelBinders // prepare message msg.Append("Cannot bind source"); - if (sourceContent) msg.Append(" content"); + if (sourceContent) + { + msg.Append(" content"); + } + msg.Append(" type "); msg.Append(sourceType.FullName); msg.Append(" to model"); - if (modelContent) msg.Append(" content"); + if (modelContent) + { + msg.Append(" content"); + } + msg.Append(" type "); msg.Append(modelType.FullName); msg.Append("."); @@ -141,7 +151,6 @@ namespace Umbraco.Web.Common.ModelBinders // raise event, to give model factories a chance at reporting // the error with more details, and optionally request that // the application restarts. - var args = new ModelBindingArgs(sourceType, modelType, msg); ModelBindingException?.Invoke(this, args); diff --git a/src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs b/src/Umbraco.Web.Common/ModelBinders/UmbracoJsonModelBinder.cs similarity index 96% rename from src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs rename to src/Umbraco.Web.Common/ModelBinders/UmbracoJsonModelBinder.cs index 7ec61656fb..7069344bda 100644 --- a/src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs +++ b/src/Umbraco.Web.Common/ModelBinders/UmbracoJsonModelBinder.cs @@ -1,14 +1,14 @@ -using Microsoft.AspNetCore.Mvc; +using System.Buffers; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; -using System.Buffers; using Umbraco.Web.Common.Formatters; -namespace Umbraco.Web.Common.ModelBinding +namespace Umbraco.Web.Common.ModelBinders { /// /// A custom body model binder that only uses a to bind body action parameters diff --git a/src/Umbraco.Web.Common/Plugins/UmbracoPluginPhysicalFileProvider.cs b/src/Umbraco.Web.Common/Plugins/UmbracoPluginPhysicalFileProvider.cs new file mode 100644 index 0000000000..d62e203cce --- /dev/null +++ b/src/Umbraco.Web.Common/Plugins/UmbracoPluginPhysicalFileProvider.cs @@ -0,0 +1,52 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.IO; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Web.Common.Plugins +{ + /// + /// Looks up files using the on-disk file system and check file extensions are on a allow list + /// + /// + /// When the environment variable "DOTNET_USE_POLLING_FILE_WATCHER" is set to "1" or "true", calls to + /// will use . + /// + public class UmbracoPluginPhysicalFileProvider : PhysicalFileProvider, IFileProvider + { + private readonly IOptions _options; + + /// + /// Initializes a new instance of the class, at the given root directory. + /// + /// The root directory. This should be an absolute path. + /// The configuration options. + /// Specifies which files or directories are excluded. + public UmbracoPluginPhysicalFileProvider(string root, IOptions options, ExclusionFilters filters = ExclusionFilters.Sensitive) + : base(root, filters) => _options = options; + + /// + /// Locate a file at the given path by directly mapping path segments to physical directories. + /// + /// + /// The path needs to pass the and the to be found. + /// + /// A path under the root directory + /// The file information. Caller must check property. + public new IFileInfo GetFileInfo(string subpath) + { + var extension = Path.GetExtension(subpath); + var subPathInclAppPluginsFolder = Path.Combine(Core.Constants.SystemDirectories.AppPlugins, subpath); + if (!_options.Value.BrowsableFileExtensions.Contains(extension)) + { + return new NotFoundFileInfo(subPathInclAppPluginsFolder); + } + + return base.GetFileInfo(subPathInclAppPluginsFolder); + } + } +} diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs index 0c10b7d95a..498b550c1a 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Logging; -using Umbraco.Net; using Umbraco.Web.Common.Lifetime; using Umbraco.Web.Common.Middleware; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Common.Profiler { @@ -31,7 +31,7 @@ namespace Umbraco.Web.Common.Profiler if (_profiler != null) return; // if VoidProfiler was registered, let it be known - if (profiler is VoidProfiler) + if (profiler is NoopProfiler) logger.LogInformation( "Profiler is VoidProfiler, not profiling (must run debug mode to profile)."); _profile = false; diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs index 3c00b0d3bc..eac3e058c2 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs b/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs index b561abc4dd..b01f703016 100644 --- a/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs +++ b/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing; namespace Umbraco.Web.Common.Routing { @@ -11,6 +11,10 @@ namespace Umbraco.Web.Common.Routing // on individual ext methods. This would reduce the amount of code in Startup, but could also mean there's less control over startup // if someone wanted that. Maybe we can just have both. + /// + /// Create routes for an area + /// + /// The endpoint route builder void CreateRoutes(IEndpointRouteBuilder endpoints); } } diff --git a/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs b/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs new file mode 100644 index 0000000000..2ab047a757 --- /dev/null +++ b/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs @@ -0,0 +1,68 @@ +using System; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Extensions; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Common.Routing +{ + /// + /// Represents the data required to route to a specific controller/action during an Umbraco request + /// + public class UmbracoRouteValues + { + /// + /// The default action name + /// + public const string DefaultActionName = nameof(RenderController.Index); + + /// + /// Initializes a new instance of the class. + /// + public UmbracoRouteValues( + IPublishedContent publishedContent, + string controllerName = null, + Type controllerType = null, + string actionName = DefaultActionName, + string templateName = null, + bool hasHijackedRoute = false) + { + ControllerName = controllerName ?? ControllerExtensions.GetControllerName(); + ControllerType = controllerType ?? typeof(RenderController); + PublishedContent = publishedContent; + HasHijackedRoute = hasHijackedRoute; + ActionName = actionName; + TemplateName = templateName; + } + + /// + /// Gets the controller name + /// + public string ControllerName { get; } + + /// + /// Gets the action name + /// + public string ActionName { get; } + + /// + /// Gets the template name + /// + public string TemplateName { get; } + + /// + /// Gets the Controller type found for routing to + /// + public Type ControllerType { get; } + + /// + /// Gets the + /// + public IPublishedContent PublishedContent { get; } + + /// + /// Gets a value indicating whether the current request has a hijacked route/user controller routed for it + /// + public bool HasHijackedRoute { get; } + } +} diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs deleted file mode 100644 index a23f880e7e..0000000000 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Web.Common.Middleware; - -namespace Umbraco.Web.Common.Runtime -{ - /// - /// Executes if the boot fails to ensure critical services are registered - /// - public class AspNetCoreBootFailedComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs index 9309bd7e38..5c7e47cf3f 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs @@ -1,9 +1,9 @@ -using System; +using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Net; +using Umbraco.Core.Hosting; using Umbraco.Web.Common.Lifetime; namespace Umbraco.Web.Common.Runtime diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index f6849215df..1eda1cc23a 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -1,36 +1,4 @@ -using System.Linq; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Diagnostics; -using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; -using Umbraco.Core.Runtime; -using Umbraco.Core.Security; -using Umbraco.Core.Services; -using Umbraco.Extensions; -using Umbraco.Net; -using Umbraco.Web.Common.AspNetCore; -using Umbraco.Web.Common.Controllers; -using Umbraco.Web.Common.Formatters; -using Umbraco.Web.Common.Install; -using Umbraco.Web.Common.Lifetime; -using Umbraco.Web.Common.Macros; -using Umbraco.Web.Common.Middleware; -using Umbraco.Web.Common.ModelBinding; -using Umbraco.Web.Common.Profiler; -using Umbraco.Web.Common.Routing; -using Umbraco.Web.Common.Security; -using Umbraco.Web.Common.Templates; -using Umbraco.Web.Composing.CompositionExtensions; -using Umbraco.Web.Macros; -using Umbraco.Web.Security; -using Umbraco.Web.Templates; - namespace Umbraco.Web.Common.Runtime { @@ -38,66 +6,7 @@ namespace Umbraco.Web.Common.Runtime /// Adds/replaces AspNetCore specific services /// [ComposeBefore(typeof(ICoreComposer))] - [ComposeAfter(typeof(CoreInitialComposer))] public class AspNetCoreComposer : ComponentComposer, IComposer { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - // AspNetCore specific services - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Our own netcore implementations - builder.Services.AddMultipleUnique(); - - builder.Services.AddUnique(); - - // The umbraco request lifetime - builder.Services.AddMultipleUnique(); - - // Password hasher - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddTransient(); - builder.Services.AddUnique(); - - builder.Services.AddMultipleUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // register the umbraco context factory - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - //register the install components - builder.ComposeInstaller(); - - var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); - builder.WithCollectionBuilder() - .Add(umbracoApiControllerTypes); - - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } } } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs index 1058192034..9a097f688b 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs @@ -1,6 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Smidge.FileProcessors; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Runtime; diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index b09fde0a6a..fdc488c65b 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index 97bb9ac7c4..2d22bc5a90 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -110,11 +110,6 @@ namespace Umbraco.Web /// public IDomainCache Domains => PublishedSnapshot.Domains; - /// - /// Boolean value indicating whether the current request is a front-end umbraco request - /// - public bool IsFrontEndUmbracoRequest => PublishedRequest != null; - /// /// Gets/sets the PublishedRequest object /// diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 4df4043861..dfbdbc34d4 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -920,35 +920,35 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha1-Olgr21OATGum0UZXnEblITDPSjs=", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha1-NNxfTKu8cg9OYPdadH5+zWwXW9M=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha1-ARuSAqcKY2bkNspcBlhEUoqwSXY=", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, "@sindresorhus/is": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha1-mgb08TfuhNffBGDB/bETX/psUP0=", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", "dev": true, "optional": true }, @@ -970,13 +970,13 @@ "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, "@types/node": { - "version": "14.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", - "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==", + "version": "14.14.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz", + "integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ==", "dev": true }, "@types/q": { @@ -1593,7 +1593,7 @@ "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha1-t5hCCtvrHego2ErNii4j0+/oXo0=", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "array-uniq": { @@ -1877,7 +1877,7 @@ "bin-build": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", - "integrity": "sha1-xXgKJaip+WbYJEIX5sH1CCoUOGE=", + "integrity": "sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA==", "dev": true, "optional": true, "requires": { @@ -1928,7 +1928,7 @@ "bin-check": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha1-/ElZcL3Ii7HVo1/BfmXEoUn8Skk=", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", "dev": true, "optional": true, "requires": { @@ -1976,7 +1976,7 @@ "bin-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", - "integrity": "sha1-WwnrKAdSsb0o8MnbP5by9DtsCDk=", + "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", "dev": true, "optional": true, "requires": { @@ -1987,7 +1987,7 @@ "bin-version-check": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", - "integrity": "sha1-fYGcYklpkfgNiT5uAqMDI2Fgj3E=", + "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", "dev": true, "optional": true, "requires": { @@ -1999,7 +1999,7 @@ "bin-wrapper": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz", - "integrity": "sha1-mTSPLPhQMePvfvzn5TAK6q6WBgU=", + "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==", "dev": true, "optional": true, "requires": { @@ -2014,7 +2014,7 @@ "download": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", - "integrity": "sha1-kFmqnXC1A+52oTKJe+beyOVYcjM=", + "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", "dev": true, "optional": true, "requires": { @@ -2044,7 +2044,7 @@ "file-type": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", - "integrity": "sha1-JE87fvZBu+DMoZbHJ25LMyOZ9ow=", + "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", "dev": true, "optional": true }, @@ -2058,7 +2058,7 @@ "got": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha1-HSP2Q5Dpf3dsrFLluTbl9RTS6Tc=", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", "dev": true, "optional": true, "requires": { @@ -2093,7 +2093,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "optional": true, "requires": { @@ -2112,14 +2112,14 @@ "p-cancelable": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha1-NfNj1n1SCByNlYXje8zrfgu8sqA=", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", "dev": true, "optional": true }, "p-event": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", - "integrity": "sha1-WWJ57xaassPgyuiMHPuwgHmZPvY=", + "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", "dev": true, "optional": true, "requires": { @@ -2129,7 +2129,7 @@ "p-timeout": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha1-2N0ZeVldLcATnh/ka4tkbLPN8Dg=", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", "dev": true, "optional": true, "requires": { @@ -2139,7 +2139,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "optional": true }, @@ -2204,7 +2204,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -2460,7 +2460,7 @@ "normalize-url": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha1-g1qdoVUfom9w6SMpBpojqmV01+Y=", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", "dev": true, "optional": true, "requires": { @@ -2557,9 +2557,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001162", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001162.tgz", - "integrity": "sha512-E9FktFxaNnp4ky3ucIGzEXLM+Knzlpuq1oN1sFAU0KeayygabGTmOsndpo8QrL4D9pcThlf4D2pUKaDxPCUmVw==", + "version": "1.0.30001168", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", + "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", "dev": true }, "caseless": { @@ -2570,7 +2570,7 @@ "caw": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", - "integrity": "sha1-bDygcfwZRyCIPC3F2psHS/x+npU=", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", "dev": true, "optional": true, "requires": { @@ -2828,8 +2828,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -2843,8 +2843,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3066,8 +3066,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3095,7 +3095,7 @@ "config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, "optional": true, "requires": { @@ -3151,7 +3151,7 @@ "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", "dev": true, "optional": true, "requires": { @@ -3610,7 +3610,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "optional": true, "requires": { @@ -3641,7 +3641,7 @@ "decompress-tar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha1-cYy9P8sWIJcW5womuE57pFkuWvE=", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, "optional": true, "requires": { @@ -3662,7 +3662,7 @@ "decompress-tarbz2": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha1-MIKluIDqQEOBY0nzeLVsUWvho5s=", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, "optional": true, "requires": { @@ -3676,7 +3676,7 @@ "file-type": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha1-5QzXXTVv/tTjBtxPW89Sp5kDqRk=", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", "dev": true, "optional": true } @@ -3685,7 +3685,7 @@ "decompress-targz": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha1-wJvDXE0R894J8tLaU+neI+fOHu4=", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "optional": true, "requires": { @@ -3875,7 +3875,7 @@ "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8=", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { "path-type": "^4.0.0" @@ -3884,7 +3884,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs=", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true } } @@ -3982,7 +3982,7 @@ "download": { "version": "6.2.5", "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", - "integrity": "sha1-rNalQuTNC7Qspwz8mMnkOwcDlxQ=", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", "dev": true, "optional": true, "requires": { @@ -4016,7 +4016,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "optional": true, "requires": { @@ -4068,8 +4068,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -4083,8 +4083,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -4631,7 +4631,7 @@ "exec-buffer": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", - "integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=", + "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==", "dev": true, "optional": true, "requires": { @@ -4705,7 +4705,7 @@ "executable": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha1-QVMr/zYdPlevTXY7cFgtsY9dEzw=", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", "dev": true, "optional": true, "requires": { @@ -4831,7 +4831,7 @@ "ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha1-C5jmTtgvWs8PKTG6v2khLvUt3Tc=", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, "optional": true, "requires": { @@ -4841,7 +4841,7 @@ "ext-name": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha1-cHgZgdGD7hXROZPIgiBFxQbI8KY=", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", "dev": true, "optional": true, "requires": { @@ -4990,7 +4990,7 @@ "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -4999,7 +4999,7 @@ "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -5026,13 +5026,13 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha1-T8sJmb+fvC/L3SEvbWKbmlbDklk=", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { "braces": "^3.0.1", @@ -5048,7 +5048,7 @@ "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -5068,9 +5068,9 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.0.tgz", + "integrity": "sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -5126,7 +5126,7 @@ "filenamify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", - "integrity": "sha1-iPr0lfsbR6v9YSMAACoWIoxnfuk=", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", "dev": true, "optional": true, "requires": { @@ -5476,7 +5476,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, "optional": true }, @@ -6074,7 +6074,7 @@ "get-proxy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", - "integrity": "sha1-NJ8rTZHUTE1NTpy6KtkBQ/rF75M=", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", "dev": true, "optional": true, "requires": { @@ -6222,7 +6222,7 @@ "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "optional": true, "requires": { @@ -6475,7 +6475,7 @@ "got": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", "dev": true, "optional": true, "requires": { @@ -7100,8 +7100,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -7121,8 +7121,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -7321,7 +7321,7 @@ "has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha1-FAn5i8ACR9pF2mfO4KNvKC/yZFU=", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", "dev": true, "optional": true }, @@ -7334,7 +7334,7 @@ "has-to-string-tag-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha1-oEWrOD17SyASoAFIqwql8pAETU0=", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, "optional": true, "requires": { @@ -7476,7 +7476,7 @@ "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", "dev": true, "optional": true }, @@ -7608,7 +7608,7 @@ "imagemin-optipng": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-7.1.0.tgz", - "integrity": "sha1-IiXILDXlwpt/qY1Pns7hFhpo6Ig=", + "integrity": "sha512-JNORTZ6j6untH7e5gF4aWdhDCxe3ODsSLKs/f7Grewy3ebZpl1ZsU+VUTPY4rzeHgaFA8GSWOoA8V2M3OixWZQ==", "dev": true, "optional": true, "requires": { @@ -7741,7 +7741,7 @@ "import-lazy": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz", - "integrity": "sha1-iRJ5ICyKIoD9vWZ029jaGh38Z8w=", + "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==", "dev": true, "optional": true }, @@ -7915,7 +7915,7 @@ "irregular-plurals": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", - "integrity": "sha1-OdQPBbAPZW0Lf6RxIw3TtxSvKHI=", + "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", "dev": true }, "is": { @@ -8098,7 +8098,7 @@ "is-gif": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz", - "integrity": "sha1-xL5gsmowHWlbuDOyDZtdZsbPg7E=", + "integrity": "sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw==", "dev": true, "optional": true, "requires": { @@ -8108,7 +8108,7 @@ "file-type": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", - "integrity": "sha1-KWHQnkZ1ufuaPua2npzSP0P9GJA=", + "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==", "dev": true, "optional": true } @@ -8170,9 +8170,9 @@ "dev": true }, "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", "dev": true, "optional": true }, @@ -8195,7 +8195,7 @@ "is-png": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-png/-/is-png-2.0.0.tgz", - "integrity": "sha1-7oy8npsFBCXO3utKb7dKZJsKSo0=", + "integrity": "sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g==", "dev": true, "optional": true }, @@ -8250,7 +8250,7 @@ "is-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha1-13hIi9CkZmo76KFIK58rqv7eqLQ=", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", "dev": true, "optional": true }, @@ -8352,7 +8352,7 @@ "isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, "optional": true, "requires": { @@ -8520,9 +8520,9 @@ } }, "ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", + "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", "dev": true } } @@ -8590,7 +8590,7 @@ "junk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha1-MUmQmNkCt+mMXZucgPQ0V6iKv6E=", + "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", "dev": true }, "just-debounce": { @@ -8798,7 +8798,7 @@ "keyv": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha1-RJI7o55osSp87H32wyaMAx8u83M=", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", "dev": true, "optional": true, "requires": { @@ -8858,8 +8858,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -8873,8 +8873,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -9249,7 +9249,7 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true, "optional": true }, @@ -9297,7 +9297,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -9489,7 +9489,7 @@ "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true, "optional": true }, @@ -12836,7 +12836,7 @@ "npm-conf": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha1-JWzEe9DiGMJZxOlVC/QTvCGSr/k=", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", "dev": true, "optional": true, "requires": { @@ -13123,7 +13123,7 @@ "optipng-bin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-6.0.0.tgz", - "integrity": "sha1-N2Eg+nnV5x7uL1JBdu/dOl6r0xY=", + "integrity": "sha512-95bB4y8IaTsa/8x6QH4bLUuyvyOoGBCLDA7wOgDL8UFqJpSUh1Hob8JRJhit+wC1ZLN3tQ7mFt7KuBj0x8F2Wg==", "dev": true, "optional": true, "requires": { @@ -13184,7 +13184,7 @@ "os-filter-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha1-HAti1fOiRCdJotE55t3e5ugdjRY=", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", "dev": true, "optional": true, "requires": { @@ -13209,7 +13209,7 @@ "p-cancelable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo=", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", "dev": true, "optional": true }, @@ -13506,7 +13506,7 @@ "plur": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha1-YCZ5Z4ZqjYEVBP5Y8vqrojdUals=", + "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", "dev": true, "requires": { "irregular-plurals": "^2.0.0" @@ -13921,9 +13921,9 @@ "dev": true }, "pretty-bytes": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz", - "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz", + "integrity": "sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==", "dev": true }, "pretty-hrtime": { @@ -14031,7 +14031,7 @@ "query-string": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha1-p4wBK3HBfgXy4/ojGd0zBoLvs8s=", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dev": true, "optional": true, "requires": { @@ -14149,8 +14149,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -14164,8 +14164,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14488,7 +14488,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY=", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, "rfdc": { @@ -14706,7 +14706,7 @@ "semver-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha1-qTwsWERTmncCMzeRB7OMe0rJ0zg=", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", "dev": true, "optional": true }, @@ -15411,7 +15411,7 @@ "strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha1-SYdzYmT8NEzyD2w0rKnRPR1O1sU=", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dev": true, "optional": true, "requires": { @@ -15451,7 +15451,7 @@ "strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", "dev": true, "optional": true, "requires": { @@ -15577,7 +15577,7 @@ "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha1-jqVdqzeXIlPZqa+Q/c1VmuQ1xVU=", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, "optional": true, "requires": { @@ -15679,8 +15679,8 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -15694,8 +15694,8 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -15706,7 +15706,7 @@ "through2-concurrent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/through2-concurrent/-/through2-concurrent-2.0.0.tgz", - "integrity": "sha1-yd0sFGUE7Jli28hqUWi2PWYmafo=", + "integrity": "sha512-R5/jLkfMvdmDD+seLwN7vB+mhbqzWop5fAjx5IX8/yQq7VhBhzDmhXgaHAOnhnWkCpRMM7gToYHycB0CS/pd+A==", "dev": true, "requires": { "through2": "^2.0.0" @@ -15789,7 +15789,7 @@ "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", "dev": true, "optional": true }, diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index 3dfbeade4f..b6f5d99d9f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -42,16 +42,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { return { - allowsCultureVariation: function () { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "AllowsCultureVariation")), - 'Failed to retrieve variant content types'); - }, - - savePermissions: function (saveModel) { + savePermissions: function (saveModel) { if (!saveModel) { throw "saveModel cannot be null"; } diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js index 97bebef062..4a8c65c322 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js @@ -361,6 +361,15 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca "HasContentNodes", [{ id: id }])), 'Failed to retrieve indication for whether content type with id ' + id + ' has associated content nodes'); + }, + + allowsCultureVariation: function () { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "contentTypeApiBaseUrl", + "AllowsCultureVariation")), + 'Failed to retrieve variant content types'); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/navigation.controller.js index a383c2d44a..37f6ff9733 100644 --- a/src/Umbraco.Web.UI.Client/src/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/navigation.controller.js @@ -9,7 +9,7 @@ * * @param {navigationService} navigationService A reference to the navigationService */ -function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource, editorState) { +function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentTypeResource, editorState) { //this is used to trigger the tree to start loading once everything is ready var treeInitPromise = $q.defer(); @@ -380,7 +380,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar */ function loadLanguages() { - return contentResource.allowsCultureVariation().then(function (b) { + return contentTypeResource.allowsCultureVariation().then(function (b) { if (b === true) { return languageResource.getAll(); } else { diff --git a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index d87ca43452..44ff1d1cdf 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -239,9 +239,10 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi // Ask to re-enter preview mode? const localizeVarsFallback = { - "returnToPreviewHeadline": "Preview content?", - "returnToPreviewDescription":"You have ended preview mode, do you want to continue previewing this content?", - "returnToPreviewButton":"Preview" + "returnToPreviewHeadline": "Preview website?", + "returnToPreviewDescription":"You have ended preview mode, do you want to enable it again to view the latest saved version of your website?", + "returnToPreviewAcceptButton":"Preview latest version", + "returnToPreviewDeclineButton":"View published version" }; const umbLocalizedVars = Object.assign(localizeVarsFallback, $window.umbLocalizedVars); @@ -344,10 +345,20 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
${umbLocalizedVars.returnToPreviewDescription}
`; con.appendChild(modal); + var declineButton = document.createElement("button"); + declineButton.type = "button"; + declineButton.innerHTML = umbLocalizedVars.returnToPreviewDeclineButton; + declineButton.addEventListener("click", () => { + bodyEl.removeChild(fragment); + $scope.exitPreview(); + hasPreviewDialog = false; + }); + modal.appendChild(declineButton); + var continueButton = document.createElement("button"); continueButton.type = "button"; continueButton.className = "umbraco-preview-dialog__continue"; - continueButton.innerHTML = umbLocalizedVars.returnToPreviewButton; + continueButton.innerHTML = umbLocalizedVars.returnToPreviewAcceptButton; continueButton.addEventListener("click", () => { bodyEl.removeChild(fragment); reenterPreviewMode(); diff --git a/src/Umbraco.Web.UI.Client/src/views/documentTypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documentTypes/edit.controller.js index e39a36a439..3946d09578 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documentTypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documentTypes/edit.controller.js @@ -176,7 +176,6 @@ hotKeyWhenHidden: true, labelKey: vm.submitButtonKey, letter: "S", - type: "submit", handler: function () { vm.save(); } }; vm.page.subButtons = [{ diff --git a/src/Umbraco.Web.UI.Client/src/views/mediaTypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/mediaTypes/edit.controller.js index fc2b83ea93..ecf2aec30c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediaTypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/mediaTypes/edit.controller.js @@ -190,7 +190,6 @@ hotKeyWhenHidden: true, labelKey: vm.saveButtonKey, letter: "S", - type: "submit", handler: function () { vm.save(); } }; vm.page.subButtons = [{ diff --git a/src/Umbraco.Web.UI.Client/src/views/memberTypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/memberTypes/edit.controller.js index c81de0ec4d..53bb4adb9b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/memberTypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/memberTypes/edit.controller.js @@ -111,7 +111,6 @@ hotKeyWhenHidden: true, labelKey: vm.saveButtonKey, letter: "S", - type: "submit", handler: function () { vm.save(); } }; vm.page.subButtons = [{ diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index de8ad6d1c4..cb9c42e44d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -16,6 +16,7 @@ vm.filesOpen = true; vm.actionsOpen = true; vm.loading = true; + vm.mediaNodeDisplayModels = []; vm.back = back; vm.createOrUpdatePackage = createOrUpdatePackage; vm.removeContentItem = removeContentItem; @@ -28,6 +29,7 @@ vm.contributorsEditor = null; vm.selectDocumentType = selectDocumentType; + vm.selectMediaType = selectMediaType; vm.selectTemplate = selectTemplate; vm.selectStyleSheet = selectStyleSheet; vm.selectMacro = selectMacro; @@ -35,6 +37,15 @@ vm.selectDictionaryItem = selectDictionaryItem; vm.selectDataType = selectDataType; + vm.mediaPickerModel = { + hideLabel: true, + view: "mediapicker", + value: "", + config: { + multiPicker: true, + allowEdit:false + } + } vm.labels = {}; vm.versionRegex = /^(\d+\.)(\d+\.)(\*|\d+)$/; @@ -76,6 +87,7 @@ }); } + vm.mediaPickerModel.value = vm.package.mediaUdis.join(','); }); @@ -88,20 +100,31 @@ function loadResources() { - // Get all document types - entityResource.getAll("DocumentType").then(documentTypes => { - // a package stores the id as a string so we - // need to convert all ids to string for comparison - documentTypes.forEach(documentType => { - documentType.id = documentType.id.toString(); - documentType.selected = vm.package.documentTypes.indexOf(documentType.id) !== -1; - }); - vm.documentTypes = documentTypes; + // Get all document types + entityResource.getAll("DocumentType").then(documentTypes => { + // a package stores the id as a string so we + // need to convert all ids to string for comparison + documentTypes.forEach(documentType => { + documentType.id = documentType.id.toString(); + documentType.selected = vm.package.documentTypes.indexOf(documentType.id) !== -1; }); + vm.documentTypes = documentTypes; + }); + + // Get all media types + entityResource.getAll("MediaType").then(mediaTypes => { + // a package stores the id as a string so we + // need to convert all ids to string for comparison + mediaTypes.forEach(mediaType => { + mediaType.id = mediaType.id.toString(); + mediaType.selected = vm.package.mediaTypes.indexOf(mediaType.id) !== -1; + }); + vm.mediaTypes = mediaTypes; + }); // Get all templates entityResource.getAll("Template").then(templates => { - // a package stores the id as a string so we + // a package stores the id as a string so we // need to convert all ids to string for comparison templates.forEach(template => { template.id = template.id.toString(); @@ -120,7 +143,7 @@ // Get all macros entityResource.getAll("Macro").then(macros => { - // a package stores the id as a string so we + // a package stores the id as a string so we // need to convert all ids to string for comparison macros.forEach(macro => { macro.id = macro.id.toString(); @@ -131,7 +154,7 @@ // Get all languages entityResource.getAll("Language").then(languages => { - // a package stores the id as a string so we + // a package stores the id as a string so we // need to convert all ids to string for comparison languages.forEach(language => { language.id = language.id.toString(); @@ -142,7 +165,7 @@ // Get all dictionary items entityResource.getAll("DictionaryItem").then(dictionaryItems => { - // a package stores the id as a string so we + // a package stores the id as a string so we // need to convert all ids to string for comparison dictionaryItems.forEach(dictionaryItem => { dictionaryItem.id = dictionaryItem.id.toString(); @@ -153,7 +176,7 @@ // Get all data types entityResource.getAll("DataType").then(dataTypes => { - // a package stores the id as a string so we + // a package stores the id as a string so we // need to convert all ids to string for comparison dataTypes.forEach(dataType => { dataType.id = dataType.id.toString(); @@ -181,10 +204,12 @@ function createOrUpdatePackage(editPackageForm) { - let contributors = vm.contributorsEditor.value.map(o => o.value); + let contributors = vm.contributorsEditor.value.map(o => o.value) vm.package.contributors = contributors; + // Split by comma and remove empty entries + vm.package.mediaUdis = vm.mediaPickerModel.value.split(",").filter(i => i); if (formHelper.submitForm({ formCtrl: editPackageForm, scope: $scope })) { vm.buttonState = "busy"; @@ -215,23 +240,23 @@ vm.package.contentNodeId = null; } - function openContentPicker() { - const contentPicker = { - submit: function (model) { - if (model.selection && model.selection.length > 0) { - vm.package.contentNodeId = model.selection[0].id.toString(); - vm.contentNodeDisplayModel = model.selection[0]; - } - editorService.close(); - }, - close: function () { - editorService.close(); - } - }; - editorService.contentPicker(contentPicker); - } + function openContentPicker() { + const contentPicker = { + submit: function (model) { + if (model.selection && model.selection.length > 0) { + vm.package.contentNodeId = model.selection[0].id.toString(); + vm.contentNodeDisplayModel = model.selection[0]; + } + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + editorService.contentPicker(contentPicker); + } - function openFilePicker() { + function openFilePicker() { let selection = Utilities.copy(vm.package.files); @@ -313,6 +338,18 @@ } } + function selectMediaType(mediatype) { + + // Check if the document type is already selected. + var index = vm.package.mediaTypes.indexOf(mediatype.id); + + if (index === -1) { + vm.package.mediaTypes.push(mediatype.id); + } else { + vm.package.mediaTypes.splice(index, 1); + } + } + function selectTemplate(template) { // Check if the template is already selected. diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index ce65d1cff6..f4011a9d78 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -137,6 +137,22 @@ + + + + + + + + + + + + + +
+ +
+ + +
+
+
+ text="{{template.name}}">umb-expansion-panel__content
diff --git a/src/Umbraco.Web.UI.NetCore/Program.cs b/src/Umbraco.Web.UI.NetCore/Program.cs index 4a7722597d..4849ee226a 100644 --- a/src/Umbraco.Web.UI.NetCore/Program.cs +++ b/src/Umbraco.Web.UI.NetCore/Program.cs @@ -20,7 +20,6 @@ namespace Umbraco.Web.UI.NetCore { x.ClearProviders(); }) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) - .UseUmbraco(); + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } } diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index d496aadfd3..46f7b2d7ae 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -4,8 +4,12 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Umbraco.Extensions; using Umbraco.Core.DependencyInjection; +using Umbraco.Extensions; +using Umbraco.Web.BackOffice.DependencyInjection; +using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.Common.DependencyInjection; +using Umbraco.Web.Website.DependencyInjection; namespace Umbraco.Web.UI.NetCore { @@ -28,19 +32,25 @@ namespace Umbraco.Web.UI.NetCore _config = config ?? throw new ArgumentNullException(nameof(config)); } - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + + /// /// Configures the services /// + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + /// public void ConfigureServices(IServiceCollection services) { #pragma warning disable IDE0022 // Use expression body for methods services.AddUmbraco(_env, _config) - .AddAllBackOfficeComponents() - .AddUmbracoWebsite() + .AddBackOffice() + .AddWebsite() + .AddComposers() .Build(); #pragma warning restore IDE0022 // Use expression body for methods + } /// @@ -54,6 +64,7 @@ namespace Umbraco.Web.UI.NetCore } app.UseUmbraco(); + app.UseUmbracoBackOffice(); app.UseUmbracoWebsite(); } } diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 211238d951..8d9ca58ea9 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json index 29682186f6..44d148acdc 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.json @@ -39,7 +39,7 @@ }, "RuntimeMinification": { "dataFolder": "App_Data/TEMP/Smidge", - "version": "637429346786793415" + "version": "637432008251409860" }, "Security": { "KeepUserLoggedIn": false, diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml index bc72c1649b..382e0acce2 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Preview.cshtml @@ -28,7 +28,8 @@ var OpenWebsiteTitle = LocalizedTextService.Localize("preview", "openWebsiteTitle"); var returnToPreviewHeadline = LocalizedTextService.Localize("preview", "returnToPreviewHeadline"); var returnToPreviewDescription = LocalizedTextService.Localize("preview", "returnToPreviewDescription"); - var returnToPreviewButton = LocalizedTextService.Localize("preview", "returnToPreviewButton"); + var returnToPreviewAcceptButton = LocalizedTextService.Localize("preview", "returnToPreviewAcceptButton"); + var returnToPreviewDeclineButton = LocalizedTextService.Localize("preview", "returnToPreviewDeclineButton"); } @@ -44,7 +45,8 @@ window.umbLocalizedVars = { 'returnToPreviewHeadline': '@returnToPreviewHeadline', 'returnToPreviewDescription':'@returnToPreviewDescription', - 'returnToPreviewButton':'@returnToPreviewButton' + 'returnToPreviewAcceptButton':'@returnToPreviewAcceptButton', + 'returnToPreviewDeclineButton':'@returnToPreviewDeclineButton' }; diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml index 857129b1c1..b6d10589fe 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml @@ -1439,7 +1439,7 @@ Mange hilsner fra Umbraco robotten Dette benyttes ikke for en Element-type Du har lavet ændringer til denne egenskab. Er du sikker på at du vil kassere dem? Visning - Flyt label over editoren + Label hen over (fuld brede) Tilføj sprog @@ -1873,8 +1873,9 @@ Mange hilsner fra Umbraco robotten Vis i nyt vindue Åben forhåndsvisning i nyt vindue Forhåndsvisning af indholdet? - Du har afslutet forhåndsvisning, vil du se dette indhold i forhåndsvisning? - Fortsæt + Du har afslutet forhåndsvisning, vil du starte forhåndsvisning igen for at se seneste gemte version af indholdet? + Start forhåndsvisning + Se udgivet indhold Se udgivet indhold? Du er i forhåndsvisning, vil du afslutte for at se den udgivet version? Se udgivet version diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml index 6916b00e1c..2ab1d90b07 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml @@ -1699,7 +1699,7 @@ To manage your website, simply open the Umbraco back office and start adding con This is not applicable for an Element type You have made changes to this property. Are you sure you want to discard them? Appearance - Display label on top of editor. + Label above (full-width) Add language @@ -2536,9 +2536,10 @@ To manage your website, simply open the Umbraco back office and start adding con End preview mode Preview website Open website in preview mode - Preview content? - You have ended preview mode, do you want to continue previewing this content? - Preview + Preview website? + You have ended preview mode, do you want to enable it again to view the latest saved version of your website? + Preview latest version + View published version View published version? You are in Preview Mode, do you want exit in order to view the published version of your website? View published version diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml index cacb8288b3..fb6b5a22d6 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml @@ -730,6 +730,7 @@ Logout Macro Mandatory + Media Message Move Name @@ -1717,7 +1718,7 @@ To manage your website, simply open the Umbraco back office and start adding con This is not applicable for an element type You have made changes to this property. Are you sure you want to discard them? Appearance - Display label on top of editor. + Label above (full-width) Add language @@ -2556,9 +2557,10 @@ To manage your website, simply open the Umbraco back office and start adding con End preview mode Preview website Open website in preview mode - Preview content? - You have ended preview mode, do you want to continue previewing this content? - Preview + Preview website? + You have ended preview mode, do you want to enable it again to view the latest saved version of your website? + Preview latest version + View published version View published version? You are in Preview Mode, do you want exit in order to view the published version of your website? View published version diff --git a/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs b/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs index 62942541e9..abf269e062 100644 --- a/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs +++ b/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -99,7 +99,7 @@ namespace Umbraco.Web.Website.ActionResults /// private static void ValidateRouteData(RouteData routeData) { - if (routeData.DataTokens.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken) == false) + if (routeData.Values.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken) == false) { throw new InvalidOperationException("Can only use " + typeof(UmbracoPageResult).Name + " in the context of an Http POST when using a SurfaceController form"); diff --git a/src/Umbraco.Web.Website/Controllers/IUmbracoRenderingDefaults.cs b/src/Umbraco.Web.Website/Controllers/IUmbracoRenderingDefaults.cs new file mode 100644 index 0000000000..507b8c4a04 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/IUmbracoRenderingDefaults.cs @@ -0,0 +1,15 @@ +using System; + +namespace Umbraco.Web.Website.Controllers +{ + /// + /// The defaults used for rendering Umbraco front-end pages + /// + public interface IUmbracoRenderingDefaults + { + /// + /// Gets the default umbraco render controller type + /// + Type DefaultControllerType { get; } + } +} diff --git a/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs b/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs deleted file mode 100644 index f1ea65e983..0000000000 --- a/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.ActionConstraints; -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; - -namespace Umbraco.Web.Mvc -{ - /// - /// A custom ActionMethodSelector which will ensure that the RenderMvcController.Index(ContentModel model) action will be executed - /// if the - /// - internal class RenderIndexActionSelectorAttribute : ActionMethodSelectorAttribute - { - private static readonly ConcurrentDictionary> _controllerActionsCache = new ConcurrentDictionary>(); - - /// - /// Determines whether the action method selection is valid for the specified controller context. - /// - /// - /// true if the action method selection is valid for the specified controller context; otherwise, false. - /// - /// The route context. - /// Information about the action method. - public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) - { - if (action is ControllerActionDescriptor controllerAction) - { - var currType = controllerAction.ControllerTypeInfo.UnderlyingSystemType; - var baseType = controllerAction.ControllerTypeInfo.BaseType; - - //It's the same type, so this must be the Index action to use - if (currType == baseType) return true; - - var actions = _controllerActionsCache.GetOrAdd(currType, type => - { - var actionDescriptors = routeContext.HttpContext.RequestServices - .GetRequiredService().ActionDescriptors.Items - .Where(x=>x is ControllerActionDescriptor).Cast() - .Where(x => x.ControllerTypeInfo == controllerAction.ControllerTypeInfo); - - return actionDescriptors; - }); - - //If there are more than one Index action for this controller, then - // this base class one should not be matched - return actions.Count(x => x.ActionName == "Index") <= 1; - } - - return false; - - } - } -} diff --git a/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs b/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs deleted file mode 100644 index 62ffb010ea..0000000000 --- a/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Common.Filters; -using Umbraco.Web.Models; -using Umbraco.Web.Routing; - -namespace Umbraco.Web.Mvc -{ - - /// - /// Represents the default front-end rendering controller. - /// - [PreRenderViewActionFilter] - [TypeFilter(typeof(ModelBindingExceptionFilter))] - public class RenderMvcController : UmbracoController, IRenderMvcController - { - private IPublishedRequest _publishedRequest; - private readonly ILogger _logger; - private readonly ICompositeViewEngine _compositeViewEngine; - - public RenderMvcController(ILogger logger, ICompositeViewEngine compositeViewEngine) - { - _logger = logger; - _compositeViewEngine = compositeViewEngine; - } - - /// - /// Gets the current content item. - /// - protected IPublishedContent CurrentPage => PublishedRequest.PublishedContent; - - /// - /// Gets the current published content request. - /// - protected internal virtual IPublishedRequest PublishedRequest - { - get - { - if (_publishedRequest != null) - return _publishedRequest; - if (RouteData.DataTokens.ContainsKey(Core.Constants.Web.PublishedDocumentRequestDataToken) == false) - { - throw new InvalidOperationException("DataTokens must contain an 'umbraco-doc-request' key with a PublishedRequest object"); - } - _publishedRequest = (IPublishedRequest)RouteData.DataTokens[Core.Constants.Web.PublishedDocumentRequestDataToken]; - return _publishedRequest; - } - } - - /// - /// Ensures that a physical view file exists on disk. - /// - /// The view name. - protected bool EnsurePhsyicalViewExists(string template) - { - var result = _compositeViewEngine.FindView(ControllerContext, template, false); - if (result.View != null) return true; - - _logger.LogWarning("No physical template file was found for template {Template}", template); - return false; - } - - /// - /// Gets an action result based on the template name found in the route values and a model. - /// - /// The type of the model. - /// The model. - /// The action result. - /// If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned. - protected IActionResult CurrentTemplate(T model) - { - var template = ControllerContext.RouteData.Values["action"].ToString(); - if (EnsurePhsyicalViewExists(template) == false) - throw new InvalidOperationException("No physical template file was found for template " + template); - return View(template, model); - } - - /// - /// The default action to render the front-end view. - /// - /// - /// - [RenderIndexActionSelector] - public virtual IActionResult Index(ContentModel model) - { - return CurrentTemplate(model); - } - } -} diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs index 4e0517754c..390da69453 100644 --- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs +++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Specialized; using Microsoft.AspNetCore.Http; using Umbraco.Core; @@ -8,6 +8,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Common.Routing; using Umbraco.Web.Routing; using Umbraco.Web.Website.ActionResults; @@ -38,18 +39,18 @@ namespace Umbraco.Web.Website.Controllers { var routeDefAttempt = TryGetRouteDefinitionFromAncestorViewContexts(); if (routeDefAttempt.Success == false) + { throw routeDefAttempt.Exception; + } var routeDef = routeDefAttempt.Result; - return routeDef.PublishedRequest.PublishedContent; + return routeDef.PublishedContent; } } /// /// Redirects to the Umbraco page with the given id /// - /// - /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey) { return new RedirectToUmbracoPageResult(contentKey, PublishedUrlProvider, UmbracoContextAccessor); @@ -58,9 +59,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the Umbraco page with the given id and passes provided querystring /// - /// - /// - /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey, QueryString queryString) { return new RedirectToUmbracoPageResult(contentKey, queryString, PublishedUrlProvider, UmbracoContextAccessor); @@ -69,8 +67,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the Umbraco page with the given published content /// - /// - /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent) { return new RedirectToUmbracoPageResult(publishedContent, PublishedUrlProvider, UmbracoContextAccessor); @@ -79,9 +75,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the Umbraco page with the given published content and passes provided querystring /// - /// - /// - /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, QueryString queryString) { return new RedirectToUmbracoPageResult(publishedContent, queryString, PublishedUrlProvider, UmbracoContextAccessor); @@ -90,7 +83,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the currently rendered Umbraco page /// - /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage() { return new RedirectToUmbracoPageResult(CurrentPage, PublishedUrlProvider, UmbracoContextAccessor); @@ -99,8 +91,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the currently rendered Umbraco page and passes provided querystring /// - /// - /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(QueryString queryString) { return new RedirectToUmbracoPageResult(CurrentPage, queryString, PublishedUrlProvider, UmbracoContextAccessor); @@ -109,7 +99,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Redirects to the currently rendered Umbraco URL /// - /// /// /// This is useful if you need to redirect /// to the current page but the current page is actually a rewritten URL normally done with something like @@ -123,7 +112,6 @@ namespace Umbraco.Web.Website.Controllers /// /// Returns the currently rendered Umbraco page /// - /// protected UmbracoPageResult CurrentUmbracoPage() { return new UmbracoPageResult(ProfilingLogger); @@ -132,18 +120,19 @@ namespace Umbraco.Web.Website.Controllers /// /// we need to recursively find the route definition based on the parent view context /// - /// - private Attempt TryGetRouteDefinitionFromAncestorViewContexts() + private Attempt TryGetRouteDefinitionFromAncestorViewContexts() { var currentContext = ControllerContext; while (!(currentContext is null)) { var currentRouteData = currentContext.RouteData; - if (currentRouteData.DataTokens.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken)) - return Attempt.Succeed((RouteDefinition)currentRouteData.DataTokens[Core.Constants.Web.UmbracoRouteDefinitionDataToken]); + if (currentRouteData.Values.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken)) + { + return Attempt.Succeed((UmbracoRouteValues)currentRouteData.Values[Core.Constants.Web.UmbracoRouteDefinitionDataToken]); + } } - return Attempt.Fail( + return Attempt.Fail( new InvalidOperationException("Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request")); } } diff --git a/src/Umbraco.Web.Website/Controllers/UmbracoRenderingDefaults.cs b/src/Umbraco.Web.Website/Controllers/UmbracoRenderingDefaults.cs new file mode 100644 index 0000000000..65c27a3269 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbracoRenderingDefaults.cs @@ -0,0 +1,14 @@ +using System; +using Umbraco.Web.Common.Controllers; + +namespace Umbraco.Web.Website.Controllers +{ + /// + /// The defaults used for rendering Umbraco front-end pages + /// + public class UmbracoRenderingDefaults : IUmbracoRenderingDefaults + { + /// + public Type DefaultControllerType => typeof(RenderController); + } +} diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..52f6d5df11 --- /dev/null +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Umbraco.Core.DependencyInjection; +using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Web.Website.Collections; +using Umbraco.Web.Website.Controllers; +using Umbraco.Web.Website.Routing; +using Umbraco.Web.Website.ViewEngines; + +namespace Umbraco.Web.Website.DependencyInjection +{ + /// + /// extensions for umbraco front-end website + /// + public static class UmbracoBuilderExtensions + { + /// + /// Add services for the umbraco front-end website + /// + public static IUmbracoBuilder AddWebsite(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + + builder.WithCollectionBuilder() + .Add(builder.TypeLoader.GetSurfaceControllers()); + + // Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection + // to inject dependencies into the viewEngines) + builder.Services.AddTransient, RenderMvcViewOptionsSetup>(); + builder.Services.AddSingleton(); + builder.Services.AddTransient, PluginMvcViewOptionsSetup>(); + builder.Services.AddSingleton(); + + // Wraps all existing view engines in a ProfilerViewEngine + builder.Services.AddTransient, ProfilingViewEngineWrapperMvcViewOptionsSetup>(); + + // TODO figure out if we need more to work on load balanced setups + builder.Services.AddDataProtection(); + + builder.Services.AddScoped(); + builder.Services.AddSingleton(); + + builder.AddDistributedCache(); + + return builder; + } + + } +} diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs deleted file mode 100644 index 72d12809e2..0000000000 --- a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.DependencyInjection; -using Umbraco.Web.Website.ViewEngines; - -namespace Umbraco.Extensions -{ - public static class UmbracoBuilderExtensions - { - public static IUmbracoBuilder AddUmbracoWebsite(this IUmbracoBuilder builder) - { - // Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection - // to inject dependencies into the viewEngines) - builder.Services.AddTransient, RenderMvcViewOptionsSetup>(); - builder.Services.AddSingleton(); - builder.Services.AddTransient, PluginMvcViewOptionsSetup>(); - builder.Services.AddSingleton(); - - // Wraps all existing view engines in a ProfilerViewEngine - builder.Services.AddTransient, ProfilingViewEngineWrapperMvcViewOptionsSetup>(); - - //TODO figure out if we need more to work on load balanced setups - builder.Services.AddDataProtection(); - - return builder; - } - - - } -} diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs index ef99d67373..5ceb5e523f 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteApplicationBuilderExtensions.cs @@ -1,34 +1,46 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Web.DependencyInjection; using Umbraco.Web.Website.Routing; namespace Umbraco.Extensions { + /// + /// extensions for the umbraco front-end website + /// public static class UmbracoWebsiteApplicationBuilderExtensions { + /// + /// Sets up services and routes for the front-end umbraco website + /// public static IApplicationBuilder UseUmbracoWebsite(this IApplicationBuilder app) { - if (app == null) throw new ArgumentNullException(nameof(app)); + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } - if (!app.UmbracoCanBoot()) return app; + if (!app.UmbracoCanBoot()) + { + return app; + } - // Important we handle image manipulations before the static files, otherwise the querystring is just ignored. - // TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoBackOffice too? - app.UseImageSharp(); - app.UseStaticFiles(); - app.UseUmbracoNoContentPage(); + app.UseUmbracoRoutes(); return app; } - public static IApplicationBuilder UseUmbracoNoContentPage(this IApplicationBuilder app) + /// + /// Sets up routes for the umbraco front-end + /// + public static IApplicationBuilder UseUmbracoRoutes(this IApplicationBuilder app) { app.UseEndpoints(endpoints => { - var noContentRoutes = app.ApplicationServices.GetRequiredService(); + NoContentRoutes noContentRoutes = app.ApplicationServices.GetRequiredService(); noContentRoutes.CreateRoutes(endpoints); + + endpoints.MapDynamicControllerRoute("/{**slug}"); }); return app; diff --git a/src/Umbraco.Web.Website/RouteDefinition.cs b/src/Umbraco.Web.Website/RouteDefinition.cs deleted file mode 100644 index 02eab6ae77..0000000000 --- a/src/Umbraco.Web.Website/RouteDefinition.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using Umbraco.Web.Routing; - -namespace Umbraco.Web.Website -{ - /// - /// Represents the data required to route to a specific controller/action during an Umbraco request - /// - public class RouteDefinition - { - public string ControllerName { get; set; } - public string ActionName { get; set; } - - /// - /// The Controller type found for routing to - /// - public Type ControllerType { get; set; } - - /// - /// Everything related to the current content request including the requested content - /// - public IPublishedRequest PublishedRequest { get; set; } - - /// - /// Gets/sets whether the current request has a hijacked route/user controller routed for it - /// - public bool HasHijackedRoute { get; set; } - } -} diff --git a/src/Umbraco.Web.Website/Routing/NoContentRoutes.cs b/src/Umbraco.Web.Website/Routing/NoContentRoutes.cs index 58885bcd96..f2f2e8dfe3 100644 --- a/src/Umbraco.Web.Website/Routing/NoContentRoutes.cs +++ b/src/Umbraco.Web.Website/Routing/NoContentRoutes.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Umbraco.Core; @@ -17,6 +17,9 @@ namespace Umbraco.Web.Website.Routing private readonly IRuntimeState _runtimeState; private readonly string _umbracoPathSegment; + /// + /// Initializes a new instance of the class. + /// public NoContentRoutes( IOptions globalSettings, IHostingEnvironment hostingEnvironment, @@ -26,6 +29,7 @@ namespace Umbraco.Web.Website.Routing _umbracoPathSegment = globalSettings.Value.GetUmbracoMvcArea(hostingEnvironment); } + /// public void CreateRoutes(IEndpointRouteBuilder endpoints) { switch (_runtimeState.Level) @@ -35,13 +39,16 @@ namespace Umbraco.Web.Website.Routing case RuntimeLevel.Upgrade: break; case RuntimeLevel.Run: + + // TODO: I don't really think this is working AFAIK the code has just been migrated but it's not really enabled + // yet. Our route handler needs to be aware that there is no content and redirect there. Though, this could all be + // managed directly in UmbracoRouteValueTransformer. Else it could actually do a 'redirect' but that would need to be + // an internal rewrite. endpoints.MapControllerRoute( - // named consistently - Constants.Web.NoContentRouteName, + Constants.Web.NoContentRouteName, // named consistently _umbracoPathSegment + "/UmbNoContent", - new { controller = "RenderNoContent", action = "Index" } - ); - break; + new { controller = "RenderNoContent", action = "Index" }); + break; case RuntimeLevel.BootFailed: case RuntimeLevel.Unknown: case RuntimeLevel.Boot: diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs new file mode 100644 index 0000000000..731c0320d6 --- /dev/null +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Strings; +using Umbraco.Extensions; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Common.Middleware; +using Umbraco.Web.Common.Routing; +using Umbraco.Web.Models; +using Umbraco.Web.Routing; +using Umbraco.Web.Website.Controllers; + +namespace Umbraco.Web.Website.Routing +{ + /// + /// The route value transformer for Umbraco front-end routes + /// + /// + /// NOTE: In aspnet 5 DynamicRouteValueTransformer has been improved, see https://github.com/dotnet/aspnetcore/issues/21471 + /// It seems as though with the "State" parameter we could more easily assign the IPublishedRequest or IPublishedContent + /// or UmbracoContext more easily that way. In the meantime we will rely on assigning the IPublishedRequest to the + /// route values along with the IPublishedContent to the umbraco context + /// have created a GH discussion here https://github.com/dotnet/aspnetcore/discussions/28562 we'll see if anyone responds + /// + public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer + { + private readonly ILogger _logger; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IUmbracoRenderingDefaults _renderingDefaults; + private readonly IShortStringHelper _shortStringHelper; + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; + private readonly IPublishedRouter _publishedRouter; + private readonly GlobalSettings _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IRuntimeState _runtime; + + /// + /// Initializes a new instance of the class. + /// + public UmbracoRouteValueTransformer( + ILogger logger, + IUmbracoContextAccessor umbracoContextAccessor, + IUmbracoRenderingDefaults renderingDefaults, + IShortStringHelper shortStringHelper, + IActionDescriptorCollectionProvider actionDescriptorCollectionProvider, + IPublishedRouter publishedRouter, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IRuntimeState runtime) + { + _logger = logger; + _umbracoContextAccessor = umbracoContextAccessor; + _renderingDefaults = renderingDefaults; + _shortStringHelper = shortStringHelper; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; + _publishedRouter = publishedRouter; + _globalSettings = globalSettings.Value; + _hostingEnvironment = hostingEnvironment; + _runtime = runtime; + } + + /// + public override async ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values) + { + // If we aren't running, then we have nothing to route + if (_runtime.Level != RuntimeLevel.Run) + { + return values; + } + + // will be null for any client side requests like JS, etc... + if (_umbracoContextAccessor.UmbracoContext == null) + { + return values; + } + + // Check for back office request + // TODO: This is how the module was doing it before but could just as easily be part of the RoutableDocumentFilter + // which still needs to be migrated. + if (httpContext.Request.IsDefaultBackOfficeRequest(_globalSettings, _hostingEnvironment)) + { + return values; + } + + bool routed = RouteRequest(_umbracoContextAccessor.UmbracoContext, out IPublishedRequest publishedRequest); + if (!routed) + { + return values; + // TODO: Deal with it not being routable, perhaps this should be an enum result? + } + + UmbracoRouteValues routeDef = GetUmbracoRouteDefinition(httpContext, values, publishedRequest); + values["controller"] = routeDef.ControllerName; + if (string.IsNullOrWhiteSpace(routeDef.ActionName) == false) + { + values["action"] = routeDef.ActionName; + } + + return await Task.FromResult(values); + } + + /// + /// Returns a object based on the current content request + /// + private UmbracoRouteValues GetUmbracoRouteDefinition(HttpContext httpContext, RouteValueDictionary values, IPublishedRequest request) + { + if (httpContext is null) + { + throw new ArgumentNullException(nameof(httpContext)); + } + + if (values is null) + { + throw new ArgumentNullException(nameof(values)); + } + + if (request is null) + { + throw new ArgumentNullException(nameof(request)); + } + + Type defaultControllerType = _renderingDefaults.DefaultControllerType; + var defaultControllerName = ControllerExtensions.GetControllerName(defaultControllerType); + + string customActionName = null; + var customControllerName = request.PublishedContent.ContentType.Alias; // never null + + // check that a template is defined), if it doesn't and there is a hijacked route it will just route + // to the index Action + if (request.HasTemplate) + { + // the template Alias should always be already saved with a safe name. + // if there are hyphens in the name and there is a hijacked route, then the Action will need to be attributed + // with the action name attribute. + customActionName = request.TemplateAlias.Split('.')[0].ToSafeAlias(_shortStringHelper); + } + + // creates the default route definition which maps to the 'UmbracoController' controller + var def = new UmbracoRouteValues( + request.PublishedContent, + defaultControllerName, + defaultControllerType, + templateName: customActionName); + + IReadOnlyList candidates = FindControllerCandidates(customControllerName, customActionName, def.ActionName); + + // check if there's a custom controller assigned, base on the document type alias. + var customControllerCandidates = candidates.Where(x => x.ControllerName.InvariantEquals(customControllerName)).ToList(); + + // check if that custom controller exists + if (customControllerCandidates.Count > 0) + { + ControllerActionDescriptor controllerDescriptor = customControllerCandidates[0]; + + // ensure the controller is of type IRenderController and ControllerBase + if (TypeHelper.IsTypeAssignableFrom(controllerDescriptor.ControllerTypeInfo) + && TypeHelper.IsTypeAssignableFrom(controllerDescriptor.ControllerTypeInfo)) + { + // now check if the custom action matches + var customActionExists = customActionName != null && customControllerCandidates.Any(x => x.ActionName.InvariantEquals(customActionName)); + + def = new UmbracoRouteValues( + request.PublishedContent, + controllerDescriptor.ControllerName, + controllerDescriptor.ControllerTypeInfo, + customActionExists ? customActionName : def.ActionName, + customActionName, + true); // Hijacked = true + } + else + { + _logger.LogWarning( + "The current Document Type {ContentTypeAlias} matches a locally declared controller of type {ControllerName}. Custom Controllers for Umbraco routing must implement '{UmbracoRenderController}' and inherit from '{UmbracoControllerBase}'.", + request.PublishedContent.ContentType.Alias, + controllerDescriptor.ControllerTypeInfo.FullName, + typeof(IRenderController).FullName, + typeof(ControllerBase).FullName); + + // we cannot route to this custom controller since it is not of the correct type so we'll continue with the defaults + // that have already been set above. + } + } + + // store the route definition + values.TryAdd(Constants.Web.UmbracoRouteDefinitionDataToken, def); + + return def; + } + + /// + /// Return a list of controller candidates that match the custom controller and action names + /// + private IReadOnlyList FindControllerCandidates(string customControllerName, string customActionName, string defaultActionName) + { + var descriptors = _actionDescriptorCollectionProvider.ActionDescriptors.Items + .Cast() + .Where(x => x.ControllerName.InvariantEquals(customControllerName) + && (x.ActionName.InvariantEquals(defaultActionName) || (customActionName != null && x.ActionName.InvariantEquals(customActionName)))) + .ToList(); + + return descriptors; + } + + private bool RouteRequest(IUmbracoContext umbracoContext, out IPublishedRequest publishedRequest) + { + // TODO: I suspect one day this will be async + + // ok, process + + // note: requestModule.UmbracoRewrite also did some stripping of &umbPage + // from the querystring... that was in v3.x to fix some issues with pre-forms + // auth. Paul Sterling confirmed in Jan. 2013 that we can get rid of it. + + // instantiate, prepare and process the published content request + // important to use CleanedUmbracoUrl - lowercase path-only version of the current url + IPublishedRequest request = _publishedRouter.CreateRequest(umbracoContext); + + // TODO: This is ugly with the re-assignment to umbraco context also because IPublishedRequest is mutable + publishedRequest = umbracoContext.PublishedRequest = request; + bool prepared = _publishedRouter.PrepareRequest(request); + return prepared && request.HasPublishedContent; + + // // HandleHttpResponseStatus returns a value indicating that the request should + // // not be processed any further, eg because it has been redirect. then, exit. + // if (UmbracoModule.HandleHttpResponseStatus(httpContext, request, _logger)) + // return; + // if (!request.HasPublishedContent == false) + // { + // // httpContext.RemapHandler(new PublishedContentNotFoundHandler()); + // } + // else + // { + // // RewriteToUmbracoHandler(httpContext, request); + // } + } + } +} diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs deleted file mode 100644 index a40b29aea2..0000000000 --- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Extensions; -using Umbraco.Web.Website.Routing; -using Umbraco.Web.Common.Runtime; -using Umbraco.Web.Website.Collections; - -namespace Umbraco.Web.Website.Runtime -{ - // web's initial composer composes after core's, and before all core composers - [ComposeBefore(typeof(ICoreComposer))] - [ComposeAfter(typeof(AspNetCoreComposer))] - public class WebsiteComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - - builder.WithCollectionBuilder() - .Add(builder.TypeLoader.GetSurfaceControllers()); - } - } -} - diff --git a/src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs b/src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs index ac16be417a..e0b16a351e 100644 --- a/src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs +++ b/src/Umbraco.Web.Website/ViewEngines/PluginViewEngine.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.Logging; @@ -6,6 +6,10 @@ using Microsoft.Extensions.Options; namespace Umbraco.Web.Website.ViewEngines { + // TODO: We don't really need to have different view engines simply to search additional places, + // we can just do ConfigureOptions on startup to add more to the + // default list so this can be totally removed/replaced with configure options logic. + /// /// A view engine to look into the App_Plugins folder for views for packaged controllers /// @@ -21,28 +25,28 @@ namespace Umbraco.Web.Website.ViewEngines { } - private static IOptions OverrideViewLocations() + private static IOptions OverrideViewLocations() => Options.Create(new RazorViewEngineOptions() { - return Options.Create(new RazorViewEngineOptions() - { - AreaViewLocationFormats = + // This is definitely not doing what it used to do :P see: + // https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/src/Umbraco.Web/Mvc/PluginViewEngine.cs#L23 + + AreaViewLocationFormats = { - //set all of the area view locations to the plugin folder + // set all of the area view locations to the plugin folder string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"), string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"), - //will be used when we have partial view and child action macros + // will be used when we have partial view and child action macros string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Partials/{0}.cshtml"), string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/MacroPartials/{0}.cshtml"), - //for partialsCurrent. + // for partialsCurrent. string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"), string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/Shared/{0}.cshtml"), }, - ViewLocationFormats = + ViewLocationFormats = { string.Concat(Core.Constants.SystemDirectories.AppPlugins, "/{2}/Views/{1}/{0}.cshtml"), } - }); - } + }); } } diff --git a/src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs b/src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs index ea727a07f1..8c53255928 100644 --- a/src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs +++ b/src/Umbraco.Web.Website/ViewEngines/RenderViewEngine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -16,6 +16,10 @@ using Umbraco.Web.Models; namespace Umbraco.Web.Website.ViewEngines { + // TODO: We don't really need to have different view engines simply to search additional places, + // we can just do ConfigureOptions on startup to add more to the + // default list so this can be totally removed/replaced with configure options logic. + /// /// A view engine to look into the template location specified in the config for the front-end/Rendering part of the cms, /// this includes paths to render partial macros and media item templates. @@ -23,6 +27,9 @@ namespace Umbraco.Web.Website.ViewEngines public class RenderViewEngine : RazorViewEngine, IRenderViewEngine { + /// + /// Initializes a new instance of the class. + /// public RenderViewEngine( IRazorPageFactoryProvider pageFactory, IRazorPageActivator pageActivator, @@ -33,27 +40,24 @@ namespace Umbraco.Web.Website.ViewEngines { } - private static IOptions OverrideViewLocations() + private static IOptions OverrideViewLocations() => Options.Create(new RazorViewEngineOptions() { - return Options.Create(new RazorViewEngineOptions() - { - //NOTE: we will make the main view location the last to be searched since if it is the first to be searched and there is both a view and a partial - // view in both locations and the main view is rendering a partial view with the same name, we will get a stack overflow exception. - // http://issues.umbraco.org/issue/U4-1287, http://issues.umbraco.org/issue/U4-1215 - ViewLocationFormats = + // NOTE: we will make the main view location the last to be searched since if it is the first to be searched and there is both a view and a partial + // view in both locations and the main view is rendering a partial view with the same name, we will get a stack overflow exception. + // http://issues.umbraco.org/issue/U4-1287, http://issues.umbraco.org/issue/U4-1215 + ViewLocationFormats = { - "/Partials/{0}.cshtml", - "/MacroPartials/{0}.cshtml", - "/{0}.cshtml" + "/Views/Partials/{0}.cshtml", + "/Views/MacroPartials/{0}.cshtml", + "/Views/{0}.cshtml" }, - AreaViewLocationFormats = + AreaViewLocationFormats = { - "/Partials/{0}.cshtml", - "/MacroPartials/{0}.cshtml", - "/{0}.cshtml" + "/Views/Partials/{0}.cshtml", + "/Views/MacroPartials/{0}.cshtml", + "/Views/{0}.cshtml" } - }); - } + }); public new ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage) { @@ -72,16 +76,17 @@ namespace Umbraco.Web.Website.ViewEngines /// private static bool ShouldFindView(ActionContext context, bool isMainPage) { - //In v8, this was testing recursively into if it was a child action, but child action do not exist anymore, - //And my best guess is that it - context.RouteData.DataTokens.TryGetValue(Core.Constants.Web.UmbracoDataToken, out var umbracoToken); - // first check if we're rendering a partial view for the back office, or surface controller, etc... - // anything that is not ContentModel as this should only pertain to Umbraco views. - if (!isMainPage && !(umbracoToken is ContentModel)) - return true; - - // only find views if we're rendering the umbraco front end - return umbracoToken is ContentModel; + return true; + // TODO: Determine if this is required, i don't think it is + ////In v8, this was testing recursively into if it was a child action, but child action do not exist anymore, + ////And my best guess is that it + //context.RouteData.DataTokens.TryGetValue(Core.Constants.Web.UmbracoDataToken, out var umbracoToken); + //// first check if we're rendering a partial view for the back office, or surface controller, etc... + //// anything that is not ContentModel as this should only pertain to Umbraco views. + //if (!isMainPage && !(umbracoToken is ContentModel)) + // return true; + //// only find views if we're rendering the umbraco front end + //return umbracoToken is ContentModel; } diff --git a/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs b/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs index f0ff6e3cad..90261b1a5a 100644 --- a/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Web; -using Umbraco.Net; +using Umbraco.Core.Hosting; namespace Umbraco.Web.AspNet { diff --git a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs index 1c2be3f713..c59c701d42 100644 --- a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs +++ b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Web.Http; using System.Web.Mvc; @@ -127,7 +127,9 @@ namespace Umbraco.Web.Mvc //match this area controllerPluginRoute.DataTokens.Add("area", area.AreaName); - controllerPluginRoute.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, umbracoTokenValue); //ensure the umbraco token is set + + // TODO: No longer needed, remove + //controllerPluginRoute.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, umbracoTokenValue); //ensure the umbraco token is set return controllerPluginRoute; } diff --git a/src/Umbraco.Web/Mvc/ControllerContextExtensions.cs b/src/Umbraco.Web/Mvc/ControllerContextExtensions.cs deleted file mode 100644 index 4baaaac4fc..0000000000 --- a/src/Umbraco.Web/Mvc/ControllerContextExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Web.Mvc; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.Mvc -{ - public static class ControllerContextExtensions - { - /// - /// Gets the Umbraco context from a controller context hierarchy, if any, else the 'current' Umbraco context. - /// - /// The controller context. - /// The Umbraco context. - public static IUmbracoContext GetUmbracoContext(this ControllerContext controllerContext) - { - var o = controllerContext.GetDataTokenInViewContextHierarchy(Core.Constants.Web.UmbracoContextDataToken); - return o != null ? o as IUmbracoContext : Current.UmbracoContext; - } - - /// - /// Recursively gets a data token from a controller context hierarchy. - /// - /// The controller context. - /// The name of the data token. - /// The data token, or null. - internal static object GetDataTokenInViewContextHierarchy(this ControllerContext controllerContext, string dataTokenName) - { - var context = controllerContext; - while (context != null) - { - object token; - if (context.RouteData.DataTokens.TryGetValue(dataTokenName, out token)) - return token; - context = context.ParentActionViewContext; - } - return null; - } - } -} diff --git a/src/Umbraco.Web/Mvc/RenderControllerFactory.cs b/src/Umbraco.Web/Mvc/RenderControllerFactory.cs deleted file mode 100644 index 091ace4d98..0000000000 --- a/src/Umbraco.Web/Mvc/RenderControllerFactory.cs +++ /dev/null @@ -1,45 +0,0 @@ -// using System.Web.Mvc; -// using System.Web.Routing; -// -// namespace Umbraco.Web.Mvc -// { -// /// -// /// A controller factory for the render pipeline of Umbraco. This controller factory tries to create a controller with the supplied -// /// name, and falls back to UmbracoController if none was found. -// /// -// /// -// public class RenderControllerFactory : UmbracoControllerFactory -// { -// /// -// /// Determines whether this instance can handle the specified request. -// /// -// /// The request. -// /// true if this instance can handle the specified request; otherwise, false. -// /// -// public override bool CanHandle(RequestContext request) -// { -// var dataToken = request.RouteData.DataTokens["area"]; -// return dataToken == null || string.IsNullOrWhiteSpace(dataToken.ToString()); -// } -// -// /// -// /// Creates the controller -// /// -// /// -// /// -// /// -// /// -// /// We always set the correct ActionInvoker on our custom created controller, this is very important for route hijacking! -// /// -// public override IController CreateController(RequestContext requestContext, string controllerName) -// { -// var instance = base.CreateController(requestContext, controllerName); -// if (instance is Controller controllerInstance) -// { -// //set the action invoker! -// controllerInstance.ActionInvoker = new RenderActionInvoker(); -// } -// return instance; -// } -// } -// } diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs index 163364602d..3ca0931585 100644 --- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs @@ -56,8 +56,6 @@ namespace Umbraco.Web.Mvc /// Assigns the correct controller based on the Umbraco request and returns a standard MvcHandler to process the response, /// this also stores the render model into the data tokens for the current RouteData. /// - /// - /// public IHttpHandler GetHttpHandler(RequestContext requestContext) { if (UmbracoContext == null) @@ -70,37 +68,18 @@ namespace Umbraco.Web.Mvc throw new NullReferenceException("There is no current PublishedRequest, it must be initialized before the RenderRouteHandler executes"); } - SetupRouteDataForRequest( - new ContentModel(request.PublishedContent), - requestContext, - request); - return GetHandlerForRoute(requestContext, request); } #endregion - /// - /// Ensures that all of the correct DataTokens are added to the route values which are all required for rendering front-end umbraco views - /// - /// - /// - /// - internal void SetupRouteDataForRequest(ContentModel contentModel, RequestContext requestContext, IPublishedRequest frequest) - { - //put essential data into the data tokens, the 'umbraco' key is required to be there for the view engine - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, contentModel); //required for the ContentModelBinder and view engine - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.PublishedDocumentRequestDataToken, frequest); //required for RenderMvcController - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, UmbracoContext); //required for UmbracoViewPage - } - private void UpdateRouteDataForRequest(ContentModel contentModel, RequestContext requestContext) { if (contentModel == null) throw new ArgumentNullException(nameof(contentModel)); if (requestContext == null) throw new ArgumentNullException(nameof(requestContext)); - requestContext.RouteData.DataTokens[Core.Constants.Web.UmbracoDataToken] = contentModel; + // requestContext.RouteData.DataTokens[Core.Constants.Web.UmbracoDataToken] = contentModel; // the rest should not change -- it's only the published content that has changed } @@ -293,7 +272,7 @@ namespace Umbraco.Web.Mvc } //store the route definition - requestContext.RouteData.DataTokens[Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; + requestContext.RouteData.Values[Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; return def; } @@ -338,10 +317,10 @@ namespace Umbraco.Web.Mvc } - //Here we need to check if there is no hijacked route and no template assigned, - //if this is the case we want to return a blank page, but we'll leave that up to the NoTemplateHandler. - //We also check if templates have been disabled since if they are then we're allowed to render even though there's no template, - //for example for json rendering in headless. + // Here we need to check if there is no hijacked route and no template assigned, + // if this is the case we want to return a blank page, but we'll leave that up to the NoTemplateHandler. + // We also check if templates have been disabled since if they are then we're allowed to render even though there's no template, + // for example for json rendering in headless. if ((request.HasTemplate == false && Features.Disabled.DisableTemplates == false) && routeDef.HasHijackedRoute == false) { @@ -370,7 +349,7 @@ namespace Umbraco.Web.Mvc routeDef = GetUmbracoRouteDefinition(requestContext, request); } - //no post values, just route to the controller/action required (local) + // no post values, just route to the controller/action required (local) requestContext.RouteData.Values["controller"] = routeDef.ControllerName; if (string.IsNullOrWhiteSpace(routeDef.ActionName) == false) diff --git a/src/Umbraco.Web/Mvc/RouteDefinition.cs b/src/Umbraco.Web/Mvc/RouteDefinition.cs index 45e759fd66..2977c49cb5 100644 --- a/src/Umbraco.Web/Mvc/RouteDefinition.cs +++ b/src/Umbraco.Web/Mvc/RouteDefinition.cs @@ -1,13 +1,9 @@ -using System; -using System.Web.Mvc; +using System; using Umbraco.Web.Routing; namespace Umbraco.Web.Mvc { - /// - /// Represents the data required to route to a specific controller/action during an Umbraco request - /// - /// Migrated already to .Net Core + // TODO: Migrated already to .Net Core public class RouteDefinition { public string ControllerName { get; set; } diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index cd344ea261..fa67248e7d 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Core; using System.Collections.Specialized; using Umbraco.Core.Cache; @@ -204,8 +204,10 @@ namespace Umbraco.Web.Mvc while (currentContext != null) { var currentRouteData = currentContext.RouteData; - if (currentRouteData.DataTokens.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken)) - return Attempt.Succeed((RouteDefinition)currentRouteData.DataTokens[Core.Constants.Web.UmbracoRouteDefinitionDataToken]); + if (currentRouteData.Values.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken)) + { + return Attempt.Succeed((RouteDefinition)currentRouteData.Values[Core.Constants.Web.UmbracoRouteDefinitionDataToken]); + } currentContext = currentContext.IsChildAction ? currentContext.ParentActionViewContext diff --git a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs index 30c990a981..580924b909 100644 --- a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs +++ b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Web.Mvc; using System.Web.Routing; @@ -26,7 +26,7 @@ namespace Umbraco.Web.Mvc ValidateRouteData(context.RouteData); - var routeDef = (RouteDefinition)context.RouteData.DataTokens[Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken]; + var routeDef = (RouteDefinition)context.RouteData.Values[Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken]; var factory = ControllerBuilder.Current.GetControllerFactory(); context.RouteData.Values["action"] = routeDef.ActionName; @@ -72,7 +72,7 @@ namespace Umbraco.Web.Mvc /// private static void ValidateRouteData(RouteData routeData) { - if (routeData.DataTokens.ContainsKey(Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken) == false) + if (routeData.Values.ContainsKey(Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken) == false) { throw new InvalidOperationException("Can only use " + typeof(UmbracoPageResult).Name + " in the context of an Http POST when using a SurfaceController form"); diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs index 18e1fb8a1a..43dc341655 100644 --- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs +++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using System.Web; using System.Web.Mvc; @@ -20,9 +20,7 @@ using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Web.Mvc { - /// - /// Represents the properties and methods that are needed in order to render an Umbraco view. - /// + // TODO: This has been ported to netcore, just needs testing public abstract class UmbracoViewPage : WebViewPage { private readonly GlobalSettings _globalSettings; @@ -50,11 +48,9 @@ namespace Umbraco.Web.Mvc // like the Services & ApplicationCache properties, and have a setter for those special weird // cases. - /// - /// Gets the Umbraco context. - /// - public IUmbracoContext UmbracoContext => _umbracoContext - ?? (_umbracoContext = ViewContext.GetUmbracoContext() ?? Current.UmbracoContext); + // TODO: Can be injected to the view in netcore, else injected to the base model + // public IUmbracoContext UmbracoContext => _umbracoContext + // ?? (_umbracoContext = ViewContext.GetUmbracoContext() ?? Current.UmbracoContext); /// /// Gets the public content request. @@ -63,21 +59,27 @@ namespace Umbraco.Web.Mvc { get { - const string token = Core.Constants.Web.PublishedDocumentRequestDataToken; + // TODO: we only have one data token for a route now: Constants.Web.UmbracoRouteDefinitionDataToken - // we should always try to return the object from the data tokens just in case its a custom object and not - // the one from UmbracoContext. Fallback to UmbracoContext if necessary. + throw new NotImplementedException("Probably needs to be ported to netcore"); - // try view context - if (ViewContext.RouteData.DataTokens.ContainsKey(token)) - return (IPublishedRequest) ViewContext.RouteData.DataTokens.GetRequiredObject(token); + //// we should always try to return the object from the data tokens just in case its a custom object and not + //// the one from UmbracoContext. Fallback to UmbracoContext if necessary. - // child action, try parent view context - if (ViewContext.IsChildAction && ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey(token)) - return (IPublishedRequest) ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject(token); + //// try view context + //if (ViewContext.RouteData.DataTokens.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken)) + //{ + // return (IPublishedRequest) ViewContext.RouteData.DataTokens.GetRequiredObject(Constants.Web.UmbracoRouteDefinitionDataToken); + //} - // fallback to UmbracoContext - return UmbracoContext.PublishedRequest; + //// child action, try parent view context + //if (ViewContext.IsChildAction && ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken)) + //{ + // return (IPublishedRequest) ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject(Constants.Web.UmbracoRouteDefinitionDataToken); + //} + + //// fallback to UmbracoContext + //return UmbracoContext.PublishedRequest; } } diff --git a/src/Umbraco.Web/Mvc/UmbracoVirtualNodeRouteHandler.cs b/src/Umbraco.Web/Mvc/UmbracoVirtualNodeRouteHandler.cs index c00eb24cca..dc922d9fd2 100644 --- a/src/Umbraco.Web/Mvc/UmbracoVirtualNodeRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/UmbracoVirtualNodeRouteHandler.cs @@ -1,4 +1,4 @@ -using System.Web; +using System.Web; using System.Web.Mvc; using System.Web.Routing; using Microsoft.Extensions.DependencyInjection; @@ -62,12 +62,12 @@ namespace Umbraco.Web.Mvc var renderModel = new ContentModel(umbracoContext.PublishedRequest.PublishedContent); // assigns the required tokens to the request - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, renderModel); - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.PublishedDocumentRequestDataToken, umbracoContext.PublishedRequest); - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbracoContext); + //requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, renderModel); + //requestContext.RouteData.DataTokens.Add(Core.Constants.Web.PublishedDocumentRequestDataToken, umbracoContext.PublishedRequest); + //requestContext.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbracoContext); - // this is used just for a flag that this is an umbraco custom route - requestContext.RouteData.DataTokens.Add(Core.Constants.Web.CustomRouteDataToken, true); + //// this is used just for a flag that this is an umbraco custom route + //requestContext.RouteData.DataTokens.Add(Core.Constants.Web.CustomRouteDataToken, true); // Here we need to detect if a SurfaceController has posted var formInfo = RenderRouteHandler.GetFormInfo(requestContext); @@ -81,7 +81,7 @@ namespace Umbraco.Web.Mvc }; // set the special data token to the current route definition - requestContext.RouteData.DataTokens[Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; + requestContext.RouteData.Values[Core.Constants.Web.UmbracoRouteDefinitionDataToken] = def; return RenderRouteHandler.HandlePostedValues(requestContext, formInfo); } diff --git a/src/Umbraco.Web/Runtime/WebInitialComponent.cs b/src/Umbraco.Web/Runtime/WebInitialComponent.cs index 4fb1754946..c11d648b37 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComponent.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; @@ -171,7 +171,9 @@ namespace Umbraco.Web.Runtime new[] { meta.ControllerNamespace }); if (route.DataTokens == null) // web api routes don't set the data tokens object route.DataTokens = new RouteValueDictionary(); - route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set + + // TODO: Pretty sure this is not necessary, we'll see + //route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set } private static void RouteLocalSurfaceController(Type controller, string umbracoPath) @@ -183,7 +185,10 @@ namespace Umbraco.Web.Runtime url, // URL to match new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional }, new[] { meta.ControllerNamespace }); // look in this namespace to create the controller - route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); // ensure the umbraco token is set + + // TODO: Pretty sure this is not necessary, we'll see + //route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); // ensure the umbraco token is set + route.DataTokens.Add("UseNamespaceFallback", false); // don't look anywhere else except this namespace! // make it use our custom/special SurfaceMvcHandler route.RouteHandler = new SurfaceRouteHandler(); diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 49cff7196e..cac49f9421 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -1,26 +1,19 @@ -using System.Web.Mvc; using System.Web.Security; -using Microsoft.AspNet.SignalR; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Dictionary; using Umbraco.Core.Templates; -using Umbraco.Core.Runtime; using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.Composing.CompositionExtensions; using Umbraco.Web.Macros; -using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; namespace Umbraco.Web.Runtime { - // web's initial composer composes after core's, and before all core composers - [ComposeAfter(typeof(CoreInitialComposer))] [ComposeBefore(typeof(ICoreComposer))] public sealed class WebInitialComposer : ComponentComposer { @@ -46,7 +39,7 @@ namespace Umbraco.Web.Runtime if (state.Level == RuntimeLevel.Run) { var umbCtx = factory.GetRequiredService(); - return new UmbracoHelper(umbCtx.IsFrontEndUmbracoRequest ? umbCtx.PublishedRequest?.PublishedContent : null, factory.GetRequiredService(), + return new UmbracoHelper(umbCtx.IsFrontEndUmbracoRequest() ? umbCtx.PublishedRequest?.PublishedContent : null, factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService()); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index e59eed272c..b37b766a7d 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -141,8 +141,6 @@ - - @@ -184,7 +182,6 @@ - @@ -193,8 +190,6 @@ - - @@ -240,7 +235,6 @@ - diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index f10f4491d9..82182e26b7 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -46,7 +46,6 @@ namespace Umbraco.Web protected UmbracoApplicationBase() { - HostingSettings hostingSettings = null; GlobalSettings globalSettings = null; SecuritySettings securitySettings = null; @@ -60,8 +59,6 @@ namespace Umbraco.Web var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, _loggerFactory.CreateLogger(), Options.Create(webRoutingSettings)); var profiler = GetWebProfiler(hostingEnvironment); - StaticApplicationLogging.Initialize(_loggerFactory); - Logger = NullLogger.Instance; } private IProfiler GetWebProfiler(IHostingEnvironment hostingEnvironment) @@ -71,10 +68,10 @@ namespace Umbraco.Web { // should let it be null, that's how MiniProfiler is meant to work, // but our own IProfiler expects an instance so let's get one - return new VoidProfiler(); + return new NoopProfiler(); } - return new VoidProfiler(); + return new NoopProfiler(); } protected UmbracoApplicationBase(ILogger logger, ILoggerFactory loggerFactory, SecuritySettings securitySettings, GlobalSettings globalSettings, ConnectionStrings connectionStrings, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) @@ -87,7 +84,6 @@ namespace Umbraco.Web _loggerFactory = loggerFactory; Logger = logger; - StaticApplicationLogging.Initialize(_loggerFactory); } protected ILogger Logger { get; } @@ -189,7 +185,6 @@ namespace Umbraco.Web LogContext.Push(new HttpRequestIdEnricher(_factory.GetRequiredService())); _runtime = _factory.GetRequiredService(); - _runtime.Start(); } // called by ASP.NET (auto event wireup) once per app domain @@ -237,7 +232,6 @@ namespace Umbraco.Web { if (_runtime != null) { - _runtime.Terminate(); _runtime.DisposeIfDisposable(); _runtime = null; diff --git a/src/Umbraco.Web/UmbracoBuilderExtensions.cs b/src/Umbraco.Web/UmbracoBuilderExtensions.cs index bb6fe29c93..d9eea6b5ea 100644 --- a/src/Umbraco.Web/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web/UmbracoBuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Web.Routing; diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 5fdfd8c255..8707bea26b 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -29,7 +29,8 @@ namespace Umbraco.Web // internal for unit tests // otherwise it's used by EnsureContext above // warn: does *not* manage setting any IUmbracoContextAccessor - internal UmbracoContext(IHttpContextAccessor httpContextAccessor, + internal UmbracoContext( + IHttpContextAccessor httpContextAccessor, IPublishedSnapshotService publishedSnapshotService, IBackOfficeSecurity backofficeSecurity, GlobalSettings globalSettings, @@ -123,11 +124,6 @@ namespace Umbraco.Web /// public IDomainCache Domains => PublishedSnapshot.Domains; - /// - /// Boolean value indicating whether the current request is a front-end umbraco request - /// - public bool IsFrontEndUmbracoRequest => PublishedRequest != null; - /// /// Gets/sets the PublishedRequest object /// diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs index e9a1cc1436..5c7468ce95 100644 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ b/src/Umbraco.Web/UmbracoInjectedModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Web; using System.Web.Routing; using Microsoft.Extensions.Logging; @@ -157,9 +157,6 @@ namespace Umbraco.Web /// /// Checks the current request and ensures that it is routable based on the structure of the request and URI /// - /// - /// - /// internal Attempt EnsureUmbracoRoutablePage(IUmbracoContext context, HttpContextBase httpContext) { var uri = context.OriginalRequestUrl; @@ -186,8 +183,8 @@ namespace Umbraco.Web return Attempt.If(reason == EnsureRoutableOutcome.IsRoutable, reason); } - - + // TODO: Where should this execute in netcore? This will have to be a middleware + // executing before UseRouting so that it is done before any endpoint routing takes place. private bool EnsureRuntime(HttpContextBase httpContext, Uri uri) { var level = _runtime.Level; diff --git a/src/Umbraco.Web/WebApi/AngularJsonMediaTypeFormatter.cs b/src/Umbraco.Web/WebApi/AngularJsonMediaTypeFormatter.cs deleted file mode 100644 index 0e7cf6453a..0000000000 --- a/src/Umbraco.Web/WebApi/AngularJsonMediaTypeFormatter.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Formatting; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Umbraco.Core.Logging; - -namespace Umbraco.Web.WebApi -{ - /// - /// This will format the JSON output for use with AngularJs's approach to JSON Vulnerability attacks - /// - /// - /// See: http://docs.angularjs.org/api/ng.$http (Security considerations) - /// - public class AngularJsonMediaTypeFormatter : JsonMediaTypeFormatter - { - - public const string XsrfPrefix = ")]}',\n"; - - /// - /// This will prepend the special chars to the stream output that angular will strip - /// - /// - /// - /// - /// - /// - /// - public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) - { - if (type == null) throw new ArgumentNullException("type"); - if (writeStream == null) throw new ArgumentNullException("writeStream"); - - var effectiveEncoding = SelectCharacterEncoding(content == null ? null : content.Headers); - - using (var streamWriter = new StreamWriter(writeStream, effectiveEncoding, - //we are only writing a few chars so we don't need to allocate a large buffer - 128, - //this is important! We don't want to close the stream, the base class is in charge of stream management, we just want to write to it. - leaveOpen:true)) - { - //write the special encoding for angular json to the start - // (see: http://docs.angularjs.org/api/ng.$http) - streamWriter.Write(XsrfPrefix); - streamWriter.Flush(); - await base.WriteToStreamAsync(type, value, writeStream, content, transportContext); - } - } - - } -} diff --git a/src/Umbraco.Web/WebApi/AngularJsonOnlyConfigurationAttribute.cs b/src/Umbraco.Web/WebApi/AngularJsonOnlyConfigurationAttribute.cs deleted file mode 100644 index 6a6e63f335..0000000000 --- a/src/Umbraco.Web/WebApi/AngularJsonOnlyConfigurationAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Linq; -using System.Net.Http.Formatting; -using System.Web.Http.Controllers; - -namespace Umbraco.Web.WebApi -{ - /// - /// Applying this attribute to any webapi controller will ensure that it only contains one json formatter compatible with the angular json vulnerability prevention. - /// - public class AngularJsonOnlyConfigurationAttribute : Attribute, IControllerConfiguration - { - public virtual void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) - { - //remove all json/xml formatters then add our custom one - var toRemove = controllerSettings.Formatters.Where(t => (t is JsonMediaTypeFormatter) || (t is XmlMediaTypeFormatter)).ToList(); - foreach (var r in toRemove) - { - controllerSettings.Formatters.Remove(r); - } - controllerSettings.Formatters.Add(new AngularJsonMediaTypeFormatter()); - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs deleted file mode 100644 index 358c9cc3b3..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/EnableOverrideAuthorizationAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// This allows for Action based auth attributes to override Class based auth attributes if they are specified - /// - /// - /// This attribute can be applied at the class level and will indicate to any class level auth attribute that inherits from OverridableAuthorizationAttribute - /// - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public sealed class EnableOverrideAuthorizationAttribute : Attribute - { - // TODO: we should remove this and use the System.Web.Http.OverrideAuthorizationAttribute which uses IOverrideFilter instead - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/OverridableAuthorizationAttribute.cs b/src/Umbraco.Web/WebApi/Filters/OverridableAuthorizationAttribute.cs deleted file mode 100644 index 070bb53fb3..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/OverridableAuthorizationAttribute.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Linq; -using System.Web.Http; -using System.Web.Http.Controllers; - -namespace Umbraco.Web.WebApi.Filters -{ - // TODO: remove this since we don't need it, see notes in EnableOverrideAuthorizationAttribute - - /// - /// Abstract auth filter class that can be used to enable overriding class auth filters at the action level - /// - /// - /// To enable a class auth filter to be overridden by an action auth filter the EnableOverrideAuthorizationAttribute can be applied - /// to the class. - /// - public abstract class OverridableAuthorizationAttribute : AuthorizeAttribute - { - /// - /// If the controller has an EnabledOverrideAuthorizationAttribute attribute specified and the action has any AuthorizeAttribute - /// specified then use the action's auth attribute instead of this one - /// - /// The context. - /// The context parameter is null. - public override void OnAuthorization(HttpActionContext actionContext) - { - if (actionContext == null) throw new ArgumentNullException("actionContext"); - - var actionAttributes = actionContext.ActionDescriptor.GetCustomAttributes(); - - //if 'this' authorize attribute exists in the current collection then continue as per normal... this is because 'this' attribute instance - // is obviously assigned at an Action level and therefore it's already executing - - if (actionAttributes.Any(x => Equals(x, this))) - { - base.OnAuthorization(actionContext); - return; - } - - //if the controller is allowing authorization to be overridden at the action level and there are action level authorization attributes - // then exit and let the action level auth attribute(s) execute. - - if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes().Any() - && actionAttributes.Any()) - { - return; - } - - base.OnAuthorization(actionContext); - } - } -}