Skip to content

Commit

Permalink
Merge pull request #43 from DynamicsValue/bugfix/66-containvalues-mul…
Browse files Browse the repository at this point in the history
…tioptionset

Resolves DynamicsValue/fake-xrm-easy#66
  • Loading branch information
jordimontana82 authored Aug 23, 2023
2 parents 916407e + 79db1eb commit 6a05372
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [2.3.3]

### Changed

- Resolves an issue with query evaluation and MultiOptionSets when using late bound entities or if type information is not present. - https://github.com/DynamicsValue/fake-xrm-easy/issues/66

## [2.3.2]

### Changed
Expand Down
8 changes: 6 additions & 2 deletions src/FakeXrmEasy.Core/Extensions/XmlExtensionsForFetchXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -958,12 +958,16 @@ public static object GetConditionExpressionValueCast(string value, IXrmFakedCont
{
throw new Exception(string.Format("When trying to parse value for entity {0} and attribute {1}: {2}", sEntityName, sAttributeName, e.Message));
}

}
}
}


#if FAKE_XRM_EASY_9
if(op == ConditionOperator.ContainValues || op == ConditionOperator.DoesNotContainValues)
{
return GetValueBasedOnType(typeof(OptionSetValueCollection), value);
}
#endif
// Try parsing a guid
Guid gOut = Guid.Empty;
if (Guid.TryParse(value, out gOut))
Expand Down
2 changes: 1 addition & 1 deletion src/FakeXrmEasy.Core/FakeXrmEasy.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<TargetFrameworks Condition="'$(Configuration)'=='FAKE_XRM_EASY_2013'">net452</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)'=='FAKE_XRM_EASY'">net452</TargetFrameworks>
<PackageId>FakeXrmEasy.Core</PackageId>
<VersionPrefix>2.3.2</VersionPrefix>
<VersionPrefix>2.3.3</VersionPrefix>
<Authors>Jordi Montaña</Authors>
<Company>Dynamics Value</Company>
<Title>FakeXrmEasy Core</Title>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#if FAKE_XRM_EASY_9

using System.Collections.Generic;
using System.Linq.Expressions;
using FakeXrmEasy.Extensions;
using Microsoft.Xrm.Sdk;

