Skip to content

Commit

Permalink
Added tests for both ConstantNode and SingleResourceCastNode
Browse files Browse the repository at this point in the history
  • Loading branch information
WanjohiSammy committed Sep 13, 2024
1 parent 53d9268 commit 1820efe
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using Microsoft.FullyQualified.NS;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;

namespace Microsoft.AspNetCore.OData.Tests.Query.Expressions
{
internal static class EdmModelBuilder
{
private static readonly IEdmModel Model = BuildAndGetEdmModel();

public static IEdmModel TestModel
{
get { return Model; }
}

public static IEdmEntityType GetEntityType(string entityQualifiedName)
{
return TestModel.FindDeclaredType(entityQualifiedName) as IEdmEntityType;
}

public static IEdmComplexType GetEdmComplexType(string complexTypeQualifiedName)
{
return TestModel.FindDeclaredType(complexTypeQualifiedName) as IEdmComplexType;
}

public static IEdmEntityTypeReference GetEntityTypeReference(IEdmEntityType entityType)
{
return new EdmEntityTypeReference(entityType, false);
}

public static IEdmComplexTypeReference GetComplexTypeReference(IEdmComplexType complexType)
{
// Create a complex type reference using the EdmCoreModel
return new EdmComplexTypeReference(complexType, isNullable: false);
}

public static IEdmProperty GetPersonLocationProperty()
{
return GetEntityType("Microsoft.FullyQualified.NS.Person").FindProperty("Location");
}

/// <summary>
/// Get the entity set from the model
/// </summary>
/// <returns>People Set</returns>
public static IEdmEntitySet GetPeopleSet()
{
return TestModel.EntityContainer.FindEntitySet("People");
}

public static IEdmModel BuildAndGetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.Namespace = "Microsoft.FullyQualified.NS";
builder.EntitySet<Person>("People");
builder.ComplexType<MyAddress>();
builder.ComplexType<WorkAddress>();
builder.EntitySet<Employee>("Employees");

return builder.GetEdmModel();
}
}
}

