Skip to content

Commit

Permalink
Implemented testing for TypeAdapter.ValidateAndAdapt
Browse files Browse the repository at this point in the history
  • Loading branch information
haritha99ch committed Oct 8, 2023
1 parent 7445200 commit 794f4fd
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 10 deletions.
48 changes: 48 additions & 0 deletions src/Mapster.Tests/WhenRequiresPropsValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using Mapster.Tests.Classes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;

namespace Mapster.Tests
{
[TestClass]
public class WhenRequiresPropsValidation
{
[TestInitialize]
public void Setup()
{
TypeAdapterConfig.GlobalSettings.Clear();
}

[TestCleanup]
public void TestCleanup()
{
TypeAdapterConfig.GlobalSettings.Default.NameMatchingStrategy(NameMatchingStrategy.Exact);
}

[TestMethod]
public void DestinationProps_Exist_In_Source()
{
var product = new Product {Id = Guid.NewGuid(), Title = "ProductA", CreatedUser = new User {Name = "UserA"}};

var dto = product.ValidateAndAdapt<Product, ProductNestedDTO>();

dto.ShouldNotBeNull();
dto.Id.ShouldBe(product.Id);
}

[TestMethod]
public void DestinationProps_Not_Exist_In_Source()
{
var product = new Product {Id = Guid.NewGuid(), Title = "ProductA", CreatedUser = new User {Name = "UserA"}};

ProductDTO productDtoRef;
var notExistingPropName = nameof(productDtoRef.CreatedUserName);

var ex = Should.Throw<Exception>(() => product.ValidateAndAdapt<Product, ProductDTO>());

ex.Message.ShouldContain(notExistingPropName);
ex.Message.ShouldContain(nameof(Product));
}
}
}
53 changes: 53 additions & 0 deletions src/Mapster.Tests/WhenRequiresPropsValidationWithAdapterConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using Mapster.Tests.Classes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;

namespace Mapster.Tests
{
[TestClass]
public class WhenRequiresPropsValidationWithAdapterConfig
{
[TestInitialize]
public void Setup()
{
TypeAdapterConfig.GlobalSettings.Clear();
}

[TestCleanup]
public void TestCleanup()
{
TypeAdapterConfig.GlobalSettings.Default.NameMatchingStrategy(NameMatchingStrategy.Exact);
}

[TestMethod]
public void DestinationProps_Not_Exist_In_Source_But_Configured()
{
var product = new Product {Id = Guid.NewGuid(), Title = "ProductA", CreatedUser = new User {Name = "UserA"}};

var adapterSettings = TypeAdapterConfig<Product, ProductDTO>.NewConfig()
.Map(dest => dest.CreatedUserName, src => $"{src.CreatedUser.Name} {src.CreatedUser.Surname}");

var dto = product.ValidateAndAdapt<Product, ProductDTO>(adapterSettings.Config);

dto.ShouldNotBeNull();
dto.CreatedUserName.ShouldBe($"{product.CreatedUser.Name} {product.CreatedUser.Surname}");
}

[TestMethod]
public void DestinationProps_Not_Exist_In_Source_And_MisConfigured()
{
var product = new Product {Id = Guid.NewGuid(), Title = "ProductA", CreatedUser = new User {Name = "UserA"}};

var adapterSettings = TypeAdapterConfig<Product, ProductDTO>.NewConfig();

ProductDTO productDtoRef;
var notExistingPropName = nameof(productDtoRef.CreatedUserName);

var ex = Should.Throw<Exception>(() => product.ValidateAndAdapt<Product, ProductDTO>(adapterSettings.Config));

ex.Message.ShouldContain(notExistingPropName);
ex.Message.ShouldContain(nameof(Product));
}
}
}
20 changes: 10 additions & 10 deletions src/Mapster/TypeAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,22 +183,22 @@ public static TDestination Adapt<TSource, TDestination>(this TSource source, TDe
/// <returns>Adapted destination type.</returns>
public static TDestination ValidateAndAdapt<TSource, TDestination>(this TSource source)
{
var entityType = typeof(TSource);
var sourceType = typeof(TSource);
var selectorType = typeof(TDestination);

var entityProperties = new HashSet<string>(entityType.GetProperties().Select(p => p.Name));
var sourceProperties = new HashSet<string>(sourceType.GetProperties().Select(p => p.Name));
var selectorProperties = new HashSet<string>(selectorType.GetProperties().Select(p=> p.Name));

foreach (var selectorProperty in selectorProperties)
{
if (entityProperties.Contains(selectorProperty)) continue;
throw new Exception($"Property {selectorProperty} does not exist in {entityType.Name} and is not configured in Mapster");
if (sourceProperties.Contains(selectorProperty)) continue;
throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster");
}
return source.Adapt<TDestination>();
}

/// <summary>
/// Validate properties and Adapt the source object to the destination type.
/// Validate properties with configuration and Adapt the source object to the destination type.
/// </summary>
/// <typeparam name="TSource">Source type.</typeparam>
/// <typeparam name="TDestination">Destination type.</typeparam>
Expand All @@ -207,23 +207,23 @@ public static TDestination ValidateAndAdapt<TSource, TDestination>(this TSource
/// <returns>Adapted destination type.</returns>
public static TDestination ValidateAndAdapt<TSource, TDestination>(this TSource source, TypeAdapterConfig config)
{
var entityType = typeof(TSource);
var sourceType = typeof(TSource);
var selectorType = typeof(TDestination);

var entityProperties = new HashSet<string>(entityType.GetProperties().Select(p => p.Name));
var sourceProperties = new HashSet<string>(sourceType.GetProperties().Select(p => p.Name));
var selectorProperties = new HashSet<string>(selectorType.GetProperties().Select(p=> p.Name));

// Get the rule map for the current types
var ruleMap = config.RuleMap;
var typeTuple = new TypeTuple(entityType, selectorType);
var typeTuple = new TypeTuple(sourceType, selectorType);
ruleMap.TryGetValue(typeTuple, out var rule);

foreach (var selectorProperty in selectorProperties)
{
if (entityProperties.Contains(selectorProperty)) continue;
if (sourceProperties.Contains(selectorProperty)) continue;
// Check whether the adapter config has a config for the property
if (rule != null && rule.Settings.Resolvers.Any(r => r.DestinationMemberName.Equals(selectorProperty))) continue;
throw new Exception($"Property {selectorProperty} does not exist in {entityType.Name} and is not configured in Mapster");
throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster");
}
return source.Adapt<TDestination>(config);
}
Expand Down

0 comments on commit 794f4fd

Please sign in to comment.