namespace FakeXrmEasy.Query
{
public static partial class ConditionExpressionExtensions
{
internal static Expression ToContainsValuesExpression(this TypedConditionExpression tc, Expression getAttributeValueExpr, Expression containsAttributeExpr)
{
var leftHandSideExpression = tc.AttributeType.GetAppropiateCastExpressionBasedOnType(getAttributeValueExpr, null);
var leftHandSideExpression = typeof(OptionSetValueCollection).GetAppropiateCastExpressionBasedOnType(getAttributeValueExpr, null);
var rightHandSideExpression = Expression.Constant(OptionSetValueCollectionExtensions.ConvertToHashSetOfInt(tc.CondExpression.Values, isOptionSetValueCollectionAccepted: false));

return Expression.AndAlso(
Expand Down
2 changes: 1 addition & 1 deletion src/FakeXrmEasy.Core/Query/TypeCastExpressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal static Expression GetAppropiateCastExpressionBasedOnAttributeTypeOrValu
return GetAppropiateCastExpressionDefault(input, value); //any other type
}

return GetAppropiateCastExpressionBasedOnValueInherentType(input, value); //Dynamic entities
return GetAppropiateCastExpressionBasedOnValueInherentType(input, value); //Dynamic / late bound entities
}

internal static Expression GetAppropiateCastExpressionBasedGuid(Expression input)
Expand Down
8 changes: 4 additions & 4 deletions src/FakeXrmEasy.Core/Query/TypedConditionExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
namespace FakeXrmEasy.Query
{
/// <summary>
/// A condition expression with a decorated type
/// A condition expression with a decorated type of the attribute in the condition expression
/// </summary>
public class TypedConditionExpression
{
/// <summary>
///
/// The original condition expression
/// </summary>
public ConditionExpression CondExpression { get; set; }

/// <summary>
///
/// The attribute type of the condition expression, if known (i.e. was generated via a strongly-typed generation tool)
/// </summary>
public Type AttributeType { get; set; }

Expand All @@ -29,7 +29,7 @@ public class TypedConditionExpression
public bool IsOuter { get; set; }

/// <summary>
///
/// Creates a TypedConditionExpression from an existing ConditionExpression with no attribute type information
/// </summary>
/// <param name="c"></param>
public TypedConditionExpression(ConditionExpression c)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,6 @@ public void When_executing_a_query_expression_containvalues_operator_throws_exce
[Fact]
public void When_executing_a_query_expression_containvalues_operator_throws_exception_for_optionsetvaluecollection_right_hand_side()
{



_service.Create(new Contact { FirstName = "1,2,3", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(1), new OptionSetValue(2) } });

var qe = new QueryExpression("contact");
Expand All @@ -514,9 +511,6 @@ public void When_executing_a_query_expression_containvalues_operator_throws_exce
[Fact]
public void When_executing_a_query_expression_containvalues_operator_returns_partial_matches_for_single_int_array_right_hand_side()
{



_service.Create(new Contact { FirstName = "1,2", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(1), new OptionSetValue(2) } });
_service.Create(new Contact { FirstName = "2", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(2) } });
_service.Create(new Contact { FirstName = "2,3", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(2), new OptionSetValue(3) } });
Expand Down Expand Up @@ -558,9 +552,6 @@ public void When_executing_a_query_expression_containvalues_operator_returns_par
[Fact]
public void When_executing_a_query_expression_containvalues_operator_returns_partial_matches_for_int_params_right_hand_side()
{



_service.Create(new Contact { FirstName = "1,2", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(1), new OptionSetValue(2) } });
_service.Create(new Contact { FirstName = "2", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(2) } });
_service.Create(new Contact { FirstName = "2,3", new_MultiSelectAttribute = new OptionSetValueCollection() { new OptionSetValue(2), new OptionSetValue(3) } });
Expand Down
14 changes: 7 additions & 7 deletions tests/FakeXrmEasy.Core.Tests/FakeXrmEasy.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<IsPackable>true</IsPackable>

<PackageId>FakeXrmEasy.CoreTests</PackageId>
<VersionPrefix>2.3.2</VersionPrefix>
<VersionPrefix>2.3.3</VersionPrefix>
<Authors>Jordi Montaña</Authors>
<Company>Dynamics Value S.L.</Company>
<Title>Internal Unit test suite for FakeXrmEasy.Core package</Title>
Expand Down Expand Up @@ -141,22 +141,22 @@
</ItemGroup>

<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY'">
<PackageReference Include="FakeXrmEasy.Core.v2011" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v2011" Version="[2.3.3-*,3.0)" />
</ItemGroup>
<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY_2013'">
<PackageReference Include="FakeXrmEasy.Core.v2013" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v2013" Version="[2.3.3-*,3.0)" />
</ItemGroup>
<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY_2015'">
<PackageReference Include="FakeXrmEasy.Core.v2015" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v2015" Version="[2.3.3-*,3.0)" />
</ItemGroup>
<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY_2016'">
<PackageReference Include="FakeXrmEasy.Core.v2016" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v2016" Version="[2.3.3-*,3.0)" />
</ItemGroup>
<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY_365'">
<PackageReference Include="FakeXrmEasy.Core.v365" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v365" Version="[2.3.3-*,3.0)" />
</ItemGroup>
<ItemGroup Condition="'$(PackTests)' == 'true' And '$(Configuration)'=='FAKE_XRM_EASY_9'">
<PackageReference Include="FakeXrmEasy.Core.v9" Version="[2.3.2-*,3.0)" />
<PackageReference Include="FakeXrmEasy.Core.v9" Version="[2.3.3-*,3.0)" />
</ItemGroup>

</Project>
89 changes: 89 additions & 0 deletions tests/FakeXrmEasy.Core.Tests/Issues/Issue467.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#if FAKE_XRM_EASY_9
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using Xunit;

namespace FakeXrmEasy.Tests.Issues
{
// https://github.com/jordimontana82/fake-xrm-easy/issues/467

public class Issue467 : FakeXrmEasyTestsBase
{
Entity _product;
// setup

public Issue467()
{
_product = new Entity("product", Guid.NewGuid());
var productCategories = new OptionSetValueCollection
{
new OptionSetValue(121720003),
new OptionSetValue(121720002)
};
_product["name"] = "Test product";
_product["abc_productcategories"] = productCategories;

_context.Initialize(new List<Entity> { _product });
}

// This test currently fails - Object reference not set to an instance of an object
[Fact]
public void When_A_Query_Expression_Has_A_ContainsValues_Clause_On_A_MultiSelectOptionSet_It_Should_Not_Fail()
{
var query = new QueryExpression("product");
query.ColumnSet = new ColumnSet(new[] { "name" });
query.Criteria.AddCondition("abc_productcategories", ConditionOperator.ContainValues, 121720003, 121720002);

EntityCollection products = _service.RetrieveMultiple(query);
Assert.Equal(_product.Id, products.Entities[0].Id);
}

// This test currently fails - Object reference not set to an instance of an object
[Fact]
public void When_A_Query_Expression_Has_A_ContainsValues_Array_Clause_On_A_MultiSelectOptionSet_It_Should_Not_Fail()
{
var query = new QueryExpression("product");
query.Criteria.AddCondition("abc_productcategories", ConditionOperator.ContainValues, new[] { 121720003, 121720002 });

EntityCollection products = _service.RetrieveMultiple(query);
Assert.Equal(_product.Id, products.Entities[0].Id);
}

// This test currently fails - Object reference not set to an instance of an object
[Fact]
public void When_A_Query_Expression_Has_A_DoesNotContainValues_Clause_On_A_MultiSelectOptionSet_It_Should_Not_Fail()
{
var query = new QueryExpression("product");
query.Criteria.AddCondition("abc_productcategories", ConditionOperator.DoesNotContainValues, 121720003, 121720002);

EntityCollection products = _service.RetrieveMultiple(query);
Assert.Empty(products.Entities);
}

// This test should also pass, but fails with this error
// When using arithmetic values in Fetch a ProxyTypesAssembly must be used in order to know which types to cast values to.
// This is a requirement of FXE, but I don't think any of the Early bound classes have multi-select option set attributes so difficult to test in the core project...
//
[Fact]
public void When_A_FetchXml_Query_Has_A_Contains_Clause_On_A_MultiSelectOptionSet_It_Should_Not_Fail()
{
string fetchXml = @"<fetch top='50'>
<entity name='product'>
<filter>
<condition attribute='abc_productcategories' operator='contain-values'>
<value>121720003</value>
<value>121720002</value>
</condition>
</filter>
</entity>
</fetch>";

EntityCollection products = _service.RetrieveMultiple(new FetchExpression(fetchXml));
Assert.Equal(_product.Id, products.Entities[0].Id);
}

}
}
#endif

0 comments on commit 6a05372

Please sign in to comment.