public void ValidateOpenComplexTypeSupported()
        {
            var ct = new StubEdmComplexType("NS1", "CT1")
            {
                IsOpen = true
            };
            ct.Add(new EdmStructuralProperty(ct, "p1", EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Int16, true)));

            var model = new EdmModel();
            model.AddElement(ct);

            IEnumerable<EdmError> errors;

            foreach (var v in new[] { Microsoft.OData.Edm.Library.EdmConstants.EdmVersionLatest })
            {
                model.SetEdmVersion(v);
                model.Validate(out errors);
                Assert.AreEqual(0, errors.Count(), "No error should be returned");
            }
        }
        public void CsdlWriterShouldFailWithGoodMessageWhenWritingInvalidXml()
        {
            var model = new EdmModel();
            model.SetEdmVersion(Microsoft.OData.Edm.Library.EdmConstants.EdmVersion4);
            var fredFlintstone = new EdmComplexType("Flintstones", "Fred");
            fredFlintstone.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(false));
            model.AddElement(fredFlintstone);

            // set annotation which will be serialzed (because the value is an IEdmValue) with a name that doesn't match the xml spec for NCName.
            model.SetAnnotationValue(fredFlintstone, "sap", "-contentversion", new EdmStringConstant(EdmCoreModel.Instance.GetString(false), "hello"));

            Assert.AreEqual(1, model.DirectValueAnnotations(fredFlintstone).Count(), "Wrong # of Annotations on {0}.", fredFlintstone);

            var stringWriter = new StringWriter();
            var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings() { Indent = true });

            try
            {
                IEnumerable<EdmError> errors;
                model.TryWriteCsdl(xmlWriter, out errors);
                Assert.Fail("Excepted an exception when trying to serialize a direct value annotation which does not match the xml naming spec.");
            }
            catch (ArgumentException e)
            {
                Assert.AreEqual(e.Message, "Invalid name character in '-contentversion'. The '-' character, hexadecimal value 0x2D, cannot be included in a name.", "Expected exception message did not match.");
            }

            xmlWriter.Close();
        }
        public void ComplexValueIgnorePropertyNullValuesTest()
        {
            var versions = new Version[] {
                    null,
                    new Version(4, 0),
                };

            EdmModel edmModel = new EdmModel();
            IEdmComplexType countryRegionType = edmModel.ComplexType("CountryRegion")
                .Property("Name", EdmPrimitiveTypeKind.String)
                .Property("CountryRegionCode", EdmPrimitiveTypeKind.String);
            IEdmComplexType countryRegionNullType = edmModel.ComplexType("CountryRegionNull")
                .Property("Name", EdmPrimitiveTypeKind.String)
                .Property("CountryRegionCode", EdmPrimitiveTypeKind.String);
            IEdmComplexType addressType = edmModel.ComplexType("Address")
                .Property("Street", EdmPrimitiveTypeKind.String)
                .Property("StreetNull", EdmCoreModel.Instance.GetString(true) as EdmTypeReference)
                .Property("Numbers", EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetInt32(false)) as EdmTypeReference)
                .Property("CountryRegion", new EdmComplexTypeReference(countryRegionType, false))
                .Property("CountryRegionNull", new EdmComplexTypeReference(countryRegionNullType, true));
            edmModel.EntityType("Customer")
                .KeyProperty("ID", EdmCoreModel.Instance.GetInt32(false) as EdmTypeReference)
                .Property("Address", new EdmComplexTypeReference(addressType, false));
            edmModel.Fixup();

            this.CombinatorialEngineProvider.RunCombinations(
                new ODataNullValueBehaviorKind[] { ODataNullValueBehaviorKind.Default, ODataNullValueBehaviorKind.DisableValidation, ODataNullValueBehaviorKind.IgnoreValue },
                versions,
                versions,
                TestReaderUtils.ODataBehaviorKinds,
                (nullPropertyValueReaderBehavior, dataServiceVersion, edmVersion, behaviorKind) =>
                {
                    edmModel.SetEdmVersion(edmVersion);

                    // Now we set the 'IgnoreNullValues' annotation on all properties
                    IEdmComplexType edmAddressType = (IEdmComplexType)edmModel.FindType("TestModel.Address");
                    foreach (IEdmStructuralProperty edmProperty in edmAddressType.StructuralProperties())
                    {
                        edmModel.SetNullValueReaderBehavior(edmProperty, nullPropertyValueReaderBehavior);
                    }

                    EntityInstance customerPayload = PayloadBuilder.Entity("TestModel.Customer")
                        .PrimitiveProperty("ID", 1)
                        .Property("Address", PayloadBuilder.ComplexValue("TestModel.Address")
                            .PrimitiveProperty("Street", "One Microsoft Way")
                            .PrimitiveProperty("StreetNull", "One Microsoft Way")
                            .Property("Numbers", PayloadBuilder.PrimitiveMultiValue("Collection(Edm.Int32)").Item(1).Item(2))
                            .Property("CountryRegion", PayloadBuilder.ComplexValue("TestModel.CountryRegion")
                                .PrimitiveProperty("Name", "Austria")
                                .PrimitiveProperty("CountryRegionCode", "AUT"))
                            .Property("CountryRegionNull", PayloadBuilder.ComplexValue("TestModel.CountryRegionNull")
                                .PrimitiveProperty("Name", "Austria")
                                .PrimitiveProperty("CountryRegionCode", "AUT")));

                    var testCases = new[]
                    {
                        // Complex types that are not nullable should not allow null values.
                        // Null primitive property in the payload and non-nullable property in the model
                        new IgnoreNullValueTestCase
                        {
                            PropertyName = "Street",
                            ExpectedResponseException = ODataExpectedExceptions.ODataException("ReaderValidationUtils_NullNamedValueForNonNullableType", "Street", "Edm.String"),
                        },
                         // Null complex property in the payload and non-nullable property in the model
                        new IgnoreNullValueTestCase
                        {
                            PropertyName = "CountryRegion",
                            ExpectedResponseException = ODataExpectedExceptions.ODataException("ReaderValidationUtils_NullNamedValueForNonNullableType", "CountryRegion", "TestModel.CountryRegion"),
                        },
                        // Null collection property in the payload and non-nullable property in the model
                        new IgnoreNullValueTestCase
                        {
                            PropertyName = "Numbers",
                            ExpectedResponseException = ODataExpectedExceptions.ODataException("ReaderValidationUtils_NullNamedValueForNonNullableType", "Numbers", "Collection(Edm.Int32)"),
                        },
                        // Complex types that are nullable should allow null values.
                        // Null primitive property in the payload and nullable property in the model
                        new IgnoreNullValueTestCase
                        {
                            PropertyName = "StreetNull",
                        },
                        // Null complex property in the payload and nullable property in the model
                        new IgnoreNullValueTestCase
                        {
                            PropertyName = "CountryRegionNull",
                        },
                    };

                    Func<IgnoreNullValueTestCase, ReaderTestConfiguration, PayloadReaderTestDescriptor> createTestDescriptor =
                        (testCase, testConfig) =>
                        {
                            EntityInstance payloadValue = customerPayload.DeepCopy();
                            ComplexInstance payloadAddressValue = ((ComplexProperty)payloadValue.GetProperty("Address")).Value;
                            SetToNull(payloadAddressValue, testCase.PropertyName);

                            ComplexInstance resultValue = payloadValue;
                            if (testConfig.IsRequest && nullPropertyValueReaderBehavior == ODataNullValueBehaviorKind.IgnoreValue)
                            {
                                resultValue = customerPayload.DeepCopy();
                                ComplexInstance resultAddressValue = ((ComplexProperty)resultValue.GetProperty("Address")).Value;
                                resultAddressValue.Remove(resultAddressValue.GetProperty(testCase.PropertyName));
                            }

                            return new PayloadReaderTestDescriptor(this.Settings)
                            {
                                PayloadElement = payloadValue,
                                PayloadEdmModel = edmModel,
                                ExpectedResultPayloadElement = 
                                    tc =>
                                    {
                                        if (tc.Format == ODataFormat.Json)
                                        {
                                            // under the client knob ODL will compute edit links, ids, etc
                                            // so we need to update the expected payload
                                            if (tc.RunBehaviorKind == TestODataBehaviorKind.WcfDataServicesClient)
                                            {
                                                var entity = resultValue as EntityInstance;
                                                if (entity != null)
                                                {
                                                    if (!tc.IsRequest)
                                                    {
                                                        entity.Id = "http://odata.org/test/Customer(1)";
                                                        entity.EditLink = "http://odata.org/test/Customer(1)";
                                                        entity.WithSelfLink("http://odata.org/test/Customer(1)");
                                                    }
                                                }
                                            } 
                                            
                                            var tempDescriptor = new PayloadReaderTestDescriptor(this.Settings)
                                            {
                                                PayloadElement = resultValue,
                                                PayloadEdmModel = edmModel,
                                            };

                                            JsonLightPayloadElementFixup.Fixup(tempDescriptor);
                                            return tempDescriptor.PayloadElement;
                                        }

                                        return resultValue;
                                    },
                                ExpectedException = (testConfig.IsRequest && nullPropertyValueReaderBehavior != ODataNullValueBehaviorKind.Default) ? null : testCase.ExpectedResponseException
                            };
                        };

                    this.CombinatorialEngineProvider.RunCombinations(
                        testCases,
                        this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations,
                        (testCase, testConfiguration) =>
                        {
                            testConfiguration = testConfiguration.CloneAndApplyBehavior(behaviorKind);
                            testConfiguration.MessageReaderSettings.BaseUri = null;

                            PayloadReaderTestDescriptor testDescriptor = createTestDescriptor(testCase, testConfiguration);
                            testDescriptor.RunTest(testConfiguration);
                        });
                });
        }
        public void AnnotationNameWhichIsNotSimpleIdentifierShouldPassValidation()
        {
            var model = new EdmModel();
            model.SetEdmVersion(Microsoft.OData.Edm.Library.EdmConstants.EdmVersion4);
            var fredFlintstone = new EdmComplexType("Flintstones", "Fred");
            fredFlintstone.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(false));
            model.AddElement(fredFlintstone);

            // set the annotation name to a value which is valid XML, but not a valid SimpleIdentifier.
            model.SetAnnotationValue(fredFlintstone, "sap", "content-version", new EdmStringConstant(EdmCoreModel.Instance.GetString(false), "hello"));

            Assert.AreEqual(1, model.DirectValueAnnotations(fredFlintstone).Count(), "Wrong # of Annotations on {0}.", fredFlintstone);

            IEnumerable<EdmError> errors;
            model.Validate(out errors);
            Assert.AreEqual(0, errors.Count(), "Model expected to be valid.");
        }
        public void NullPropertyTypeNameTest()
        {
            Version[] versions = new Version[] {
                null,
                new Version(4, 0),
            };

            var innerComplexType = new EdmComplexType("TestNS", "ComplexType");
            innerComplexType.AddStructuralProperty("NumberProperty", EdmCoreModel.Instance.GetInt32(true));
            innerComplexType.AddStructuralProperty("StringProperty", EdmCoreModel.Instance.GetString(true));

            var outerComplexType = new EdmComplexType("TestNS", "ComplexType");
            outerComplexType.AddStructuralProperty("NumberProperty", EdmCoreModel.Instance.GetInt32(true));
            outerComplexType.AddStructuralProperty("StringProperty", EdmCoreModel.Instance.GetString(true));
            outerComplexType.AddStructuralProperty("InnerComplex", new EdmComplexTypeReference(innerComplexType, true));

            var model = new EdmModel();
            var complexType = new EdmComplexType("TestNS", "ComplexType");
            complexType.AddStructuralProperty("NumberProperty", EdmCoreModel.Instance.GetInt32(true));
            complexType.AddStructuralProperty("StringProperty", EdmCoreModel.Instance.GetString(true));
            complexType.AddStructuralProperty("InnerComplex", new EdmComplexTypeReference(innerComplexType, true));
            model.AddElement(complexType);

            var entityType = new EdmEntityType("TestNS", "EntityType", null, false, true);
            entityType.AddStructuralProperty("NumberProperty", EdmCoreModel.Instance.GetInt32(true));
            entityType.AddStructuralProperty("StringProperty", EdmCoreModel.Instance.GetString(true));
            entityType.AddStructuralProperty("ComplexProperty", new EdmComplexTypeReference(outerComplexType, true));

            model.AddElement(entityType);

            var container = new EdmEntityContainer("TestNS", "DefaultContainer");
            model.AddElement(container);

            var testDescriptorSet = versions.SelectMany(dataServiceVersion =>
                versions.SelectMany(edmVersion =>
                {
                    model.SetEdmVersion(edmVersion);

                    // Client only writes type for primitive properties with null value, Server writes it for both primitive and complex.
                    // Edm.String is never written as the default is Edm.String.
                    var testCases = new[]
                        {
                            new { PropertyName = "NumberProperty", ExpectedServerTypeName = "Edm.Int32", ExpectedClientTypeName = "Edm.Int32" },
                            new { PropertyName = "StringProperty", ExpectedServerTypeName = (string)null, ExpectedClientTypeName = (string)null },
                            new { PropertyName = "ComplexProperty", ExpectedServerTypeName = "TestNS.ComplexType", ExpectedClientTypeName = (string)null },
                            new { PropertyName = "OpenProperty", ExpectedServerTypeName = (string)null, ExpectedClientTypeName = (string)null },
                            new { PropertyName = "OpenProperty", ExpectedServerTypeName = (string)null, ExpectedClientTypeName = (string)null },
                            new { PropertyName = "ComplexProperty/NumberProperty", ExpectedServerTypeName = "Edm.Int32", ExpectedClientTypeName = "Edm.Int32" },
                            new { PropertyName = "ComplexProperty/StringProperty", ExpectedServerTypeName = (string)null, ExpectedClientTypeName = (string)null },
                            new { PropertyName = "ComplexProperty/InnerComplex", ExpectedServerTypeName = "TestNS.ComplexType", ExpectedClientTypeName = (string)null },
                            new { PropertyName = "ComplexProperty/InnerComplex/NumberProperty", ExpectedServerTypeName = "Edm.Int32", ExpectedClientTypeName = "Edm.Int32" },
                            new { PropertyName = "ComplexProperty/InnerComplex/StringProperty", ExpectedServerTypeName = (string)null, ExpectedClientTypeName = (string)null },
                        };

                    return testCases.Select(testCase =>
                    {
                        string[] propertyPath = testCase.PropertyName.Split('/');
                        ODataProperty property = new ODataProperty { Name = propertyPath[propertyPath.Length - 1], Value = null };
                        for (int i = propertyPath.Length - 2; i >= 0; i--)
                        {
                            property = new ODataProperty
                            {
                                Name = propertyPath[i],
                                Value = new ODataComplexValue
                                {
                                    Properties = new[] { property }
                                }
                            };
                        }

                        Func<XElement, XElement> extractor = (result) =>
                        {
                            result = TestAtomUtils.ExtractPropertiesFromEntry(result);
                            foreach (string name in propertyPath)
                            {
                                result = result.Element(TestAtomConstants.ODataXNamespace + name);
                            }

                            return result;
                        };

                        return new Func<TestODataBehaviorKind, ODataVersion, PayloadWriterTestDescriptor<ODataItem>>(
                            (behaviorKind, version) =>
                            {
                                string expectedTypeName = null;
                                switch (behaviorKind)
                                {
                                    case TestODataBehaviorKind.Default:
                                        break;
                                    case TestODataBehaviorKind.WcfDataServicesClient:
                                        expectedTypeName = testCase.ExpectedClientTypeName;
                                        break;
                                    case TestODataBehaviorKind.WcfDataServicesServer:
                                        expectedTypeName = testCase.ExpectedServerTypeName;
                                        break;
                                }

                                // Starting with V3, we only support the standard behavior
                                expectedTypeName = null;

                                return new PayloadWriterTestDescriptor<ODataItem>(
                                    this.Settings,
                                    new ODataEntry()
                                    {
                                        TypeName = "TestNS.EntityType",
                                        Properties = new[] { property },
                                        SerializationInfo = new ODataFeedAndEntrySerializationInfo()
                                        {
                                            NavigationSourceEntityTypeName = "TestNS.EntityType",
                                            NavigationSourceName = "MySet",
                                            ExpectedTypeName = "TestNS.EntityType"
                                        }
                                    },
                                    (tc) => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                                    {
                                        Xml = expectedTypeName == null ? "<type/>" : "<type>" + expectedTypeName + "</type>",
                                        FragmentExtractor = (result) => new XElement("type",
                                            (string)extractor(result).Attribute(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.AtomTypeAttributeName))
                                    }
                                    ) { Model = model };
                            });
                    });
                }));

            this.CombinatorialEngineProvider.RunCombinations(
                TestWriterUtils.ODataBehaviorKinds,
                testDescriptorSet,
                this.WriterTestConfigurationProvider.AtomFormatConfigurationsWithIndent,
                (behaviorKind, testDescriptor, testConfiguration) =>
                {
                    testConfiguration = testConfiguration.CloneAndApplyBehavior(behaviorKind);
                    testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);
                    TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor(behaviorKind, testConfiguration.Version), testConfiguration, this.Assert, this.Logger);
                });
        }