public OperationSerializerTests()
        {
            ResourceType intType = ResourceType.GetPrimitiveResourceType(typeof(int));

            var customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "FQ.NS", "Customer", false);
            customerType.CanReflectOnInstanceType = false;
            customerType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, intType) { CanReflectOnInstanceTypeProperty = false });
            customerType.SetReadOnly();

            var operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", intType) }, null);
            operation.SetReadOnly();
            this.baseTypeOperation = new OperationWrapper(operation);

            var bestCustomerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, customerType, "FQ.NS", "BestCustomer", false);
            bestCustomerType.SetReadOnly();

            operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", bestCustomerType) }, null);
            operation.SetReadOnly();
            this.derivedTypeOperation = new OperationWrapper(operation);

            operation = new ServiceAction("Unambiguous", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType) }, null);
            operation.SetReadOnly();
            this.unambiguousOperation = new OperationWrapper(operation);

            this.entityToSerialize = EntityToSerialize.CreateFromExplicitValues(new object(), bestCustomerType, new TestSerializedEntityKey("http://odata.org/Service.svc/Customers(0)/", bestCustomerType.FullName));

            this.testSubject = CreateOperationSerializer(AlwaysAdvertiseActions);
        }
        public void DataServiceProviderWrapperShouldFailOnMultipleActionsWithSameNameAndBindingType()
        {
            var entityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Fake.NS", "Type", false) { CanReflectOnInstanceType = false };
            entityType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Key | ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(int))) {CanReflectOnInstanceTypeProperty = false});
            entityType.SetReadOnly();

            var resourceSet = new ResourceSet("MyEntitySet", entityType);
            resourceSet.SetReadOnly();

            ResourceType stringType = ResourceType.GetPrimitiveResourceType(typeof(string));
            var duplicateAction1 = new ServiceAction("Duplicate", stringType, OperationParameterBindingKind.Always, new[] { new ServiceActionParameter("p1", entityType), new ServiceActionParameter("p2", stringType) }, null);
            duplicateAction1.SetReadOnly();
            var duplicateAction2 = new ServiceAction("Duplicate", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("p1", entityType) }, null);
            duplicateAction2.SetReadOnly();

            var actionProvider = new TestActionProvider
            {
                GetServiceActionsCallback = ctx => new[] { duplicateAction1, duplicateAction2 }
            };

            var providerWrapper = CreateProviderWrapper(actionProvider, p => p.AddResourceSet(resourceSet));

            Action getVisibleOperations = () => providerWrapper.GetVisibleOperations().ToList();
            getVisibleOperations.ShouldThrow<DataServiceException>()
                .WithMessage(ErrorStrings.DataServiceActionProviderWrapper_DuplicateAction("Duplicate"))
                .And.StatusCode.Should().Be(500);
        }
        public OperationLinkBuilderTests()
        {
            ResourceType intType = ResourceType.GetPrimitiveResourceType(typeof(int));

            var customerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "FQ.NS", "Customer", false);
            customerType.CanReflectOnInstanceType = false;
            customerType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Primitive | ResourcePropertyKind.Key, intType) { CanReflectOnInstanceTypeProperty = false });
            customerType.SetReadOnly();

            var operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", intType) }, null);
            operation.SetReadOnly();
            this.operationWithParameters = new OperationWrapper(operation);

            var typeWithEscapedName = new ResourceType(typeof(object), ResourceTypeKind.ComplexType, null, "FQ NS", "+ /", false);
            typeWithEscapedName.CanReflectOnInstanceType = false;
            typeWithEscapedName.AddProperty(new ResourceProperty("Number", ResourcePropertyKind.Primitive, intType) { CanReflectOnInstanceTypeProperty = false });
            typeWithEscapedName.SetReadOnly();

            operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType), new ServiceActionParameter("P2", typeWithEscapedName) }, null);
            operation.SetReadOnly();
            this.operationWithEscapedParameter = new OperationWrapper(operation);

            var bestCustomerType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, customerType, "FQ.NS", "BestCustomer", false);
            bestCustomerType.SetReadOnly();

            operation = new ServiceAction("Action", intType, OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("P1", customerType) }, null);
            operation.SetReadOnly();
            this.operationBoundToBaseType = new OperationWrapper(operation);

            this.entityToSerialize = EntityToSerialize.CreateFromExplicitValues(new object(), bestCustomerType, new TestSerializedEntityKey("http://odata.org/Service.svc/Customers/", bestCustomerType.FullName));

            var metadataUri = new Uri("http://odata.org/Service.svc/$metadata");
            this.testSubject = new OperationLinkBuilder("MyContainer", metadataUri);
        }
        public void MetadataProviderModelShouldGoDirectlyToProviderWhenLookingUpOperationsInSelect()
        {
            var entityType = CreateResourceTypeWithKeyProperties("Id");
            var derivedType = CreateDerivedType("Derived", entityType);
            var veryDerivedType = CreateDerivedType("VeryDerived", derivedType);
            var unrelatedDerivedType = CreateDerivedType("UnrelatedDerived", entityType);
            var action1 = new ServiceAction("Action", null, null, OperationParameterBindingKind.Always, new[] { new ServiceActionParameter("p1", entityType) });
            var action2 = new ServiceAction("Action", null, null, OperationParameterBindingKind.Always, new[] { new ServiceActionParameter("p1", derivedType) });
            var actionWithDifferentName = new ServiceAction("Action2", null, null, OperationParameterBindingKind.Always, new[] { new ServiceActionParameter("p1", derivedType) });
            var action3 = new ServiceAction("Action", null, null, OperationParameterBindingKind.Always, new[] { new ServiceActionParameter("p1", veryDerivedType) });
            action1.SetReadOnly();
            action2.SetReadOnly();
            actionWithDifferentName.SetReadOnly();
            action3.SetReadOnly();
            int calls = 0;
            var actionProvider = new TestActionProvider
                                 {
                                     GetByBindingTypeCallback = (o, t) =>
                                     {
                                         calls++;

                                         if (t == entityType)
                                         {
                                             return new[] { action1 };
                                         }

                                         if (t == derivedType)
                                         {
                                             return new[] { action2, actionWithDifferentName };
                                         }

                                         if (t == veryDerivedType)
                                         {
                                             return new[] { action3 };
                                         }

                                         t.Should().NotBeSameAs(unrelatedDerivedType);
                                         return null;
                                     }};

            var metadataProvider = new DataServiceProviderSimulator();
            metadataProvider.AddResourceType(entityType);
            metadataProvider.AddResourceType(derivedType);
            metadataProvider.AddResourceType(veryDerivedType);
            metadataProvider.AddResourceType(unrelatedDerivedType);
            var model = CreateMetadataProviderEdmModel(metadataProvider, actionProvider);
            var schemaType = (IEdmEntityType)model.EnsureSchemaType(derivedType);
            var result = model.FindDeclaredBoundOperations(schemaType).FilterByName(false, "Action");
            result.Should().NotBeNull();
            result.Should().HaveCount(3);
            result.Should().OnlyContain(f => f.Name == "Action");
            calls.Should().Be(3);
        }
        public void DataServiceProviderWrapperShouldFailOnMultipleActionsWithSameNameAndNoBindingType()
        {
            ResourceType stringType = ResourceType.GetPrimitiveResourceType(typeof(string));
            var duplicateAction1 = new ServiceAction("Duplicate", stringType, OperationParameterBindingKind.Never, new[] { new ServiceActionParameter("p1", stringType) }, null);
            duplicateAction1.SetReadOnly();
            var duplicateAction2 = new ServiceAction("Duplicate", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Never, new ServiceActionParameter[0], null);
            duplicateAction2.SetReadOnly();

            var actionProvider = new TestActionProvider
            {
                GetServiceActionsCallback = ctx => new[] { duplicateAction1, duplicateAction2 }
            };

            var providerWrapper = CreateProviderWrapper(actionProvider);

            Action getVisibleOperations = () => providerWrapper.GetVisibleOperations().ToList();
            getVisibleOperations.ShouldThrow<DataServiceException>()
                .WithMessage(ErrorStrings.DataServiceActionProviderWrapper_DuplicateAction("Duplicate"))
                .And.StatusCode.Should().Be(500);
        }
        protected override IEnumerable<ServiceAction> LoadServiceActions(IDataServiceMetadataProvider dataServiceMetadataProvider)
        {
            ResourceType employeeType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Employee", out employeeType);
            ResourceType computerDetailType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.ComputerDetail", out computerDetailType);
            ResourceType computerType;          
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Computer", out computerType);
            ResourceType customerType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Customer", out customerType);
            ResourceType auditInfoType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.AuditInfo", out auditInfoType);            
            ResourceSet computerSet;
            dataServiceMetadataProvider.TryResolveResourceSet("Computer", out computerSet);
            var increaseSalaryAction = new ServiceAction(
                 "IncreaseSalaries",
                 null,
                 null,
                 OperationParameterBindingKind.Always,
                 new[]
                {
                    new ServiceActionParameter("employees", ResourceType.GetEntityCollectionResourceType(employeeType)),
                    new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
                });

            increaseSalaryAction.SetReadOnly();

            yield return increaseSalaryAction;

            var sackEmployeeAction = new ServiceAction(
                "Sack",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
                {
                    new ServiceActionParameter("employee", employeeType), 
                });

            sackEmployeeAction.SetReadOnly();

            yield return sackEmployeeAction;

            var getComputerAction = new ServiceAction(
                "GetComputer",
                computerType,
                OperationParameterBindingKind.Always,
                new[]
                {
                    new ServiceActionParameter("computer", computerType)
                },
                new ResourceSetPathExpression("computer"));

            getComputerAction.SetReadOnly();

            yield return getComputerAction;
             
            var changeCustomerAuditInfoAction = new ServiceAction(
               "ChangeCustomerAuditInfo",
               null,
               null,
               OperationParameterBindingKind.Always,
               new[]
                {
                
                    new ServiceActionParameter("customer", customerType), 
                    new ServiceActionParameter("auditInfo", auditInfoType),
                });

            changeCustomerAuditInfoAction.SetReadOnly();

            yield return changeCustomerAuditInfoAction;

             var resetComputerDetailsSpecificationsAction = new ServiceAction(
                "ResetComputerDetailsSpecifications",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
                {
                    new ServiceActionParameter("computerDetail", computerDetailType), 
                    new ServiceActionParameter("specifications", ResourceType.GetCollectionResourceType(ResourceType.GetPrimitiveResourceType(typeof(string)))),
                    new ServiceActionParameter("purchaseTime", ResourceType.GetPrimitiveResourceType(typeof(DateTimeOffset)))
                });

            resetComputerDetailsSpecificationsAction.SetReadOnly();

            yield return resetComputerDetailsSpecificationsAction;
        }
        protected override IEnumerable<ServiceAction> LoadServiceActions(IDataServiceMetadataProvider dataServiceMetadataProvider)
        {
            ResourceType productType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Product", out productType);

            ResourceType orderLineType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.OrderLine", out orderLineType);

            ResourceType personType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Person", out personType);

            ResourceType employeeType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Employee", out employeeType);

            ResourceType specialEmployeeType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.SpecialEmployee", out specialEmployeeType);

            ResourceType contractorType;
            dataServiceMetadataProvider.TryResolveResourceType("Microsoft.Test.OData.Services.AstoriaDefaultService.Contractor", out contractorType);

            //
            // actions with the same name and non-related binding types
            //
            var RetrieveProductActionProduct = new ServiceAction(
                "RetrieveProduct",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("product", productType), 
                });
            RetrieveProductActionProduct.SetReadOnly();
            yield return RetrieveProductActionProduct;

            var RetrieveProductActionOrderLine = new ServiceAction(
                "RetrieveProduct",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("orderLine", orderLineType), 
                });
            RetrieveProductActionOrderLine.SetReadOnly();
            yield return RetrieveProductActionOrderLine;

            //
            // Collection bound actions with the same name
            //
            var increaseSalariesActionEmployee = new ServiceAction(
                "IncreaseSalaries",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("employees", ResourceType.GetEntityCollectionResourceType(employeeType)),
                    new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
                });
            increaseSalariesActionEmployee.SetReadOnly();
            yield return increaseSalariesActionEmployee;

            var increaseSalariesActionSpecialEmployee = new ServiceAction(
                "IncreaseSalaries",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("specialEmployees", ResourceType.GetEntityCollectionResourceType(specialEmployeeType)),
                    new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
                });
            increaseSalariesActionSpecialEmployee.SetReadOnly();
            yield return increaseSalariesActionSpecialEmployee;

            //
            // Actions with the same name and base/derived type binding parameters
            //
            var updatePersonInfoAction = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Never,
                null);
            updatePersonInfoAction.SetReadOnly();
            yield return updatePersonInfoAction;

            var updatePersonInfoActionPerson = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("person", personType), 
                });
            updatePersonInfoActionPerson.SetReadOnly();
            yield return updatePersonInfoActionPerson;

            var updatePersonInfoActionEmployee = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("employee", employeeType), 
                });
            updatePersonInfoActionEmployee.SetReadOnly();
            yield return updatePersonInfoActionEmployee;

            var updatePersonInfoActionSpecialEmployee = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("specialEmployee", specialEmployeeType), 
                });
            updatePersonInfoActionSpecialEmployee.SetReadOnly();
            yield return updatePersonInfoActionSpecialEmployee;

            var updatePersonInfoActionContractor = new ServiceAction(
                "UpdatePersonInfo",
                null,
                null,
                OperationParameterBindingKind.Always,
                new[]
                {
                    new ServiceActionParameter("contractor", contractorType), 
                });
            updatePersonInfoActionContractor.SetReadOnly();
            yield return updatePersonInfoActionContractor;

            //
            // Actions with the same name, base/derived type binding parameters, different non-binding parameters
            //
            var increaseEmployeeSalaryActionEmployee = new ServiceAction(
                "IncreaseEmployeeSalary",
                ResourceType.GetPrimitiveResourceType(typeof(bool)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("employee", employeeType),
                    new ServiceActionParameter("n", ResourceType.GetPrimitiveResourceType(typeof(int))),
                });
            increaseEmployeeSalaryActionEmployee.SetReadOnly();
            yield return increaseEmployeeSalaryActionEmployee;

            var increaseEmployeeSalaryActionSpecialEmployee = new ServiceAction(
                "IncreaseEmployeeSalary",
                ResourceType.GetPrimitiveResourceType(typeof(int)),
                null,
                OperationParameterBindingKind.Sometimes,
                new[]
                {
                    new ServiceActionParameter("specialEmployee", specialEmployeeType),
                });
            increaseEmployeeSalaryActionSpecialEmployee.SetReadOnly();
            yield return increaseEmployeeSalaryActionSpecialEmployee;
        }