namespace Microsoft.FullyQualified.NS
{
public class Person
{
public int Id { get; set; }
public string FullName { get; set; }
public MyAddress Location { get; set; }
}

public class Employee : Person
{
public string EmployeeNumber { get; set; }
}

public class MyAddress
{
public string Street { get; set; }
public AddressType AddressType { get; set; }
}

public class WorkAddress : MyAddress
{
public string OfficeNumber { get; set; }
}

public enum AddressType
{
Home,
Work,
Other
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Microsoft.OData.Edm;
using Microsoft.OData.UriParser;

namespace Microsoft.AspNetCore.OData.Tests.Query.Expressions
{
public class FakeSingleEntityNode : SingleEntityNode
{
private readonly IEdmEntityTypeReference typeReference;
private readonly IEdmEntitySetBase set;

public FakeSingleEntityNode(IEdmEntityTypeReference type, IEdmEntitySetBase set)
{
this.typeReference = type;
this.set = set;
}

public override IEdmTypeReference TypeReference
{
get { return this.typeReference; }
}

public override IEdmNavigationSource NavigationSource
{
get { return this.set; }
}

public override IEdmStructuredTypeReference StructuredTypeReference
{
get { return this.typeReference; }
}

public override IEdmEntityTypeReference EntityTypeReference
{
get { return this.typeReference; }
}

public static FakeSingleEntityNode CreateFakeNodeForPerson()
{
var personType = EdmModelBuilder.GetEntityType("Microsoft.FullyQualified.NS.Person");
return new FakeSingleEntityNode(EdmModelBuilder.GetEntityTypeReference(personType), EdmModelBuilder.GetPeopleSet());
}
}

public class FakeCollectionResourceNode : CollectionResourceNode
{
private readonly IEdmStructuredTypeReference _typeReference;
private readonly IEdmNavigationSource _source;
private readonly IEdmTypeReference _itemType;
private readonly IEdmCollectionTypeReference _collectionType;

public FakeCollectionResourceNode(IEdmStructuredTypeReference type, IEdmNavigationSource source, IEdmTypeReference itemType, IEdmCollectionTypeReference collectionType)
{
_typeReference = type;
_source = source;
_itemType = itemType;
_collectionType = collectionType;
}

public override IEdmStructuredTypeReference ItemStructuredType => _typeReference;

public override IEdmNavigationSource NavigationSource => _source;

public override IEdmTypeReference ItemType => _itemType;

public override IEdmCollectionTypeReference CollectionType => _collectionType;

public static FakeCollectionResourceNode CreateFakeNodeForPerson()
{
var singleEntityNode = FakeSingleEntityNode.CreateFakeNodeForPerson();
return new FakeCollectionResourceNode(
singleEntityNode.EntityTypeReference, singleEntityNode.NavigationSource, singleEntityNode.EntityTypeReference, singleEntityNode.EntityTypeReference.AsCollection());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.AspNetCore.OData.Edm;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Query.Expressions;
using Microsoft.AspNetCore.OData.Query.Wrapper;
using Microsoft.AspNetCore.OData.Tests.Commons;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
using Microsoft.OData.UriParser;
using Microsoft.FullyQualified.NS;
using Moq;
using Xunit;

Expand Down Expand Up @@ -100,6 +105,134 @@ public void BindSingleResourceFunctionCallNode_ThrowsNotSupported_ForNotAcceptNo
"Unknown function 'anyUnknown'.");
}

[Theory]
[InlineData(typeof(ConstantNode))]
[InlineData(typeof(SingleResourceCastNode))]
public void BindSingleResourceFunctionCallNode_CastingEntityType_ReturnsExpression(Type queryNodeType)
{
// Arrange
var binder = new MyQueryBinder();

var model = EdmModelBuilder.BuildAndGetEdmModel();

// Create the type reference and navigation source
var personType = EdmModelBuilder.GetEntityType("Microsoft.FullyQualified.NS.Person");
var personTypeRef = EdmModelBuilder.GetEntityTypeReference(personType);
var collectionNode = FakeCollectionResourceNode.CreateFakeNodeForPerson();

var employeeType = EdmModelBuilder.GetEntityType("Microsoft.FullyQualified.NS.Employee");

// Create a ResourceRangeVariableReferenceNode for the Person entity
var rangeVariable = new ResourceRangeVariable("$it", personTypeRef, collectionNode);
var personNode = new ResourceRangeVariableReferenceNode(rangeVariable.Name, rangeVariable) as SingleValueNode;

// Create the parameters list
int capacity = 2;
var parameters = new List<QueryNode>(capacity)
{
personNode // First parameter is the Person entity
};

if (queryNodeType == typeof(SingleResourceCastNode))
{
// Create a SingleResourceCastNode to cast Person to NS.Employee
var singleResourceCastNode = new SingleResourceCastNode(personNode as SingleResourceNode, employeeType);
parameters.Add(singleResourceCastNode); // Second parameter is the SingleResourceCastNode
}
else if (queryNodeType == typeof(ConstantNode))
{
// Create a ConstantNode to cast Person to NS.Employee
var constantNode = new ConstantNode("Microsoft.FullyQualified.NS.Employee");
parameters.Add(constantNode); // Second parameter is the ConstantNode
}

// Create the SingleResourceFunctionCallNode
var node = new SingleResourceFunctionCallNode("cast", parameters, collectionNode.ItemStructuredType, collectionNode.NavigationSource);

// Create an instance of QueryBinderContext using the real model and settings
Type clrType = model.GetClrType(personType);
var context = new QueryBinderContext(model, new ODataQuerySettings(), clrType);

// Act
Expression expression = binder.BindSingleResourceFunctionCallNode(node, context);

// Assert
Assert.NotNull(expression);
Assert.Equal("($it As Employee)", expression.ToString());
Assert.Equal("Microsoft.FullyQualified.NS.Employee", expression.Type.ToString());
Assert.Equal(typeof(Employee), expression.Type);
Assert.Equal(ExpressionType.TypeAs, expression.NodeType);
Assert.Equal(personType.FullName(), (expression as UnaryExpression).Operand.Type.FullName);
Assert.Equal(employeeType.FullName(), (expression as UnaryExpression).Type.FullName);
}

[Theory]
[InlineData(typeof(ConstantNode))]
[InlineData(typeof(SingleResourceCastNode))]
public void BindSingleResourceFunctionCallNode_PropertyCasting_ReturnsExpression(Type queryNodeType)
{
// Arrange
var binder = new MyQueryBinder();

var model = EdmModelBuilder.BuildAndGetEdmModel();

// Create the type reference and navigation source
var personType = EdmModelBuilder.GetEntityType("Microsoft.FullyQualified.NS.Person");
var personTypeRef = EdmModelBuilder.GetEntityTypeReference(personType);
var collectionNode = FakeCollectionResourceNode.CreateFakeNodeForPerson();

var myAddressType = EdmModelBuilder.GetEdmComplexType("Microsoft.FullyQualified.NS.MyAddress");
var workAddressType = EdmModelBuilder.GetEdmComplexType("Microsoft.FullyQualified.NS.WorkAddress");

// Create a ResourceRangeVariableReferenceNode for the Person entity
var rangeVariable = new ResourceRangeVariable("$it", personTypeRef, collectionNode);
var personNode = new ResourceRangeVariableReferenceNode(rangeVariable.Name, rangeVariable) as SingleValueNode;

// Create a SingleComplexNode for the Location property of the Person entity
var locationProperty = EdmModelBuilder.GetPersonLocationProperty();
var locationNode = new SingleComplexNode(personNode as SingleResourceNode, locationProperty);

// Create the parameters list
int capacity = 2;
var parameters = new List<QueryNode>(capacity)
{
locationNode // First parameter is the Location property
};

if(queryNodeType == typeof(SingleResourceCastNode))
{
// Create a SingleResourceCastNode to cast Location to NS.WorkAddress
var singleResourceCastNode = new SingleResourceCastNode(locationNode, workAddressType);
parameters.Add(singleResourceCastNode); // Second parameter is the SingleResourceCastNode
}
else if (queryNodeType == typeof(ConstantNode))
{
// Create a ConstantNode to cast Location to NS.WorkAddress
var constantNode = new ConstantNode("Microsoft.FullyQualified.NS.WorkAddress");
parameters.Add(constantNode); // Second parameter is the ConstantNode
}

// Create the SingleResourceFunctionCallNode
var node = new SingleResourceFunctionCallNode("cast", parameters, collectionNode.ItemStructuredType, collectionNode.NavigationSource);

// Create an instance of QueryBinderContext using the real model and settings
Type clrType = model.GetClrType(personType);
var context = new QueryBinderContext(model, new ODataQuerySettings(), clrType);

// Act
Expression expression = binder.BindSingleResourceFunctionCallNode(node, context);

// Assert
Assert.NotNull(expression);
Assert.Equal("($it.Location As WorkAddress)", expression.ToString());
Assert.Equal("Microsoft.FullyQualified.NS.WorkAddress", expression.Type.ToString());
Assert.Equal("Location", ((expression as UnaryExpression).Operand as MemberExpression).Member.Name);
Assert.Equal(typeof(WorkAddress), expression.Type);
Assert.Equal(ExpressionType.TypeAs, expression.NodeType);
Assert.Equal(workAddressType.FullName(), (expression as UnaryExpression).Type.FullName);
Assert.Equal(myAddressType.FullName(), (expression as UnaryExpression).Operand.Type.FullName);
}

[Fact]
public void BindSingleValueFunctionCallNode_ThrowsArgumentNull_ForInputs()
{
Expand Down

0 comments on commit 1820efe

Please sign in to comment.