Skip to content

Commit

Permalink
Add support for Singleton's in VocabularyAnnotationInaccessibleTarget…
Browse files Browse the repository at this point in the history
… Rule.
  • Loading branch information
marabooy committed Apr 19, 2021
1 parent 66ee246 commit 243b29c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,15 @@ private IEdmVocabularyAnnotatable ComputeTarget()
container = this.schema.FindEntityContainer(targetSegments[0]);
if (container != null)
{
IEdmEntityContainerElement containerElement = container.FindEntitySetExtended(targetSegments[1]);
// Using the methods here results in a much faster lookup as it used a dictionary instead of using the list of container elements.
IEdmEntityContainerElement containerElement = container.FindEntitySetExtended(targetSegments[1])
?? container.FindSingletonExtended(targetSegments[1]) as IEdmEntityContainerElement;
if (containerElement != null)
{
return containerElement;
}


IEdmOperationImport operationImport = FindParameterizedOperationImport(targetSegments[1], container.FindOperationImportsExtended, this.CreateAmbiguousOperationImport);
if (operationImport != null)
{
Expand Down
43 changes: 21 additions & 22 deletions src/Microsoft.OData.Edm/Validation/ValidationRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2383,54 +2383,55 @@ Dependent properties | | | |
var target = annotation.Target;
bool foundTarget = false;

IEdmEntityContainer entityContainer = target as IEdmEntityContainer;
if (entityContainer != null)
if (target is IEdmEntityContainer entityContainer)
{
foundTarget = (context.Model.FindEntityContainer(entityContainer.FullName()) as IEdmEntityContainer != null);
}
else
{
IEdmEntitySet entitySet = target as IEdmEntitySet;
if (entitySet != null)
if (target is IEdmEntitySet entitySet)
{
IEdmEntityContainer container = entitySet.Container as IEdmEntityContainer;
IEdmEntityContainer container = entitySet.Container;
if (container != null)
{
foundTarget = (container.FindEntitySetExtended(entitySet.Name) != null);
}
}
else if (target is IEdmSingleton singleton)
{
IEdmEntityContainer container = singleton.Container;
if (container != null)
{
foundTarget = container.FindSingletonExtended(singleton.Name) != null;
}
}
else
{
IEdmSchemaType schemaType = target as IEdmSchemaType;
if (schemaType != null)
if (target is IEdmSchemaType schemaType)
{
foundTarget = (context.Model.FindType(schemaType.FullName()) as IEdmSchemaType != null);
}
else
{
IEdmTerm term = target as IEdmTerm;
if (term != null)
if (target is IEdmTerm term)
{
foundTarget = (context.Model.FindTerm(term.FullName()) != null);
}
else
{
IEdmOperation operation = target as IEdmOperation;
if (operation != null)
if (target is IEdmOperation operation)
{
foundTarget = context.Model.FindOperations(operation.FullName()).Any();
}
else
{
IEdmOperationImport operationImport = target as IEdmOperationImport;
if (operationImport != null)
if (target is IEdmOperationImport operationImport)
{
foundTarget = operationImport.Container.FindOperationImportsExtended(operationImport.Name).Any();
}
else
{
IEdmProperty typeProperty = target as IEdmProperty;
if (typeProperty != null)
if (target is IEdmProperty typeProperty)
{
string declaringTypeFullName = EdmUtil.FullyQualifiedName(typeProperty.DeclaringType as IEdmSchemaType);
IEdmStructuredType modelType = context.Model.FindType(declaringTypeFullName) as IEdmStructuredType;
Expand All @@ -2442,8 +2443,7 @@ Dependent properties | | | |
}
else
{
IEdmOperationParameter operationParameter = target as IEdmOperationParameter;
if (operationParameter != null)
if (target is IEdmOperationParameter operationParameter)
{
IEdmOperation declaringOperation = operationParameter.DeclaringOperation as IEdmOperation;
if (declaringOperation != null)
Expand All @@ -2460,8 +2460,7 @@ Dependent properties | | | |
}
else
{
IEdmOperationImport declaringFunctionImport = operationParameter.DeclaringOperation as IEdmOperationImport;
if (declaringFunctionImport != null)
if (operationParameter.DeclaringOperation is IEdmOperationImport declaringFunctionImport)
{
var container = declaringFunctionImport.Container as IEdmEntityContainer;
foreach (var currentFunction in container.FindOperationImportsExtended(declaringFunctionImport.Name))
Expand Down Expand Up @@ -2567,9 +2566,9 @@ Dependent properties | | | |

#region IEdmPropertyValueBinding

/// <summary>
/// Validates that the value of a property value binding is the correct type.
/// </summary>
/// <summary>
/// Validates that the value of a property value binding is the correct type.
/// </summary>
public static readonly ValidationRule<IEdmPropertyValueBinding> PropertyValueBindingValueIsCorrectType =
new ValidationRule<IEdmPropertyValueBinding>(
(context, binding) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public void OperationImportCannotImportBoundOperationTestShouldIndicateError()
{
EdmFunctionImport functionImport = new EdmFunctionImport(new EdmEntityContainer("ds.n", "Container"), "function1", new EdmFunction("ds", "func", EdmCoreModel.Instance.GetString(true), true /*IsBound*/, null, false));
ValidateError(
ValidationRules.OperationImportCannotImportBoundOperation,
functionImport,
ValidationRules.OperationImportCannotImportBoundOperation,
functionImport,
EdmErrorCode.OperationImportCannotImportBoundOperation,
Strings.EdmModel_Validator_Semantic_OperationImportCannotImportBoundOperation("function1", "func"));
}
Expand Down Expand Up @@ -160,7 +160,7 @@ public void EntitySetAndOperationImportWithSameNameShouldError()
var container = new EdmEntityContainer("ns", "container");
container.AddEntitySet("Set", DefaultValidEntityType.EntityDefinition());
container.AddActionImport("Set", new EdmAction("n", "set", null));

ValidateError(
ValidationRules.EntityContainerDuplicateEntityContainerMemberName,
container,
Expand All @@ -174,7 +174,7 @@ public void OperationImportAndEntitySetWithSameNameShouldError()
var container = new EdmEntityContainer("ns", "container");
container.AddActionImport("Set", new EdmAction("n", "set", null));
container.AddEntitySet("Set", DefaultValidEntityType.EntityDefinition());

ValidateError(
ValidationRules.EntityContainerDuplicateEntityContainerMemberName,
container,
Expand Down Expand Up @@ -486,7 +486,7 @@ public void ValidateNonEntityReturnTypeInvalid()
{
OperationOperationEntitySetPathMustBeValidValidTestModel testModelContainer = new OperationOperationEntitySetPathMustBeValidValidTestModel();

EdmFunction function = new EdmFunction("ns", "GetStuff", new EdmComplexTypeReference(new EdmComplexType("ns","complexType"), false), true /*isBound*/, new EdmPathExpression("bindingEntity/ColNav"), false);
EdmFunction function = new EdmFunction("ns", "GetStuff", new EdmComplexTypeReference(new EdmComplexType("ns", "complexType"), false), true /*isBound*/, new EdmPathExpression("bindingEntity/ColNav"), false);
function.AddParameter("bindingEntity", new EdmCollectionTypeReference(new EdmCollectionType(new EdmEntityTypeReference(testModelContainer.T3, false))));

ValidateErrorInList(
Expand Down Expand Up @@ -534,7 +534,7 @@ public void ValidateReturnTypeShouldReturnNoErrorWhenNoEntitySetPathNotValid()
OperationOperationEntitySetPathMustBeValidValidTestModel testModelContainer = new OperationOperationEntitySetPathMustBeValidValidTestModel();

EdmFunction function = new EdmFunction("ns", "GetStuff", EdmCoreModel.Instance.GetString(false), true /*isBound*/, new EdmPathExpression("bindingEntity/Nav1/Bunk.T1Foo"), false);

ValidateNoError(ValidationRules.OperationReturnTypeEntityTypeMustBeValid, testModelContainer.Model, function);
}

Expand All @@ -549,7 +549,7 @@ public OperationOperationEntitySetPathMustBeValidValidTestModel()
this.T1DerivedFromT2 = new EdmEntityType("Bunk", "T1", this.T2);

EdmStructuralProperty f31 = this.T3.AddStructuralProperty("F31", EdmCoreModel.Instance.GetString(false));
this.T3.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() {Name = "Nav1", Target = this.T2, TargetMultiplicity = EdmMultiplicity.One });
this.T3.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { Name = "Nav1", Target = this.T2, TargetMultiplicity = EdmMultiplicity.One });
this.T3.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { Name = "ColNav", Target = this.T2, TargetMultiplicity = EdmMultiplicity.Many });
this.T3.AddKeys(f31);
this.Model.AddElement(this.T3);
Expand Down Expand Up @@ -656,7 +656,7 @@ public void FunctionOverloadsWithSameBindingTypesAndSameNameWithDifferentReturnT
{
var edmFunction = new EdmFunction("n.s", "GetStuff", EdmCoreModel.Instance.GetString(true), true /*isBound*/, null /*entitySetPath*/, false /*isComposable*/);
edmFunction.AddParameter("bindingParameter", EdmCoreModel.Instance.GetInt16(true));
var edmFunction2 = new TestFunction("n.s", "GetStuff") {IsBound = true};
var edmFunction2 = new TestFunction("n.s", "GetStuff") { IsBound = true };

EdmModel model = new EdmModel();
model.AddElement(edmFunction);
Expand Down Expand Up @@ -720,8 +720,8 @@ public void DuplicateFunctionsDuplicateFunctionErrorShouldOccur()
model.AddElement(edmFunction);
model.AddElement(edmFunction2);
ValidateError(
ValidationRules.ModelDuplicateSchemaElementName,
model,
ValidationRules.ModelDuplicateSchemaElementName,
model,
EdmErrorCode.DuplicateFunctions,
Strings.EdmModel_Validator_Semantic_ModelDuplicateBoundFunctionParameterTypes("n.s.GetStuff"));
}
Expand Down Expand Up @@ -803,7 +803,7 @@ public void NavigationPropertyWrongMultiplicityForDependent()

EdmEntityType type2 = new EdmEntityType("ns", "type2");
var Id2 = type2.AddStructuralProperty("Id2", EdmCoreModel.Instance.GetInt32(false));

var foreignKey = type2.AddStructuralProperty("foreignKey", EdmCoreModel.Instance.GetInt32(true));

type1.AddKeys(Id1);
Expand All @@ -828,7 +828,7 @@ public void NavigationPropertyWrongMultiplicityForDependent()
EdmNavigationProperty navProp = type2.AddBidirectionalNavigation(navInfo2, navInfo1);

ValidateError(
ValidationRules.NavigationPropertyDependentEndMultiplicity,
ValidationRules.NavigationPropertyDependentEndMultiplicity,
navProp,
EdmErrorCode.InvalidMultiplicityOfDependentEnd,
Strings.EdmModel_Validator_Semantic_InvalidMultiplicityOfDependentEndMustBeMany("nav2"));
Expand Down Expand Up @@ -870,7 +870,7 @@ public void NavigationPropertyTypeMismatchOnReferentialConstraint()
ValidationRules.NavigationPropertyTypeMismatchRelationshipConstraint,
navProp,
EdmErrorCode.TypeMismatchRelationshipConstraint,
Strings.EdmModel_Validator_Semantic_TypeMismatchRelationshipConstraint("foreignKey","ns.type2","Id1", "type1", "Fred"));
Strings.EdmModel_Validator_Semantic_TypeMismatchRelationshipConstraint("foreignKey", "ns.type2", "Id1", "type1", "Fred"));
}

[Fact]
Expand Down Expand Up @@ -1419,6 +1419,25 @@ public void TargetOfAnAnnotationIsNotAllowedInAppliesToOfTheTermShouldError()
"EntitySet Singleton ActionImport FunctionImport", "Org.OData.Core.V1.ResourcePath"));
}

[Fact]
public void TargetOfSingletonTypeIsFound()
{
EdmModel model = new EdmModel();
EdmEntityType entity = model.AddEntityType("NS", "Entity");
entity.AddKeys(entity.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(false)));
EdmEntityContainer container = model.AddEntityContainer("NS", "Container");
EdmSingleton singleton = container.AddSingleton("Me", entity);
IEdmTerm term = model.FindTerm("Org.OData.Core.V1.Description");
EdmVocabularyAnnotation annotation = new EdmVocabularyAnnotation(singleton, term, new EdmStringConstant("Description"));
annotation.SetSerializationLocation(model,EdmVocabularyAnnotationSerializationLocation.OutOfLine);
model.SetVocabularyAnnotation(annotation);

ValidateNoError(
ValidationRules.VocabularyAnnotationInaccessibleTarget,
model,
annotation);
}

private static void ValidateNoError<T>(ValidationRule<T> validationRule, IEdmModel model, T item) where T : IEdmElement
{
ValidationContext context = new ValidationContext(model, (object o) => false);
Expand All @@ -1437,12 +1456,12 @@ private static void ValidateError<T>(ValidationRule<T> validationRule, IEdmModel
Assert.Equal(expectedError, error.ErrorMessage);
}

private static void ValidateExactErrorsInList<T>(ValidationRule<T> validationRule, IEdmModel model, T item, params Tuple<EdmErrorCode,string> [] expectedErrors) where T : IEdmElement
private static void ValidateExactErrorsInList<T>(ValidationRule<T> validationRule, IEdmModel model, T item, params Tuple<EdmErrorCode, string>[] expectedErrors) where T : IEdmElement
{
ValidationContext context = new ValidationContext(model, (object o) => false);
validationRule.Evaluate(context, item);
int currentIndex = 0;
foreach(var actualError in context.Errors)
foreach (var actualError in context.Errors)
{
Assert.Equal(expectedErrors[currentIndex].Item1, actualError.ErrorCode);
Assert.Equal(expectedErrors[currentIndex].Item2, actualError.ErrorMessage);
Expand All @@ -1456,12 +1475,12 @@ private static void ValidateErrorInList<T>(ValidationRule<T> validationRule, IEd
{
ValidationContext context = new ValidationContext(model, (object o) => false);
validationRule.Evaluate(context, item);
var error = context.Errors.SingleOrDefault(e=>e.ErrorCode == expectedErrorCode);
var error = context.Errors.SingleOrDefault(e => e.ErrorCode == expectedErrorCode);
Assert.NotNull(error);
Assert.Equal(expectedError, error.ErrorMessage);
}

private static void ValidateError<T>(ValidationRule<T> validationRule, T item, EdmErrorCode expectedErrorCode, string expectedError) where T:IEdmElement
private static void ValidateError<T>(ValidationRule<T> validationRule, T item, EdmErrorCode expectedErrorCode, string expectedError) where T : IEdmElement
{
ValidateError(validationRule, new EdmModel(), item, expectedErrorCode, expectedError);
}
Expand Down Expand Up @@ -1491,7 +1510,7 @@ internal TestFunction(string namespaceName, string name)

public IEdmOperationParameter FindParameter(string name)
{
return this.Parameters.Single(p=>p.Name == name);
return this.Parameters.Single(p => p.Name == name);
}

public EdmSchemaElementKind SchemaElementKind
Expand Down

0 comments on commit 243b29c

Please sign in to comment.