* Update gitignore * Move csproj * Update project references * Update solutions * Update build scripts * Tests used to share editorconfig with projects in src * Fix broken tests. * Stop copying around .editorconfig merged root one with linting * csharp_style_expression_bodied -> suggestion * Move StyleCop rulesets to matching directories and update shared build properties * Remove legacy build files, update NuGet.cofig and solution files * Restore myget source * Clean up .gitignore * Update .gitignore * Move new test classes to tests after merge * Gitignore + nuget config * Move new test Co-authored-by: Ronald Barendse <ronald@barend.se>
365 lines
11 KiB
C#
365 lines
11 KiB
C#
// Copyright (c) Umbraco.
|
|
// See LICENSE for more details.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
using Umbraco.Cms.Core.Events;
|
|
using Umbraco.Cms.Core.Mapping;
|
|
using Umbraco.Cms.Core.Models;
|
|
using Umbraco.Cms.Core.Models.ContentEditing;
|
|
using Umbraco.Cms.Core.Scoping;
|
|
using PropertyCollection = Umbraco.Cms.Core.Models.PropertyCollection;
|
|
|
|
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Mapping
|
|
{
|
|
[TestFixture]
|
|
public class MappingTests
|
|
{
|
|
private IScopeProvider _scopeProvider;
|
|
|
|
[SetUp]
|
|
public void MockScopeProvider()
|
|
{
|
|
var scopeMock = new Mock<IScopeProvider>();
|
|
scopeMock.Setup(x => x.CreateScope(
|
|
It.IsAny<IsolationLevel>(),
|
|
It.IsAny<RepositoryCacheMode>(),
|
|
It.IsAny<IEventDispatcher>(),
|
|
It.IsAny<IScopedNotificationPublisher>(),
|
|
It.IsAny<bool?>(),
|
|
It.IsAny<bool>(),
|
|
It.IsAny<bool>()))
|
|
.Returns(Mock.Of<IScope>);
|
|
|
|
_scopeProvider = scopeMock.Object;
|
|
}
|
|
|
|
[Test]
|
|
public void SimpleMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition1(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
var thing1 = new Thing1 { Value = "value" };
|
|
Thing2 thing2 = mapper.Map<Thing1, Thing2>(thing1);
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
|
|
thing2 = mapper.Map<Thing2>(thing1);
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
|
|
thing2 = new Thing2();
|
|
mapper.Map(thing1, thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void EnumerableMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition1(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
var thing1A = new Thing1 { Value = "valueA" };
|
|
var thing1B = new Thing1 { Value = "valueB" };
|
|
Thing1[] thing1 = new[] { thing1A, thing1B };
|
|
var thing2 = mapper.Map<IEnumerable<Thing1>, IEnumerable<Thing2>>(thing1).ToList();
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual(2, thing2.Count);
|
|
Assert.AreEqual("valueA", thing2[0].Value);
|
|
Assert.AreEqual("valueB", thing2[1].Value);
|
|
|
|
thing2 = mapper.Map<IEnumerable<Thing2>>(thing1).ToList();
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual(2, thing2.Count);
|
|
Assert.AreEqual("valueA", thing2[0].Value);
|
|
Assert.AreEqual("valueB", thing2[1].Value);
|
|
|
|
thing2 = mapper.MapEnumerable<Thing1, Thing2>(thing1).ToList();
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual(2, thing2.Count);
|
|
Assert.AreEqual("valueA", thing2[0].Value);
|
|
Assert.AreEqual("valueB", thing2[1].Value);
|
|
}
|
|
|
|
[Test]
|
|
public void InheritedMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition1(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
var thing3 = new Thing3 { Value = "value" };
|
|
Thing2 thing2 = mapper.Map<Thing3, Thing2>(thing3);
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
|
|
thing2 = mapper.Map<Thing2>(thing3);
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
|
|
thing2 = new Thing2();
|
|
mapper.Map(thing3, thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void CollectionsMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition2(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
// can map a PropertyCollection
|
|
var source = new PropertyCollection();
|
|
IEnumerable<ContentPropertyDto> target = mapper.Map<IEnumerable<ContentPropertyDto>>(source);
|
|
}
|
|
|
|
[Test]
|
|
[Explicit]
|
|
public void ConcurrentMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition1(),
|
|
new MapperDefinition3(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
// the mapper currently has a map from Thing1 to Thing2
|
|
// because Thing3 inherits from Thing1, it will map a Thing3 instance,
|
|
// and register a new map from Thing3 to Thing2,
|
|
// thus modifying its internal dictionaries
|
|
|
|
// 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;
|
|
|
|
void ThreadLoop()
|
|
{
|
|
// keep failing at mapping - and looping through the maps
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
try
|
|
{
|
|
mapper.Map<Thing2>(thing4);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
caught = e;
|
|
Console.WriteLine($"{e.GetType().Name} {e.Message}");
|
|
}
|
|
}
|
|
|
|
Console.WriteLine("done");
|
|
}
|
|
|
|
var thread = new Thread(ThreadLoop);
|
|
thread.Start();
|
|
Thread.Sleep(1000);
|
|
|
|
try
|
|
{
|
|
Console.WriteLine($"{DateTime.Now:O} mapping");
|
|
Thing2 thing2 = mapper.Map<Thing2>(thing3);
|
|
Console.WriteLine($"{DateTime.Now:O} mapped");
|
|
|
|
Assert.IsNotNull(thing2);
|
|
Assert.AreEqual("value", thing2.Value);
|
|
}
|
|
finally
|
|
{
|
|
thread.Join();
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void EnumMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition4(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
var thing5 = new Thing5()
|
|
{
|
|
Fruit1 = Thing5Enum.Apple,
|
|
Fruit2 = Thing5Enum.Banana,
|
|
Fruit3 = Thing5Enum.Cherry
|
|
};
|
|
|
|
Thing6 thing6 = mapper.Map<Thing5, Thing6>(thing5);
|
|
|
|
Assert.IsNotNull(thing6);
|
|
Assert.AreEqual(Thing6Enum.Apple, thing6.Fruit1);
|
|
Assert.AreEqual(Thing6Enum.Banana, thing6.Fruit2);
|
|
Assert.AreEqual(Thing6Enum.Cherry, thing6.Fruit3);
|
|
}
|
|
|
|
[Test]
|
|
public void NullPropertyMap()
|
|
{
|
|
var definitions = new MapDefinitionCollection(() => new IMapDefinition[]
|
|
{
|
|
new MapperDefinition5(),
|
|
});
|
|
var mapper = new UmbracoMapper(definitions, _scopeProvider);
|
|
|
|
var thing7 = new Thing7();
|
|
|
|
Thing8 thing8 = mapper.Map<Thing7, Thing8>(thing7);
|
|
|
|
Assert.IsNotNull(thing8);
|
|
Assert.IsNull(thing8.Things);
|
|
}
|
|
|
|
private class Thing1
|
|
{
|
|
public string Value { get; set; }
|
|
}
|
|
|
|
private class Thing3 : Thing1
|
|
{
|
|
}
|
|
|
|
private class Thing2
|
|
{
|
|
public string Value { get; set; }
|
|
}
|
|
|
|
private class Thing4
|
|
{
|
|
}
|
|
|
|
private class Thing5
|
|
{
|
|
public Thing5Enum Fruit1 { get; set; }
|
|
|
|
public Thing5Enum Fruit2 { get; set; }
|
|
|
|
public Thing5Enum Fruit3 { get; set; }
|
|
}
|
|
|
|
private enum Thing5Enum
|
|
{
|
|
Apple = 0,
|
|
Banana = 1,
|
|
Cherry = 2
|
|
}
|
|
|
|
private class Thing6
|
|
{
|
|
public Thing6Enum Fruit1 { get; set; }
|
|
|
|
public Thing6Enum Fruit2 { get; set; }
|
|
|
|
public Thing6Enum Fruit3 { get; set; }
|
|
}
|
|
|
|
private enum Thing6Enum
|
|
{
|
|
Apple = 0,
|
|
Banana = 1,
|
|
Cherry = 2
|
|
}
|
|
|
|
private class Thing7
|
|
{
|
|
public IEnumerable<Thing1> Things { get; set; }
|
|
}
|
|
|
|
private class Thing8
|
|
{
|
|
public IEnumerable<Thing2> Things { get; set; }
|
|
}
|
|
|
|
private class MapperDefinition1 : IMapDefinition
|
|
{
|
|
public void DefineMaps(IUmbracoMapper mapper) => mapper.Define<Thing1, Thing2>((source, context) => new Thing2(), Map);
|
|
|
|
private void Map(Thing1 source, Thing2 target, MapperContext context) => target.Value = source.Value;
|
|
}
|
|
|
|
private class MapperDefinition2 : IMapDefinition
|
|
{
|
|
public void DefineMaps(IUmbracoMapper mapper) =>
|
|
mapper.Define<IProperty, ContentPropertyDto>((source, context) => new ContentPropertyDto(), Map);
|
|
|
|
private static void Map(IProperty source, ContentPropertyDto target, MapperContext context)
|
|
{
|
|
}
|
|
}
|
|
|
|
private class MapperDefinition3 : IMapDefinition
|
|
{
|
|
public void DefineMaps(IUmbracoMapper mapper)
|
|
{
|
|
// just some random things so that the mapper contains things
|
|
mapper.Define<int, object>();
|
|
mapper.Define<string, object>();
|
|
mapper.Define<double, object>();
|
|
mapper.Define<UmbracoMapper, object>();
|
|
mapper.Define<Property, object>();
|
|
}
|
|
}
|
|
|
|
private class MapperDefinition4 : IMapDefinition
|
|
{
|
|
public void DefineMaps(IUmbracoMapper mapper)
|
|
{
|
|
mapper.Define<Thing5, Thing6>((source, context) => new Thing6(), Map);
|
|
mapper.Define<Thing5Enum, Thing6Enum>(
|
|
(source, context) => (Thing6Enum)source);
|
|
}
|
|
|
|
private void Map(Thing5 source, Thing6 target, MapperContext context)
|
|
{
|
|
target.Fruit1 = context.Map<Thing6Enum>(source.Fruit1);
|
|
target.Fruit2 = context.Map<Thing6Enum>(source.Fruit2);
|
|
target.Fruit3 = context.Map<Thing6Enum>(source.Fruit3);
|
|
}
|
|
}
|
|
|
|
private class MapperDefinition5 : IMapDefinition
|
|
{
|
|
public void DefineMaps(IUmbracoMapper mapper)
|
|
{
|
|
mapper.Define<Thing1, Thing2>((source, context) => new Thing2(), Map1);
|
|
mapper.Define<Thing7, Thing8>((source, context) => new Thing8(), Map2);
|
|
}
|
|
|
|
private void Map1(Thing1 source, Thing2 target, MapperContext context) =>
|
|
target.Value = source.Value;
|
|
|
|
private void Map2(Thing7 source, Thing8 target, MapperContext context) =>
|
|
target.Things = context.Map<IEnumerable<Thing2>>(source.Things);
|
|
}
|
|
}
|
|
}
|