/// <summary> /// Puts the specified <paramref name="payload"/> into a property. /// </summary> /// <param name="payload">The payload to put into a property. This payload must represent a simple value (primitive, complex, collection).</param> /// <param name="propertyName">Optional name of the property to generate.</param> /// <returns>A property payload with the <paramref name="payload"/> as its value.</returns> public static PayloadReaderTestDescriptor InProperty(this PayloadReaderTestDescriptor payload, string propertyName = null) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.InProperty(propertyName) }); }
/// <summary> /// Takes the <paramref name="navPropertyPayload"/> that represents a deferred navigation property and expands it by creating a new entity type, /// adding it to the model and then creating <paramref name="count"/> entities for the new type that act as content of the expanded link. /// </summary> /// <param name="navPropertyPayload">The deferred navigation property payload to be expanded.</param> /// <param name="isSingleton">true if a singleton navigation property should be expanded; otherwise false.</param> /// <param name="count">The number of entries to be used as expanded payload. Has to be '1' for singleton navigation properties.</param> /// <param name="nextLink">An optional next link to be used in an expanded link with a feed payload (requires <paramref name="isSingleton"/> to be false).</param> /// <returns>A new test descriptor with the expanded navigation property.</returns> public static PayloadReaderTestDescriptor ExpandNavigationProperty(this PayloadReaderTestDescriptor payload, bool isSingleton, uint count = 1, string nextLink = null) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.ExpandNavigationProperty(isSingleton, count, nextLink) }); }
/// <summary> /// Makes sure to ignore top-level feed payloads in requests if the version is greater than V1. /// This is needed because for feeds in requests the MS-OData spec does not define a format and we /// thus use the V1 format. /// </summary> /// <param name="descriptor">The test descriptor to filter.</param> /// <returns> /// The same or a new <see cref="PayloadReaderTestDescriptor"/> that ensures that top-level feed /// payloads are ignored in requests of versions greater than V1. /// </returns> public static PayloadReaderTestDescriptor FilterTopLevelFeed(this PayloadReaderTestDescriptor payload) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.FilterTopLevelFeed() }); }
public void DeferredLinkTest() { IEdmModel model = Test.OData.Utils.Metadata.TestModels.BuildTestModel(); var cityType = model.FindType("TestModel.CityType"); Debug.Assert(cityType != null, "cityType != null"); // TODO: add test cases that use relative URIs // Few hand-crafted payloads IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { // Single deferred link new PayloadReaderTestDescriptor(this.Settings) { PayloadDescriptor = new PayloadTestDescriptor(), PayloadElement = PayloadBuilder.Entity("TestModel.CityType").PrimitiveProperty("Id", 1).WithTypeAnnotation(cityType) .NavigationProperty("CityHall", "http://odata.org/CityHall"), PayloadEdmModel = model }, // Multiple deferred links new PayloadReaderTestDescriptor(this.Settings) { PayloadDescriptor = new PayloadTestDescriptor(), PayloadElement = PayloadBuilder.Entity("TestModel.CityType").PrimitiveProperty("Id", 1).WithTypeAnnotation(cityType) .NavigationProperty("CityHall", "http://odata.org/CityHall") .NavigationProperty("DOL", "http://odata.org/DOL"), PayloadEdmModel = model }, // Multiple deferred links with primitive properties in between new PayloadReaderTestDescriptor(this.Settings) { PayloadDescriptor = new PayloadTestDescriptor(), PayloadElement = PayloadBuilder.Entity("TestModel.CityType").WithTypeAnnotation(cityType) .Property("Id", PayloadBuilder.PrimitiveValue(1)) .NavigationProperty("CityHall", "http://odata.org/CityHall") .Property("Name", PayloadBuilder.PrimitiveValue("Vienna")) .NavigationProperty("DOL", "http://odata.org/DOL"), PayloadEdmModel = model }, }; // Add standard deferred link payloads testDescriptors = testDescriptors.Concat(PayloadReaderTestDescriptorGenerator.CreateDeferredNavigationLinkTestDescriptors(this.Settings, true)); // Generate interesting payloads around the entry testDescriptors = testDescriptors.SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td)); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, // Deferred links are response only. // TODO: Reenable Json Light support this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => !tc.IsRequest && tc.Format == ODataFormat.Atom), (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Creates a set of interesting entity reference link instances. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <returns>List of test descriptors with interesting entity reference link instances as payload.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateEntityReferenceLinkDescriptors(PayloadReaderTestDescriptor.Settings settings) { return CreateEntityReferenceLinkValues().Select(erl => new PayloadReaderTestDescriptor(settings) { PayloadElement = erl, }); }
public void TopLevelPropertyTest() { var testDescriptors = new PayloadReaderTestDescriptor[] { new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty(null, "foo") .XmlRepresentation("<value xmlns=''>42</value>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomPropertyAndValueDeserializer_TopLevelPropertyElementWrongNamespace", string.Empty, TestAtomConstants.ODataMetadataNamespace), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty("propertyName", "foo") .XmlRepresentation("<d:value>42</d:value>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomPropertyAndValueDeserializer_TopLevelPropertyElementWrongNamespace", TestAtomConstants.ODataNamespace, TestAtomConstants.ODataMetadataNamespace), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty(null, "") .XmlRepresentation("<m:value m:type='Edm.String'/>"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty(null, "") .XmlRepresentation("<!--s--> <?value?><m:value m:type='Edm.String'/><?value?><!-- -->"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty(null, GeographyFactory.Point(50, 70).Build()) .XmlRepresentation( "<m:value>" + "<gml:Point gml:srsName=\"http://www.opengis.net/def/crs/EPSG/0/4326\" xmlns:gml=\"http://www.opengis.net/gml\">" + "<gml:pos>50 70</gml:pos>" + "</gml:Point>" + "</m:value>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveProperty(null, GeographyFactory.Point(50, 70).Build()) .XmlRepresentation( "<m:value m:type='Edm.GeographyPoint'>" + "<gml:Point gml:srsName=\"http://www.opengis.net/def/crs/EPSG/0/4326\" xmlns:gml=\"http://www.opengis.net/gml\">" + "<gml:pos>50 70</gml:pos>" + "</gml:Point>" + "</m:value>"), SkipTestConfiguration = tc => tc.Version < ODataVersion.V4 } }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Creates a set of test descriptors with interesting error payloads. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <returns>List of test descriptors with interesting errors as payload.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateErrorReaderTestDescriptors(PayloadReaderTestDescriptor.Settings settings) { return TestErrors.CreateErrorTestDescriptors().Select(err => new PayloadReaderTestDescriptor(settings) { PayloadElement = err.PayloadElement, SkipTestConfiguration = tc => tc.IsRequest }); }
/// <summary> /// Puts the specified <paramref name="payload"/> into a primitive or complex collection. /// </summary> /// <param name="payload">The payload to put into a collection. This payload must represent a value.</param> /// <param name="propertiesValuesBefore">Number of properties to put in the complex value before the <paramref name="payload"/>.</param> /// <param name="propertiesValuesAfter">Number of properties to put in the complex value after the <paramref name="payload"/>.</param> /// <returns>A collection payload with the <paramref name="payload"/> as one of its properties.</returns> public static PayloadReaderTestDescriptor InCollection( this PayloadReaderTestDescriptor payload, int propertiesValuesBefore = 0, int propertiesValuesAfter = 0) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.InCollection(propertiesValuesBefore, propertiesValuesAfter) }); }
/// <summary> /// Puts the specified <paramref name="payload"/> into an entity. /// </summary> /// <param name="payload">The payload to put into an entity. This payload must represent a property instance.</param> /// <param name="propertiesBefore">Number of properties to put in the entity before the <paramref name="payload"/>.</param> /// <param name="propertiesAfter">Number of properties to put in the entity after the <paramref name="payload"/>.</param> /// <returns>An entity payload with the <paramref name="payload"/> as one of its properties.</returns> public static PayloadReaderTestDescriptor InEntity( this PayloadReaderTestDescriptor payload, int propertiesBefore = 0, int propertiesAfter = 0) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.InEdmEntity(propertiesBefore, propertiesAfter) }); }
/// <summary> /// Puts the specified <paramref name="payload"/> into an expanded link inside of a newly constructed entry. /// </summary> /// <param name="payload">The payload to be used as content for the expanded link.</param> /// <param name="isSingletonRelationship">true if the navigation property is of singleton cardinality; false for a cardinality many. Default is false.</param> /// <param name="randomDataGeneratorResolver">Random dataGeneration resolver</param> /// <param name="randomNumberGenerator">random number generator</param> /// <returns>An entry payload with an expanded link that contains the specified <paramref name="payload"/>.</returns> public static PayloadReaderTestDescriptor InEntryWithExpandedLink( this PayloadReaderTestDescriptor payload, bool isSingletonRelationship = false, IRandomDataGeneratorResolver randomDataGeneratorResolver = null, IRandomNumberGenerator randomNumberGenerator = null) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.InEntryWithExpandedLink(isSingletonRelationship, randomDataGeneratorResolver, randomNumberGenerator) }); }
/// <summary> /// Puts the specified <paramref name="payload"/> into a feed. It accepts optional parameters to control other /// properties of the feed and the position of the <paramref name="payload"/> inside the feed. /// </summary> /// <param name="payload">The payload to be used inside of the feed. This must represent an entity instance payload.</param> /// <param name="inlineCount">An optional inline count value for the feed.</param> /// <param name="nextLink">An optional next-link value for the feed.</param> /// <param name="elementsBefore">An optional number of entries that should exist before the <paramref name="payload"/> in the feed.</param> /// <param name="elementsAfter">An optional number of entries that should exist after the <paramref name="payload"/> in the feed.</param> /// <returns>A feed payload with the <paramref name="payload"/> as one of its entities.</returns> public static PayloadReaderTestDescriptor InFeed( this PayloadReaderTestDescriptor payload, long?inlineCount = null, string nextLink = null, int elementsBefore = 0, int elementsAfter = 0) { return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payload.PayloadDescriptor.InFeed(inlineCount, nextLink, elementsBefore, elementsAfter) }); }
/// <summary> /// Creates a set of interesting service document instances. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="withTitles">true if workspaces and collections should have a title; otherwise false.</param> /// <returns>List of test descriptors with interesting service documents as payload.</returns> internal static IEnumerable <PayloadReaderTestDescriptor> CreateServiceDocumentDescriptors(PayloadReaderTestDescriptor.Settings settings, string baseUri, bool withTitles) { return(TestServiceDocuments.CreateServiceDocuments(withTitles, baseUri).Select(sd => { PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadElement = sd, SkipTestConfiguration = tc => tc.IsRequest // service docs are only allowed in responses }; return testDescriptor; })); }
/// <summary> /// Creates a set of interesting service document instances. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="withTitles">true if workspaces and collections should have a title; otherwise false.</param> /// <returns>List of test descriptors with interesting service documents as payload.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateServiceDocumentDescriptors(PayloadReaderTestDescriptor.Settings settings, string baseUri, bool withTitles) { return TestServiceDocuments.CreateServiceDocuments(withTitles, baseUri).Select(sd => { PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadElement = sd, SkipTestConfiguration = tc => tc.IsRequest // service docs are only allowed in responses }; return testDescriptor; }); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="other">The other payload test descriptor to copy</param> public PayloadReaderTestDescriptor(PayloadReaderTestDescriptor other) : base(other) { this.settings = other.settings; this.PayloadDescriptor = new PayloadTestDescriptor(other.PayloadDescriptor); this.ExpectedResultPayloadElement = other.ExpectedResultPayloadElement; this.ExpectedException = other.ExpectedException; this.PayloadNormalizers = new List <Func <ReaderTestConfiguration, Func <ODataPayloadElement, ODataPayloadElement> > >(other.PayloadNormalizers); this.ExpectedResultNormalizers = new List <Func <ReaderTestConfiguration, Func <ODataPayloadElement, ODataPayloadElement> > >(other.ExpectedResultNormalizers); this.UrlResolver = other.UrlResolver; this.TestMessageWrapper = other.TestMessageWrapper; this.IgnorePropertyOrder = other.IgnorePropertyOrder; this.TestDescriptorNormalizers = new List <Func <ReaderTestConfiguration, Action <PayloadReaderTestDescriptor> > >(other.TestDescriptorNormalizers); }
public void FeedStartElementTest() { IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { // Empty feed element new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<feed/>") }, // Element with wrong local name new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<entry/>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomEntryAndFeedDeserializer_FeedElementWrongName", "entry", "http://www.w3.org/2005/Atom") }, // Element with wrong local name new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<Feed/>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomEntryAndFeedDeserializer_FeedElementWrongName", "Feed", "http://www.w3.org/2005/Atom") }, // Element with wrong namespace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<d:feed/>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomEntryAndFeedDeserializer_FeedElementWrongName", "feed", "http://docs.oasis-open.org/odata/ns/data") }, // Element with wrong namespace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<m:type/>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomEntryAndFeedDeserializer_FeedElementWrongName", "type", "http://docs.oasis-open.org/odata/ns/metadata") }, // Empty feed element with additional attributes - all attributes are ignored new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.EntitySet().XmlRepresentation("<feed some='bar' m:type='Edm.String' m:null='true' m:etag='foo' d:prop='1' />") }, }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Creates a set of interesting entity set instances along with metadata. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="model">If non-null, the method creates types as needed and adds them to the model.</param> /// <param name="withTypeNames">true if the payloads should specify type names.</param> /// <returns>List of test descriptors with interesting entity instances as payload.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateEntitySetInstanceDescriptors( PayloadReaderTestDescriptor.Settings settings, EdmModel model, bool withTypeNames) { List<PayloadReaderTestDescriptor> testDescriptors = new List<PayloadReaderTestDescriptor>(); foreach (var payloadDescriptor in TestFeeds.CreateEntitySetTestDescriptors(model, withTypeNames)) { testDescriptors.Add(new PayloadReaderTestDescriptor(settings) { PayloadDescriptor = payloadDescriptor, PayloadEdmModel = payloadDescriptor.PayloadEdmModel, SkipTestConfiguration = tc => payloadDescriptor.SkipTestConfiguration == null ? false : payloadDescriptor.SkipTestConfiguration(tc) }); } return testDescriptors; }
internal static IEnumerable <PayloadReaderTestDescriptor> CreateEntityInstanceDescriptors( PayloadReaderTestDescriptor.Settings settings, EdmModel model, bool withTypeNames) { List <PayloadReaderTestDescriptor> testDescriptors = new List <PayloadReaderTestDescriptor>(); foreach (var payloadDescriptor in TestEntityInstances.CreateEntityInstanceTestDescriptors(model, withTypeNames)) { // NOTE so far we don't have version-specific entity instances so we don't have to specify a // minimum version or skip function; once we do we'll have to change that PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadDescriptor = payloadDescriptor }; testDescriptors.Add(testDescriptor); } return(testDescriptors); }
/// <summary> /// Creates a set of interesting homogeneous collection value test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for the payload reader test descriptor to use.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <param name="withTypeNames">true if the collection value payloads should specify type names.</param> /// <param name="withExpectedType">true if an expected type annotation should be added to the generated payload element; otherwise false.</param> /// <param name="withcollectionName">true if the collection is not in the top level, otherwise false</param> /// <param name="fullSet">true if all available collection values should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable <PayloadReaderTestDescriptor> CreateHomogeneousCollectionValueTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withMetadata, bool withTypeNames, bool withExpectedType, bool withcollectionName, bool fullSet = true) { EdmModel model = withMetadata ? new EdmModel() : null; IEnumerable <ODataPayloadElementCollection> collectionValues = TestValues.CreateHomogeneousCollectionValues(model, withTypeNames, withExpectedType, withcollectionName, fullSet); return(collectionValues.Select(collectionValue => { PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadElement = collectionValue, PayloadEdmModel = model }; if (withExpectedType && !withTypeNames) { // fill in the type names for the expected result payload since they will be added based on the expected type testDescriptor.ExpectedResultNormalizers.Add(tc => FillTypeNamesFromTypeAnnotationsPayloadElementVisitor.Visit); } if (!withExpectedType) { testDescriptor.ExpectedResultNormalizers.Add( tc => (Func <ODataPayloadElement, ODataPayloadElement>)null); } // Do not run the test descriptor if we do not have an expected type in JSON Light because it would fail. testDescriptor.SkipTestConfiguration = tc => tc.Format == ODataFormat.Json && !withExpectedType; return testDescriptor; })); }
/// <summary> /// Constructor. /// </summary> /// <param name="other"><see cref="PayloadReaderTestDescriptor"/> to initialize this instance.</param> public ReaderContentTypeTestDescriptor(PayloadReaderTestDescriptor other) : base(other) { }
internal static IEnumerable<PayloadReaderTestDescriptor> CreateEntityInstanceDescriptors( PayloadReaderTestDescriptor.Settings settings, EdmModel model, bool withTypeNames) { List<PayloadReaderTestDescriptor> testDescriptors = new List<PayloadReaderTestDescriptor>(); foreach (var payloadDescriptor in TestEntityInstances.CreateEntityInstanceTestDescriptors(model, withTypeNames)) { // NOTE so far we don't have version-specific entity instances so we don't have to specify a // minimum version or skip function; once we do we'll have to change that PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadDescriptor = payloadDescriptor }; testDescriptors.Add(testDescriptor); } return testDescriptors; }
public void ServiceDocumentReaderInvalidAtomMetadataTest() { // The ExpectedExceptions in the following test descriptors only apply when ATOM metadata reading is on. // When ATOM metadata reading is off, invalid ATOM metadata should cause no failures, and ExpectedException is ignored. IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { // Multiple atom:title elements inside the workspace element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection("Products", baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:title>Default</atom:title> <atom:title>Default</atom:title> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentMetadataDeserializer_MultipleTitleElementsFound", "workspace"), }, // Invalid value for "fixed" attribute on a categories element new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection("Products", baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <categories fixed='foo' scheme='http://baseschema.org'> <atom:category term='Some Term'/> </categories> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentMetadataDeserializer_InvalidFixedAttributeValue", "foo"), }, // Multiple app:accept attributes inside a collection new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppAccept("application/atom+xml;type=entry") .AppInlineCategories("yes", null, AtomMetadataBuilder.AtomCategory("SomeTerm", "http://someschema.org/", null)))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <accept>application/atom+xml;type=entry</accept> <categories fixed='yes'> <atom:category scheme='http://someschema.org/' term='SomeTerm'/> </categories> <accept>application/atom+xml;type=entry</accept> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentMetadataDeserializer_MultipleAcceptElementsFoundInCollection"), }, }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), new bool[] { true, false }, (testDescriptor, testConfiguration, enableAtomMetadataReading) => { testConfiguration = new ReaderTestConfiguration(testConfiguration); testConfiguration.MessageReaderSettings.EnableAtomMetadataReading = enableAtomMetadataReading; testDescriptor = new PayloadReaderTestDescriptor(testDescriptor); if (!enableAtomMetadataReading) { testDescriptor.ExpectedResultNormalizers.Add(tc => RemoveAtomMetadataFromPayloadElementVisitor.Visit); testDescriptor.ExpectedException = null; } testDescriptor.RunTest(testConfiguration); }); }
public void EntryPayloadOrderTest() { IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new[] { // Nothing new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity() .XmlRepresentation("<entry></entry>") .PayloadOrderItems("__StartEntry__") }, // Just type name after nav. link - type name should be reported first. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType").NavigationProperty("Category", "http://odata.org/Category") .XmlRepresentation( "<entry>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "</entry>") .PayloadOrderItems( "TypeName", "__StartEntry__", "NavigationLink_Category") }, // Type name properties and other things after link - type name and etag should be reported first, the rest after the link new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType") .ETag("bar") .NavigationProperty("Category", "http://odata.org/Category") .WithSelfLink("http://odata.org") .PrimitiveProperty("Name", "Foo") .XmlRepresentation( "<entry m:etag='bar'>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + "<link rel='self' href='http://odata.org'/>" + "</entry>") .PayloadOrderItems( "TypeName", "ETag", "__StartEntry__", "NavigationLink_Category", "ReadLink", "Property_Name"), // [Astoria-ODataLib-Integration] Parsing of URLs on OData recognized places may fail, but Astoria server doesn't SkipTestConfiguration = config => config.RunBehaviorKind == TestODataBehaviorKind.WcfDataServicesServer }, // Everything before nav. link new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType") .ETag("bar") .PrimitiveProperty("Name", "Foo") .NavigationProperty("Category", "http://odata.org/Category") .WithSelfLink("http://odata.org") .OperationDescriptor(new ServiceOperationDescriptor() { IsAction = true, Metadata = "/actionMetadata", Target = "http://odata.org/action" }) .OperationDescriptor(new ServiceOperationDescriptor() { IsFunction = true, Metadata = "/functionMetadata", Target = "http://odata.org/function" }) .XmlRepresentation( "<entry m:etag='bar'>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + "<link rel='self' href='http://odata.org'/>" + "<m:action metadata='/actionMetadata' target='http://odata.org/action'/>" + "<m:function metadata='/functionMetadata' target='http://odata.org/function'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/relatedlinks/PoliceStation' href='http://odata.org/associationlink' type='application/xml'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "</entry>") .PayloadOrderItems( "TypeName", "ReadLink", "ETag", "Action_/actionMetadata", "Function_/functionMetadata", "Property_Name", "__StartEntry__", "NavigationLink_Category"), // [Astoria-ODataLib-Integration] Parsing of URLs on OData recognized places may fail, but Astoria server doesn't SkipTestConfiguration = config => config.RunBehaviorKind == TestODataBehaviorKind.WcfDataServicesServer || config.IsRequest }, // Everything before nav. link - Server behavior - server ignores most of links new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType") .ETag("bar") .PrimitiveProperty("Name", "Foo") .NavigationProperty("Category", "http://odata.org/Category") .OperationDescriptor(new ServiceOperationDescriptor() { IsAction = true, Metadata = "/actionMetadata", Target = "http://odata.org/action" }) .OperationDescriptor(new ServiceOperationDescriptor() { IsFunction = true, Metadata = "/functionMetadata", Target = "http://odata.org/function" }) .XmlRepresentation( "<entry m:etag='bar'>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + "<link rel='self' href='http://odata.org'/>" + "<m:action metadata='/actionMetadata' target='http://odata.org/action'/>" + "<m:function metadata='/functionMetadata' target='http://odata.org/function'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/relatedlinks/PoliceStation' href='http://odata.org/associationlink' type='application/xml'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "</entry>") .PayloadOrderItems( "TypeName", "ETag", "Action_/actionMetadata", "Function_/functionMetadata", "Property_Name", "__StartEntry__", "NavigationLink_Category"), SkipTestConfiguration = config => config.RunBehaviorKind != TestODataBehaviorKind.WcfDataServicesServer || config.IsRequest }, // Everything between nav. links new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType") .ETag("bar") .NavigationProperty("Order", "http://odata.org/Order") .PrimitiveProperty("Name", "Foo") .NavigationProperty("Category", "http://odata.org/Category") .WithSelfLink("http://odata.org") .OperationDescriptor(new ServiceOperationDescriptor() { IsAction = true, Metadata = "/actionMetadata", Target = "http://odata.org/action" }) .OperationDescriptor(new ServiceOperationDescriptor() { IsFunction = true, Metadata = "/functionMetadata", Target = "http://odata.org/function" }) .XmlRepresentation( "<entry m:etag='bar'>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Order' type='application/atom+xml;type=entry' href='http://odata.org/Order'/>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + "<link rel='self' href='http://odata.org'/>" + "<m:action metadata='/actionMetadata' target='http://odata.org/action'/>" + "<m:function metadata='/functionMetadata' target='http://odata.org/function'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/relatedlinks/PoliceStation' href='http://odata.org/associationlink' type='application/xml'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "</entry>") .PayloadOrderItems( "TypeName", "ETag", "__StartEntry__", "NavigationLink_Order", "ReadLink", "Action_/actionMetadata", "Function_/functionMetadata", "Property_Name", "NavigationLink_Category"), // [Astoria-ODataLib-Integration] Parsing of URLs on OData recognized places may fail, but Astoria server doesn't SkipTestConfiguration = config => config.RunBehaviorKind == TestODataBehaviorKind.WcfDataServicesServer || config.IsRequest }, // Everything between nav. links - server behavior new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Entity("MyType") .ETag("bar") .NavigationProperty("Order", "http://odata.org/Order") .PrimitiveProperty("Name", "Foo") .NavigationProperty("Category", "http://odata.org/Category") .OperationDescriptor(new ServiceOperationDescriptor() { IsAction = true, Metadata = "/actionMetadata", Target = "http://odata.org/action" }) .OperationDescriptor(new ServiceOperationDescriptor() { IsFunction = true, Metadata = "/functionMetadata", Target = "http://odata.org/function" }) .XmlRepresentation( "<entry m:etag='bar'>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Order' type='application/atom+xml;type=entry' href='http://odata.org/Order'/>" + "<category term='MyType' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + "<link rel='self' href='http://odata.org'/>" + "<m:action metadata='/actionMetadata' target='http://odata.org/action'/>" + "<m:function metadata='/functionMetadata' target='http://odata.org/function'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/relatedlinks/PoliceStation' href='http://odata.org/associationlink' type='application/xml'/>" + "<link rel='http://docs.oasis-open.org/odata/ns/related/Category' type='application/atom+xml;type=entry' href='http://odata.org/Category'/>" + "</entry>") .PayloadOrderItems( "TypeName", "ETag", "__StartEntry__", "NavigationLink_Order", "Action_/actionMetadata", "Function_/functionMetadata", "Property_Name", "NavigationLink_Category"), SkipTestConfiguration = config => config.RunBehaviorKind != TestODataBehaviorKind.WcfDataServicesServer || config.IsRequest }, // EPM //new PayloadReaderTestDescriptor(this.Settings) //{ // PayloadElement = PayloadBuilder.Entity("TestModel.EpmEntity") // .NavigationProperty("Order", "http://odata.org/Order") // .PrimitiveProperty("Name", "Foo") // .NavigationProperty("Orders", "http://odata.org/Orders") // .PrimitiveProperty("Description", "Bart") // .XmlRepresentation( // "<entry>" + // "<link rel='http://docs.oasis-open.org/odata/ns/related/Order' type='application/atom+xml;type=entry' href='http://odata.org/Order'/>" + // "<category term='TestModel.EpmEntity' scheme='http://docs.oasis-open.org/odata/ns/scheme'/>" + // "<content type='application/xml'><m:properties><d:Name>Foo</d:Name></m:properties></content>" + // "<link rel='http://docs.oasis-open.org/odata/ns/related/Orders' type='application/atom+xml;type=feed' href='http://odata.org/Orders'/>" + // "<author><name>Bart</name></author>" + // "</entry>") // .PayloadOrderItems( // "TypeName", // "__StartEntry__", // "NavigationLink_Order", // "Property_Name", // "NavigationLink_Orders", // "Property_Description"), // PayloadModel = model //} }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations, TestReaderUtils.ODataBehaviorKinds, (testDescriptor, testConfiguration, behavior) => { // In WCF DS Server mode the reader reports the StartEntry as soon as it finds a type name. // Since the ETag is always on the start element it will be reported in StartEntry as well. if (behavior == TestODataBehaviorKind.WcfDataServicesServer) { ODataPayloadElement element = testDescriptor.PayloadElement.DeepCopy(); PayloadOrderODataPayloadElementAnnotation payloadOrderAnnotation = element.GetAnnotation<PayloadOrderODataPayloadElementAnnotation>(); int startEntryPosition = 0; if (payloadOrderAnnotation.PayloadItems[0] == "TypeName") { startEntryPosition++; } if (payloadOrderAnnotation.PayloadItems.Contains("ETag")) { payloadOrderAnnotation.PayloadItems.Remove("ETag"); payloadOrderAnnotation.PayloadItems.Insert(1, "ETag"); startEntryPosition++; } payloadOrderAnnotation.PayloadItems.Remove("__StartEntry__"); payloadOrderAnnotation.PayloadItems.Insert(startEntryPosition, "__StartEntry__"); testDescriptor = new PayloadReaderTestDescriptor(testDescriptor) { PayloadElement = element }; } // We must remove any payload normalizers since we are now supersensitive to ordering issues in this test. testDescriptor.ExpectedResultNormalizers.Clear(); testDescriptor.RunTest(testConfiguration.CloneAndApplyBehavior(behavior)); }); }
public void ServiceDocumentReaderWithAtomMetadataTest() { IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { #region tests related to atom:title // Verify that a title inside a collection is read into the Name property and (if ATOM metadata reading is enabled) the Title property of the metadata annotation. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection("Products", baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> </collection> </workspace> </service>"), }, // Title inside a workspace should be read when ATOM metadata reading is on, but ignored otherwise. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .AtomTitle("Default", TestAtomConstants.AtomTextConstructTextKind) .ResourceCollection("Products", baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:title>Default</atom:title> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> </collection> </workspace> </service>"), }, // Multiple atom:title elements inside the collection element should throw when metadata reading is both on and off. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <atom:title>Products</atom:title> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentMetadataDeserializer_MultipleTitleElementsFound", "collection"), }, #endregion tests related to atom:title #region app:collection element // Collection element with no children. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> </collection> </workspace> </service>"), }, // Empty collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products' /> </workspace> </service>"), }, // Multiple collections new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .AtomTitle("Default", TestAtomConstants.AtomTextConstructTextKind) .ResourceCollection( PayloadBuilder.ResourceCollection("Collection1", baseUri + "Collection1") .AppAccept("image/png") .AppOutOfLineCategories("http://somecategories.com")) .ResourceCollection( PayloadBuilder.ResourceCollection("Collection2", baseUri + "Collection2") .AppAccept("image/gif") .AppOutOfLineCategories("http://othercategories.com"))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:title>Default</atom:title> <collection href='" + baseUri + @"Collection1'> <atom:title>Collection1</atom:title> <accept>image/png</accept> <categories href='http://somecategories.com'/> </collection> <collection href='" + baseUri + @"Collection2'> <atom:title>Collection2</atom:title> <accept>image/gif</accept> <categories href='http://othercategories.com'/> </collection> </workspace> </service>"), }, #endregion app:collection element #region app:accept and app:categories element // app:accept and app:categories element inside the collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppAccept("application/atom+xml;type=entry") .AppInlineCategories("yes", null, AtomMetadataBuilder.AtomCategory("SomeTerm", "http://someschema.org/", null)))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <accept>application/atom+xml;type=entry</accept> <categories fixed='yes'> <atom:category scheme='http://someschema.org/' term='SomeTerm'/> </categories> </collection> </workspace> </service>"), }, // Out of line app:categories element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .AtomTitle("Default", TestAtomConstants.AtomTextConstructTextKind) .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppOutOfLineCategories("http://example.com/categories"))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:title>Default</atom:title> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <categories href='http://example.com/categories' /> </collection> </workspace> </service>"), }, // Attributes of the "categories" element in a non-empty namespace should be ignored. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppInlineCategories(null, null, AtomMetadataBuilder.AtomCategory("SomeTerm", "http://someschema.org", "SomeLabel")))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:foo='http://foo.org'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <categories foo:fixed='yes' atom:scheme='http://baseschema.org'> <atom:category term='SomeTerm' scheme='http://someschema.org' label='SomeLabel'/> </categories> </collection> </workspace> </service>"), }, #endregion app:accept and app:categories element #region atom:category element // Attributes of the "category" element in a non-empty namespace should be ignored. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppInlineCategories("yes", "http://baseschema.org", AtomMetadataBuilder.AtomCategory(null, null, null)))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom' xmlns:foo='http://foo.org'> <workspace> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <categories fixed='yes' scheme='http://baseschema.org'> <atom:category foo:term='SomeTerm' app:scheme='http://someschema.org' atom:label='SomeLabel'/> </categories> </collection> </workspace> </service>"), }, // Multiple atom:category elements. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .AtomTitle("Default", TestAtomConstants.AtomTextConstructTextKind) .ResourceCollection( PayloadBuilder.ResourceCollection("Products", baseUri + "Products") .AppInlineCategories("no", "http://baseschema.org", AtomMetadataBuilder.AtomCategory("FirstCategory", null, null), AtomMetadataBuilder.AtomCategory("SecondCategory", null, "SomeLabel")))) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:title>Default</atom:title> <collection href='" + baseUri + @"Products'> <atom:title>Products</atom:title> <categories fixed='no' scheme='http://baseschema.org'> <atom:category term='FirstCategory'/> <atom:category term='SecondCategory' label='SomeLabel'/> </categories> </collection> </workspace> </service>"), }, #endregion atom:category element #region extra nodes // comments at different places in the service document. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <!-- some comments --> <workspace> <!-- more comments --> <collection href='" + baseUri + @"Products'> <!-- more comments --> </collection> <!-- more comments --> </workspace> <!-- more comments --> </service>"), }, // elements having additional irrelevant attributes new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom' foo2='bar2'> <workspace foo='bar'> <collection href='" + baseUri + @"Products' foo1='bar1'> </collection> </workspace> </service>"), }, // irrelevant child elements inside a workspace or collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace() .ResourceCollection(null, baseUri + "Products") .ResourceCollection(null, baseUri + "Orders")) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <cn:foo foo1='bar1' /> <collection href='" + baseUri + @"Products'> <cn:foo href='" + baseUri + @"Products'> </cn:foo> </collection> <cn:foo2 foo3='bar3' /> <cn:foo2 foo3='bar3' /> <collection href='" + baseUri + @"Orders'> <atom:foo href='" + baseUri + @"Orders'> </atom:foo> </collection> </workspace> </service>"), }, // irrelevant element before and after the workspace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <cn:some_element>some text</cn:some_element> <workspace> <collection href='" + baseUri + @"Products'> </collection> </workspace> <cn:some_element>some text</cn:some_element> </service>"), }, #endregion extra elements }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), new bool[] { true, false }, (testDescriptor, testConfiguration, enableAtomMetadataReading) => { testConfiguration = new ReaderTestConfiguration(testConfiguration); testConfiguration.MessageReaderSettings.EnableAtomMetadataReading = enableAtomMetadataReading; testDescriptor = new PayloadReaderTestDescriptor(testDescriptor); if (!enableAtomMetadataReading) { // If we are running with ATOM metadata reading turned off, strip off all ATOM metadata annotations and // properties from the expected result. testDescriptor.ExpectedResultNormalizers.Add(tc => RemoveAtomMetadataFromPayloadElementVisitor.Visit); } // Normalize the payload elements so that if an ATOM metadata property is set, the corresponding ATOM metadata // annotation is created, and vice versa. testDescriptor.ExpectedResultNormalizers.Add(tc => ODataPayloadElementAtomMetadataNormalizer.GenerateNormalizer(testConfiguration)); testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Creates the input message for the test descriptor /// </summary> /// <param name="testConfiguration">the test configuration to use</param> /// <param name="readerTestDescriptor">The test descriptor</param> /// <param name="settings">The test descriptor settings</param> /// <param name="applyPayloadTransformations">Whether or not to apply payload transformations</param> /// <returns>The message for the test</returns> public static TestMessage CreateInputMessage(ReaderTestConfiguration testConfiguration, PayloadReaderTestDescriptor readerTestDescriptor, PayloadReaderTestDescriptor.Settings settings, bool?applyPayloadTransformations) { TestMessage testMessage; bool originalApplyTransformValue = false; var odataTransformFactory = settings.PayloadTransformFactory as ODataLibPayloadTransformFactory; try { if (applyPayloadTransformations.HasValue && odataTransformFactory != null) { originalApplyTransformValue = odataTransformFactory.ApplyTransform; odataTransformFactory.ApplyTransform = applyPayloadTransformations.Value; } if (readerTestDescriptor.TestDescriptorNormalizers != null) { foreach (var testDescriptorNormalizer in readerTestDescriptor.TestDescriptorNormalizers) { var normalizerAction = testDescriptorNormalizer(testConfiguration); if (normalizerAction != null) { normalizerAction(readerTestDescriptor); } } } MemoryStream memoryStream = new MemoryStream(GetPayload(testConfiguration, readerTestDescriptor.PayloadNormalizers, settings, readerTestDescriptor.PayloadElement)); TestStream messageStream = new TestStream(memoryStream); if (testConfiguration.Synchronous) { messageStream.FailAsynchronousCalls = true; } else { messageStream.FailSynchronousCalls = true; } testMessage = TestReaderUtils.CreateInputMessageFromStream( messageStream, testConfiguration, readerTestDescriptor.PayloadElement.GetPayloadKindFromPayloadElement(), readerTestDescriptor.PayloadElement.GetCustomContentTypeHeader(), readerTestDescriptor.UrlResolver); if (readerTestDescriptor.TestMessageWrapper != null) { testMessage = readerTestDescriptor.TestMessageWrapper(testMessage); } return(testMessage); } finally { if (applyPayloadTransformations.HasValue && odataTransformFactory != null) { odataTransformFactory.ApplyTransform = originalApplyTransformValue; } } }
/// <summary> /// Copy constructor. /// </summary> /// <param name="other">The other payload test descriptor to copy</param> public PayloadReaderTestDescriptor(PayloadReaderTestDescriptor other) : base(other) { this.settings = other.settings; this.PayloadDescriptor = new PayloadTestDescriptor(other.PayloadDescriptor); this.ExpectedResultPayloadElement = other.ExpectedResultPayloadElement; this.ExpectedException = other.ExpectedException; this.PayloadNormalizers = new List<Func<ReaderTestConfiguration, Func<ODataPayloadElement, ODataPayloadElement>>>(other.PayloadNormalizers); this.ExpectedResultNormalizers = new List<Func<ReaderTestConfiguration, Func<ODataPayloadElement, ODataPayloadElement>>>(other.ExpectedResultNormalizers); this.UrlResolver = other.UrlResolver; this.TestMessageWrapper = other.TestMessageWrapper; this.IgnorePropertyOrder = other.IgnorePropertyOrder; this.TestDescriptorNormalizers = new List<Func<ReaderTestConfiguration, Action<PayloadReaderTestDescriptor>>>(other.TestDescriptorNormalizers); }
/// <summary> /// Creates a set of interesting collections with complex items test descriptors along with metadata. /// </summary> /// <param name="withTypeNames">true if the complex value payloads should specify type names.</param> /// <param name="fullSet">true if all available complex collections should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateComplexCollectionTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withTypeNames, bool fullSet = true) { EdmModel model = new EdmModel().Fixup(); IEnumerable<ComplexMultiValue> complexCollections = TestValues.CreateComplexCollections(model, withTypeNames, fullSet); return complexCollections.Select(collection => new PayloadReaderTestDescriptor(settings) { PayloadElement = collection, PayloadEdmModel = model, SkipTestConfiguration = tc => tc.Version < ODataVersion.V4, }); }
private void RunMessageSizeLimitTests( IEnumerable<ReaderTestConfiguration> testConfigurations, EdmModel model, ODataPayloadElement payload, MessageSizeLimitTestCase[] testCases, Func<ReaderTestConfiguration, bool> skipTestConfigurationFunc = null) { var transformScope = this.Settings.PayloadTransformFactory.EmptyScope(); using (transformScope.Apply()) { this.CombinatorialEngineProvider.RunCombinations( testCases, testConfigurations, (testCase, testConfiguration) => { int size = -1; if (testConfiguration.Format == ODataFormat.Atom && testCase.AtomSizes != null) { size = testConfiguration.IsRequest ? testCase.AtomSizes.RequestSize : testCase.AtomSizes.ResponseSize; } else if (testConfiguration.Format == ODataFormat.Json && testCase.JsonLightSizes != null) { size = testConfiguration.IsRequest ? testCase.JsonLightSizes.RequestSize : testCase.JsonLightSizes.ResponseSize; } else if (testCase.RawSizes != null) { size = testConfiguration.IsRequest ? testCase.RawSizes.RequestSize : testCase.RawSizes.ResponseSize; } int maxSize = testCase.MaxMessageSize >= 0 ? testCase.MaxMessageSize : 1024 * 1024; ExpectedException expectedException = size < 0 ? null : ODataExpectedExceptions.ODataException("MessageStreamWrappingStream_ByteLimitExceeded", size.ToString(), maxSize.ToString()); var testDescriptor = new PayloadReaderTestDescriptor(this.Settings) { PayloadEdmModel = model, PayloadElement = payload.DeepCopy(), ExpectedException = expectedException, SkipTestConfiguration = skipTestConfigurationFunc, ApplyPayloadTransformations = false, }; testDescriptor.ExpectedResultNormalizers.Add( tc => (Func<ODataPayloadElement, ODataPayloadElement>)null); if (testCase.MaxMessageSize > 0) { testConfiguration = new ReaderTestConfiguration(testConfiguration); testConfiguration.MessageReaderSettings.MessageQuotas.MaxReceivedMessageSize = testCase.MaxMessageSize; } testDescriptor.RunTest(testConfiguration); }); } }
public void NonNullablePropertiesWithNullValuesTest() { IEnumerable<NonNullablePropertyTest> testCases = new NonNullablePropertyTest[] { new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetString(false), TypeName = "Edm.String" }, new NonNullablePropertyTest { Value = "foo", DataType = EdmCoreModel.Instance.GetString(false), TypeName = "Edm.String" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetBinary(false), TypeName = "Edm.Binary" }, new NonNullablePropertyTest { Value = new byte[] { 1, 2, 3 }, DataType = EdmCoreModel.Instance.GetBinary(false), TypeName = "Edm.Binary" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetBoolean(false), TypeName = "Edm.Boolean" }, new NonNullablePropertyTest { Value = true, DataType = EdmCoreModel.Instance.GetBoolean(false), TypeName = "Edm.Boolean" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetByte(false), TypeName = "Edm.Byte" }, new NonNullablePropertyTest { Value = (byte)1, DataType = EdmCoreModel.Instance.GetByte(false), TypeName = "Edm.Byte" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetDateTimeOffset(false), TypeName = "Edm.DateTimeOffset" }, new NonNullablePropertyTest { Value = new DateTimeOffset(new DateTime(2011, 08, 31), TimeSpan.Zero), DataType = EdmCoreModel.Instance.GetDateTimeOffset(false), TypeName = "Edm.DateTimeOffset" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetDecimal(false), TypeName = "Edm.Decimal" }, new NonNullablePropertyTest { Value = (decimal)1.0, DataType = EdmCoreModel.Instance.GetDecimal(false), TypeName = "Edm.Decimal" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetDouble(false), TypeName = "Edm.Double" }, new NonNullablePropertyTest { Value = (double)1.0, DataType = EdmCoreModel.Instance.GetDouble(false), TypeName = "Edm.Double" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetSingle(false), TypeName = "Edm.Single" }, new NonNullablePropertyTest { Value = (float)1.0, DataType = EdmCoreModel.Instance.GetSingle(false), TypeName = "Edm.Single" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetSByte(false), TypeName = "Edm.SByte" }, new NonNullablePropertyTest { Value = (sbyte)1, DataType = EdmCoreModel.Instance.GetSByte(false), TypeName = "Edm.SByte" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetInt16(false), TypeName = "Edm.Int16" }, new NonNullablePropertyTest { Value = (Int16)1, DataType = EdmCoreModel.Instance.GetInt16(false), TypeName = "Edm.Int16" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetInt32(false), TypeName = "Edm.Int32" }, new NonNullablePropertyTest { Value = (Int32)1, DataType = EdmCoreModel.Instance.GetInt32(false), TypeName = "Edm.Int32" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetInt64(false), TypeName = "Edm.Int64" }, new NonNullablePropertyTest { Value = (Int64)1, DataType = EdmCoreModel.Instance.GetInt64(false), TypeName = "Edm.Int64" }, new NonNullablePropertyTest { Value = null, DataType = EdmCoreModel.Instance.GetGuid(false), TypeName = "Edm.Guid" }, new NonNullablePropertyTest { Value = Guid.NewGuid(), DataType = EdmCoreModel.Instance.GetGuid(false), TypeName = "Edm.Guid" }, }; IEnumerable<PayloadReaderTestDescriptor> testDescriptors = testCases.Select(testCase => new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.PrimitiveValue(testCase.Value).WithTypeAnnotation(testCase.DataType), PayloadEdmModel = new EdmModel().Fixup(), ExpectedException = testCase.Value == null ? ODataExpectedExceptions.ODataException("ReaderValidationUtils_NullValueForNonNullableType", testCase.TypeName) : null, }); testDescriptors = testDescriptors.Select(td => td.InProperty("propertyName")); testDescriptors = testDescriptors.SelectMany(td => this.PayloadGenerator.GenerateReaderPayloads(td)); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations, (testDescriptor, testConfiguration) => { if (!(testDescriptor.PayloadElement is PrimitiveProperty) && testDescriptor.ExpectedException != null) { testDescriptor = new PayloadReaderTestDescriptor(testDescriptor); testDescriptor.ExpectedException = ODataExpectedExceptions.ODataException( "ReaderValidationUtils_NullNamedValueForNonNullableType", "propertyName", testDescriptor.ExpectedException.ExpectedMessage.Arguments.ElementAt(0)); } var property = testDescriptor.PayloadElement as PropertyInstance; if (property != null && testConfiguration.Format == ODataFormat.Atom) { property.Name = null; } testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Converts a <see cref="PayloadReaderTestDescriptor"/> to an in-stream error <see cref="PayloadReaderTestDescriptor"/>. /// </summary> /// <param name="descriptor">The <see cref="PayloadReaderTestDescriptor"/> to convert.</param> /// <param name="format">The <see cref="ODataFormat"/> the test descriptor is created for.</param> /// <returns>An in-stream error <see cref="PayloadReaderTestDescriptor"/> based on the <paramref name="descriptor"/>.</returns> /// <remarks>The <paramref name="descriptor"/> is expected to represent a top-level error payload test descriptor.</remarks> internal static PayloadReaderTestDescriptor ToInStreamErrorTestDescriptor(this PayloadReaderTestDescriptor descriptor, ODataFormat format) { ExceptionUtilities.CheckArgumentNotNull(descriptor, "descriptor"); ExceptionUtilities.CheckArgumentNotNull(format, "format"); ExceptionUtilities.Assert(descriptor.PayloadElement.ElementType == ODataPayloadElementType.ODataErrorPayload, "Only error payloads expected."); ExceptionUtilities.Assert(descriptor.ExpectedResultCallback == null, "No expected results callback expected."); ExceptionUtilities.Assert(descriptor.PayloadEdmModel == null, "No model expected."); // Model that defines the CityType to be used for wrapping the error payload to convert it into an in-stream error. IEdmModel testModel = Test.OData.Utils.Metadata.TestModels.BuildTestModel(); bool isValidTopLevelError = descriptor.ExpectedException == null; ODataPayloadElement wrappedPayloadElement = null; ExpectedException expectedException = null; if (format == ODataFormat.Atom) { var atomRepresentation = (XmlPayloadElementRepresentationAnnotation)descriptor.PayloadElement.GetAnnotation(typeof(XmlPayloadElementRepresentationAnnotation)); ExceptionUtilities.Assert(atomRepresentation != null, "Expected a format-specific annotation."); XNode xmlRepresentation = atomRepresentation.XmlNodes.Single(); XElement wrapperObject = new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName, new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomCategoryElementName, new XAttribute(TestAtomConstants.AtomCategoryTermAttributeName, "TestModel.CityType"), new XAttribute(TestAtomConstants.AtomCategorySchemeAttributeName, TestAtomConstants.ODataSchemeNamespace), new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomContentElementName, new XAttribute(TestAtomConstants.AtomTypeAttributeName, "application/xml"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.AtomPropertiesElementName, new XElement(TestAtomConstants.ODataXNamespace + "PoliceStation", xmlRepresentation))))); // replace the payload and ATOM representation of the test descriptor and set the expected error message wrappedPayloadElement = PayloadBuilder.Entity("TestModel.CityType").XmlRepresentation(wrapperObject); if (isValidTopLevelError) { // if we have a valid top-level error we expect an ODataErrorException to be thrown. ODataError error = ConvertErrorPayload((ODataErrorPayload)descriptor.PayloadElement, /*forAtom*/ true); expectedException = ODataExpectedExceptions.ODataErrorException(error, "ODataErrorException_GeneralError"); } else { expectedException = descriptor.ExpectedException; } } else if (format == ODataFormat.Json) { IEdmEntitySet citiesSet = testModel.EntityContainer.FindEntitySet("Cities"); IEdmEntityType cityType = testModel.FindType("TestModel.CityType") as IEdmEntityType; var jsonRepresentation = (JsonPayloadElementRepresentationAnnotation)descriptor.PayloadElement.GetAnnotation(typeof(JsonPayloadElementRepresentationAnnotation)); ExceptionUtilities.Assert(jsonRepresentation != null, "Expected a format-specific annotation."); JsonObject jsonObject = (JsonObject)jsonRepresentation.Json; // wrap the existing payload in an entity of type 'CityType'; the existing payload is used as value of the 'PoliceStation' property JsonObject wrapperObject = (JsonObject)JsonTextPreservingParser.ParseValue(new StringReader("{ \"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + "\":\"http://odata.org/test/$metadata#TestModel.DefaultContainer.Cities/$entity\" }")); wrapperObject.Add(new JsonProperty("PoliceStation", jsonObject)); // replace the payload and Json representation of the test descriptor and set the expected error message wrappedPayloadElement = PayloadBuilder.Entity("TestModel.CityType") .ExpectedEntityType(cityType, citiesSet) .JsonRepresentation(wrapperObject); if (isValidTopLevelError) { // if we have a valid top-level error we expect an ODataErrorException to be thrown. ODataError error = ConvertErrorPayload((ODataErrorPayload)descriptor.PayloadElement, /*forAtom*/ false); expectedException = ODataExpectedExceptions.ODataErrorException(error, "ODataErrorException_GeneralError"); } else { // if the top-level error is too deeply recursive, we expect to fail in the same way for the in-stream error. if (descriptor.ExpectedException.ExpectedMessage.ResourceIdentifier == "ValidationUtils_RecursionDepthLimitReached") { expectedException = descriptor.ExpectedException; } else { // otherwise, if the top-level error is not valid, we expect an error message that the first // property of the invalid top-level error object is not defined on type OfficeType. string firstPropertyName = jsonObject.Properties.First().Name; expectedException = ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", firstPropertyName, "TestModel.OfficeType"); } } } else { throw new TaupoInvalidOperationException("Unsupported format for error test descriptor found: " + format.GetType().Name); } return(new PayloadReaderTestDescriptor(descriptor) { PayloadElement = wrappedPayloadElement, PayloadEdmModel = testModel, ExpectedResultPayloadElement = tc => descriptor.PayloadElement, ExpectedException = expectedException, }); }
public void DuplicatePropertyNamesTest() { PropertyInstance primitiveProperty = PayloadBuilder.PrimitiveProperty("DuplicateProperty", 42); PropertyInstance complexProperty = PayloadBuilder.Property("DuplicateProperty", PayloadBuilder.ComplexValue("TestModel.DuplicateComplexType").PrimitiveProperty("Name", "foo")); PropertyInstance collectionProperty = PayloadBuilder.Property("DuplicateProperty", PayloadBuilder.PrimitiveMultiValue(EntityModelUtils.GetCollectionTypeName("Edm.String")).WithTypeAnnotation(EdmCoreModel.GetCollection(EdmCoreModel.Instance.GetString(false)))); PropertyInstance[] allProperties = new[] { primitiveProperty, complexProperty, collectionProperty }; PropertyInstance[] propertiesWithPossibleDuplication = new[] { primitiveProperty, complexProperty }; PropertyInstance[] propertiesWithNoDuplication = new[] { collectionProperty }; IEnumerable<DuplicatePropertySet> duplicatePropertySets; // Those which may allow duplication duplicatePropertySets = propertiesWithPossibleDuplication .Variations(2).Select(properties => new DuplicatePropertySet { Properties = properties, DuplicationPotentiallyAllowed = true }); // Then for each in those which don't allow duplication try it against all the others duplicatePropertySets = duplicatePropertySets.Concat(propertiesWithNoDuplication.SelectMany( propertyWithNoDuplication => allProperties.SelectMany(otherProperty => new[] { new DuplicatePropertySet { Properties = new [] { propertyWithNoDuplication, otherProperty }, DuplicationPotentiallyAllowed = false }, new DuplicatePropertySet { Properties = new [] { otherProperty, propertyWithNoDuplication }, DuplicationPotentiallyAllowed = false }, }))); this.CombinatorialEngineProvider.RunCombinations( duplicatePropertySets, new bool[] { false, true }, new bool[] { true, false }, this.ReaderTestConfigurationProvider.ExplicitFormatConfigurations, (duplicatePropertySet, allowDuplicateProperties, useMetadata, testConfiguration) => { EdmModel model = new EdmModel(); var complexType = model.ComplexType("DuplicateComplexType"); complexType.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String); model.Fixup(); PropertyInstance firstProperty = duplicatePropertySet.Properties.ElementAt(0); PropertyInstance secondProperty = duplicatePropertySet.Properties.ElementAt(1); // Non-metadata reading is not possible in JSON if (!useMetadata && (testConfiguration.Format == ODataFormat.Json)) { return; } // If we will have metadata then we can only allow combinations of the same kind if (useMetadata) { if (firstProperty.ElementType != secondProperty.ElementType) { return; } } // Copy the test config testConfiguration = new ReaderTestConfiguration(testConfiguration); if (allowDuplicateProperties) { testConfiguration.MessageReaderSettings.EnableODataServerBehavior(); } // Create a descriptor with the first property PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = firstProperty, PayloadEdmModel = useMetadata ? model : null }; // Now generate entity around it testDescriptor = testDescriptor.InComplexValue(5, 5); // Now add the second property to it ((ComplexInstance)testDescriptor.PayloadElement).Add(secondProperty); // [Astoria-ODataLib-Integration] Parsing of URLs on OData recognized places may fail, but Astoria server doesn't // Server does not read named stream links for Atom payload therefore the expected payload needs to be normalized if (testConfiguration.Format == ODataFormat.Atom) { testDescriptor.ExpectedResultNormalizers.Add(config => (payloadElement => WcfDsServerPayloadElementNormalizer.Normalize(payloadElement, ODataFormat.Atom, testDescriptor.PayloadEdmModel as EdmModel))); } // We expect failure only if we don't allow duplicates or if the property kind doesn't allow duplicates ever if ((!duplicatePropertySet.DuplicationPotentiallyAllowed || !allowDuplicateProperties)) { testDescriptor.ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed", "DuplicateProperty"); } IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { testDescriptor.InProperty("TopLevelProperty"), testDescriptor.InProperty("ComplexProperty").InEntity(2, 2), testDescriptor.InCollection(5, 5).InProperty("TopLevelCollection"), }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, td => { var property = td.PayloadElement as PropertyInstance; if (property != null && testConfiguration.Format == ODataFormat.Atom) { property.Name = null; } td.RunTest(testConfiguration); }); }); }
/// <summary> /// Returns the payload to be used for this test case and the specified test configuration. /// </summary> /// <param name="testConfiguration">The test configuration to use.</param> /// <returns>The payload to use for testing.</returns> public static byte[] GetPayload( ReaderTestConfiguration testConfiguration, List<Func<ReaderTestConfiguration, Func<ODataPayloadElement, ODataPayloadElement>>> payloadNormalizers, PayloadReaderTestDescriptor.Settings settings, ODataPayloadElement payloadElement) { IPayloadSerializer payloadSerializer = null; // Apply all payload element transforms before serialization. IPayloadTransform<ODataPayloadElement> payloadElementTransform = settings.PayloadTransformFactory.GetTransform<ODataPayloadElement>(); ODataPayloadElement transformedODataElement = null; if (payloadElementTransform.TryTransform(payloadElement, out transformedODataElement)) { payloadElement = transformedODataElement; } ODataPayloadElement payloadElementToSerialize = payloadElement; // Apply all normalizers/fixups before serialization if (payloadNormalizers != null) { ODataPayloadElement payloadElementCopy = null; foreach (var getPayloadNormalizerFunc in payloadNormalizers) { var normalizer = getPayloadNormalizerFunc(testConfiguration); if (normalizer != null) { if (payloadElementCopy == null) { payloadElementCopy = payloadElementToSerialize.DeepCopy(); } payloadElementCopy = normalizer(payloadElementCopy); } } payloadElementToSerialize = payloadElementCopy ?? payloadElementToSerialize; } if (testConfiguration.Format == ODataFormat.Atom) { payloadSerializer = new XmlPayloadSerializer(settings.PayloadElementToXmlConverter); } else if (testConfiguration.Format == ODataFormat.Json) { // Create a copy of the payload element so that we can add annotations to it. payloadElementToSerialize = payloadElementToSerialize.DeepCopy(); // Annotate elements with version and response/request as appropriate PayloadFormatVersionAnnotatingVisitor.AnnotateJsonLight( payloadElementToSerialize, testConfiguration.Version.ToDataServiceProtocolVersion(), testConfiguration.IsRequest); payloadSerializer = new JsonPayloadSerializer(settings.PayloadElementToJsonLightConverter.ConvertToJsonLight); } else if (testConfiguration.Format == null) { if (payloadElementToSerialize.ElementType == ODataPayloadElementType.PrimitiveValue) { PrimitiveValue primitiveValue = (PrimitiveValue)payloadElementToSerialize; if (primitiveValue.ClrValue == null) { throw new NotSupportedException("Reading null values is not supported (since we don't support writing null values)."); } else if (primitiveValue.ClrValue.GetType() == typeof(byte[])) { payloadSerializer = settings.BinaryValuePayloadElementConverter; } else { payloadSerializer = settings.TextValuePayloadElementConverter; } } else if (payloadElementToSerialize.ElementType == ODataPayloadElementType.BatchRequestPayload || payloadElementToSerialize.ElementType == ODataPayloadElementType.BatchResponsePayload) { return SerializeBatchPayload(payloadElementToSerialize, settings); } else { throw new NotImplementedException("Default format not yet implemented for payload test descriptor and payload element type '" + payloadElementToSerialize.ElementType + "'."); } } else { throw new NotSupportedException("Unexpected format."); } // Default encoding is UTF8 return payloadSerializer.SerializeToBinary(payloadElementToSerialize, null); }
/// <summary> /// Creates a set of interesting primitive value test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for payload reader test descriptor to use.</param> /// <param name="fullSet">true if all available primitive values should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreatePrimitiveValueTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool fullSet = true) { EdmModel model = new EdmModel().Fixup(); IEnumerable<PrimitiveValue> primitiveValues = TestValues.CreatePrimitiveValuesWithMetadata(fullSet); return primitiveValues.Select(c => new PayloadReaderTestDescriptor(settings) { PayloadElement = c, PayloadEdmModel = model }); }
/// <summary> /// Creates a set of interesting stream reference (named stream) test descriptors, optionally with metadata. /// </summary> /// <param name="settings">The settings for payload reader test descriptor to use.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <returns>Enumeration of interesting stream reference test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateStreamReferenceValueTestDescriptors(PayloadReaderTestDescriptor.Settings settings, bool withMetadata) { EdmModel model = withMetadata ? new EdmModel().Fixup() : null; IEnumerable<NamedStreamInstance> namedStreams = TestValues.CreateStreamReferenceValues(); return namedStreams.Select(c => new PayloadReaderTestDescriptor(settings) { PayloadElement = c, PayloadEdmModel = model }); }
/// <summary> /// Creates a set of interesting complex value test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for payload reader test descriptor to use.</param> /// <param name="withTypeNames">true if the complex value payloads should specify type names.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <param name="fullSet">true if all available complex values should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateComplexValueTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withTypeNames, bool fullSet = true) { EdmModel model = new EdmModel().Fixup(); IEnumerable<ComplexInstance> complexValues = TestValues.CreateComplexValues(model, withTypeNames, fullSet); return complexValues.Select(c => new PayloadReaderTestDescriptor(settings) { PayloadElement = c, PayloadEdmModel = model }); }
/// <summary> /// Creates a set of interesting deferred navigation link test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for payload reader test descriptor to use.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <returns>Enumeration of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateDeferredNavigationLinkTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withMetadata) { EdmModel model = withMetadata ? new EdmModel().Fixup() : null; return TestValues.CreateDeferredNavigationLinks().Select(navigationLink => new PayloadReaderTestDescriptor(settings) { PayloadElement = navigationLink, PayloadEdmModel = model }); }
/// <summary> /// Creates a set of interesting collections test descriptors along with metadata. /// </summary> /// <param name="withTypeNames">true if the complex value payloads should specify type names.</param> /// <param name="fullSet">true if all available collections should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateCollectionTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withTypeNames, bool fullSet = true) { return CreatePrimitiveCollectionTestDescriptors(settings, withTypeNames, fullSet) .Concat(CreateComplexCollectionTestDescriptors(settings, withTypeNames, fullSet)); }
public void ServiceDocumentReaderWithoutAtomMetadataTest() { IEnumerable<PayloadReaderTestDescriptor> manualDescriptors = new PayloadReaderTestDescriptor[] { #region extra nodes // collection element in a different namespace. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace(PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <cn:collection href='" + baseUri + @"Products'> </cn:collection> </workspace> </service>"), }, // collection element in a ATOM namespace. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace(PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <atom:collection href='" + baseUri + @"Products'> </atom:collection> </workspace> </service>"), }, // irrelevant child element inside a workspace element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace(PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <cn:foo href='" + baseUri + @"Products'> </cn:foo> </workspace> </service>"), }, #endregion extra nodes // Invalid reader tests #region Empty service document. // Service document with no children. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument() .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_MissingWorkspaceElement"), }, // Empty service. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument() .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom' />"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_MissingWorkspaceElement"), }, #endregion Empty service document. #region service element with wrong name or namespace // Service element not named as 'service'. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<myservice xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace/> </myservice>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_ServiceDocumentRootElementWrongNameOrNamespace", "myservice", TestAtomConstants.AtomApplicationNamespace), }, // Service element not in the 'app' namespace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<cn:service xmlns:cn='http://custom_namespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace/> </cn:service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_ServiceDocumentRootElementWrongNameOrNamespace", "service", "http://custom_namespace"), }, #endregion root element with wrong name or namespace #region workspace element with wrong name or namespace // Workspace element is not named as 'workspace'. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <myworkspace> <collection href='" + baseUri + @"Products'/> </myworkspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInServiceDocument", "myworkspace", TestAtomConstants.AtomApplicationNamespace), }, // Workspace element not in the 'app' namespace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:cn='http://custom_namespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <cn:workspace/> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_MissingWorkspaceElement"), }, #endregion workspace element wrong name or namespace #region missing href // href in different namespace new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:cn='http://customnamespace' xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection cn:href='" + baseUri + @"Products'> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_ServiceDocumentElementUrlMustNotBeNull") }, #endregion missing href #region multiple workspaces // multiple workspaces new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> </collection> </workspace> <workspace> <collection href='Orders'> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_MultipleWorkspaceElementsFound"), }, #endregion multiple workspaces #region extra elements in ATOM publishing namespace // Element in 'app' namespace after the workspace element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace/> <foo baz='bar2'>somedata</foo> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInServiceDocument", "foo", TestAtomConstants.AtomApplicationNamespace), }, // Element in 'app' namespace before the workspace document. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace()) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <foo baz='bar2'>somedata</foo> <workspace/> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInServiceDocument", "foo", TestAtomConstants.AtomApplicationNamespace), }, // Element in 'app' namespace before the collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <foo baz='bar2'>somedata</foo> <collection href='" + baseUri + @"Products'> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInWorkspace", "foo", TestAtomConstants.AtomApplicationNamespace), }, // Element in 'app' namespace after the collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> </collection> <foo baz='bar2'>somedata</foo> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInWorkspace", "foo", TestAtomConstants.AtomApplicationNamespace), }, // Element in 'app' namespace inside the collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument().Workspace( PayloadBuilder.Workspace().ResourceCollection(null, baseUri + "Products")) .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <foo baz='bar2'>somedata</foo> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInResourceCollection", "foo", TestAtomConstants.AtomApplicationNamespace), }, // Nested workspace element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument() .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <workspace /> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInWorkspace", "workspace", TestAtomConstants.AtomApplicationNamespace), }, // Nested collection element. new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.ServiceDocument() .XmlRepresentation(@"<service xmlns:app='http://www.w3.org/2007/app' xmlns='http://www.w3.org/2007/app' xmlns:atom='http://www.w3.org/2005/Atom'> <workspace> <collection href='" + baseUri + @"Products'> <collection href='" + baseUri + @"Customers' /> </collection> </workspace> </service>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomServiceDocumentDeserializer_UnexpectedElementInResourceCollection", "collection", TestAtomConstants.AtomApplicationNamespace), }, #endregion extra elements in ATOM publishing namespace }; this.CombinatorialEngineProvider.RunCombinations( manualDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), new bool[] { true, false }, (testDescriptor, testConfiguration, enableAtomMetadataReading) => { testConfiguration = new ReaderTestConfiguration(testConfiguration); testConfiguration.MessageReaderSettings.EnableAtomMetadataReading = enableAtomMetadataReading; testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Creates a set of interesting homogeneous collection value test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for the payload reader test descriptor to use.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <param name="withTypeNames">true if the collection value payloads should specify type names.</param> /// <param name="withExpectedType">true if an expected type annotation should be added to the generated payload element; otherwise false.</param> /// <param name="withcollectionName">true if the collection is not in the top level, otherwise false</param> /// <param name="fullSet">true if all available collection values should be returned, false if only the most interesting subset should be returned.</param> /// <returns>List of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateHomogeneousCollectionValueTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withMetadata, bool withTypeNames, bool withExpectedType, bool withcollectionName, bool fullSet = true) { EdmModel model = withMetadata ? new EdmModel() : null; IEnumerable<ODataPayloadElementCollection> collectionValues = TestValues.CreateHomogeneousCollectionValues(model, withTypeNames, withExpectedType, withcollectionName, fullSet); return collectionValues.Select(collectionValue => { PayloadReaderTestDescriptor testDescriptor = new PayloadReaderTestDescriptor(settings) { PayloadElement = collectionValue, PayloadEdmModel = model }; if (withExpectedType && !withTypeNames) { // fill in the type names for the expected result payload since they will be added based on the expected type testDescriptor.ExpectedResultNormalizers.Add(tc => FillTypeNamesFromTypeAnnotationsPayloadElementVisitor.Visit); } if (!withExpectedType) { testDescriptor.ExpectedResultNormalizers.Add( tc => (Func<ODataPayloadElement, ODataPayloadElement>)null); } // Do not run the test descriptor if we do not have an expected type in JSON Light because it would fail. testDescriptor.SkipTestConfiguration = tc => tc.Format == ODataFormat.Json && !withExpectedType; return testDescriptor; }); }
/// <summary> /// Wrapper to use the IPayloadGenerator for reader payloads. /// </summary> /// <param name="payload">The payload to generate reader input payloads for.</param> /// <param name="payloadGenerator">The implementation of the IPayloadGenerator to use.</param> /// <returns>A set of payloads that use the <paramref name="payload"/> in interesting places.</returns> internal static IEnumerable <PayloadReaderTestDescriptor> GenerateReaderPayloads(this IPayloadGenerator payloadGenerator, PayloadReaderTestDescriptor payload) { foreach (var payloadDescriptor in payloadGenerator.GeneratePayloads(payload.PayloadDescriptor)) { yield return(new PayloadReaderTestDescriptor(payload) { PayloadDescriptor = payloadDescriptor, IsGeneratedPayload = !object.ReferenceEquals(payload.PayloadDescriptor, payloadDescriptor), }); } }
/// <summary> /// Creates a set of interesting expanded navigation link test descriptors along with metadata. /// </summary> /// <param name="settings">The settings for payload reader test descriptor to use.</param> /// <param name="withMetadata">true if the generated test descriptors should have metadata.</param> /// <returns>Enumeration of interesting test descriptors.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateExpandedNavigationLinkTestDescriptors( PayloadReaderTestDescriptor.Settings settings, bool withMetadata) { return (IEnumerable<PayloadReaderTestDescriptor>)CreateDeferredNavigationLinkTestDescriptors(settings, withMetadata).SelectMany(td => new[] { new PayloadReaderTestDescriptor(settings){ PayloadDescriptor = td.PayloadDescriptor.ExpandNavigationProperty(true) }, new PayloadReaderTestDescriptor(settings){ PayloadDescriptor = td.PayloadDescriptor.ExpandNavigationProperty(false)}, new PayloadReaderTestDescriptor(settings){ PayloadDescriptor = td.PayloadDescriptor.ExpandNavigationProperty(false, 5)}, new PayloadReaderTestDescriptor(settings){ PayloadDescriptor = td.PayloadDescriptor.ExpandNavigationProperty(false, 5, "http://odata.org/expanded_navigation_link_next_feed_link")} }); }
public void HomogeneousCollectionReaderAtomTest() { EdmModel edmModel = new EdmModel(); EdmComplexType edmComplexTypeEmpty = new EdmComplexType(ModelNamespace, "EmptyComplexType"); edmModel.AddElement(edmComplexTypeEmpty); EdmComplexType edmComplexTypeCity = new EdmComplexType(ModelNamespace, "CityType"); edmComplexTypeCity.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(true)); edmModel.AddElement(edmComplexTypeCity); EdmComplexType edmComplexTypeAddress = new EdmComplexType(ModelNamespace, "AddressType"); edmComplexTypeAddress.AddStructuralProperty("Street", EdmCoreModel.Instance.GetString(true)); edmModel.AddElement(edmComplexTypeAddress); edmModel.Fixup(); IEnumerable<PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { // complex collection with primitive expected type new PayloadReaderTestDescriptor(this.PayloadTestDescriptorSettings) { PayloadElement = new ComplexInstanceCollection( PayloadBuilder.ComplexValue("TestModel.CityType").Property("Name", PayloadBuilder.PrimitiveValue("Vienna")), PayloadBuilder.ComplexValue("TestModel.CityType").Property("Name", PayloadBuilder.PrimitiveValue("Prague")) ).ExpectedCollectionItemType(EdmDataTypes.Int32).CollectionName(null), PayloadEdmModel = edmModel, ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_IncorrectTypeKind", "TestModel.CityType", "Primitive", "Complex"), }, // primitive collection in XMLRepresentation with complex expected type. new PayloadReaderTestDescriptor(this.PayloadTestDescriptorSettings) { PayloadElement = new ComplexInstanceCollection( PayloadBuilder.ComplexValue("TestModel.CityType"), PayloadBuilder.ComplexValue("TestModel.CityType") ).ExpectedCollectionItemType(edmComplexTypeCity).CollectionName(null) .XmlRepresentation(@" <m:value> <m:element m:type='Edm.Int32'>1</m:element> <m:element m:type='Edm.Int32'>2</m:element> </m:value>"), PayloadEdmModel = edmModel, ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_IncorrectTypeKind", "Edm.Int32", "Complex", "Primitive"), }, }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Returns the serialized batch payload /// </summary> /// <param name="batchPayload">batch payload</param> /// <returns>bytes representing batch payload</returns> private static byte[] SerializeBatchPayload(ODataPayloadElement batchPayload, PayloadReaderTestDescriptor.Settings settings) { string boundary = null; Byte[] bytes = null; Func<ODataPayloadElement, string> getBoundaryAnnotation = (batchPayloadElement) => { var boundaryAnn = batchPayloadElement.Annotations.OfType<BatchBoundaryAnnotation>().Single(); ExceptionUtilities.CheckObjectNotNull(boundaryAnn, "bounday annotation cannot be null"); return boundaryAnn.BatchBoundaryInPayload; }; var batchRequestPayload = batchPayload as BatchRequestPayload; if (batchRequestPayload != null) { boundary = getBoundaryAnnotation(batchRequestPayload); bytes = settings.BatchSerializer.SerializeBatchPayload(batchRequestPayload, boundary, Encoding.UTF8.WebName); // encoding assumed to be UTF8 } else { var batchResponsePayload = batchPayload as BatchResponsePayload; boundary = getBoundaryAnnotation(batchResponsePayload); ExceptionUtilities.CheckObjectNotNull(batchResponsePayload, "the specified batch payload is neither a request payload nor a response"); bytes = settings.BatchSerializer.SerializeBatchPayload(batchResponsePayload, boundary, Encoding.UTF8.WebName); // encoding assumed to be UTF8 } return bytes; }
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); }); }); }
/// <summary> /// Creates error reader test descriptors with deeply nested internal exceptions. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="depthLimit">The maximum depth limit for nested errors. Payloads with error depth over this limit should fail.</param> /// <returns>An enumerable of <see cref="PayloadReaderTestDescriptor"/> representing the deeply nested error payloads.</returns> internal static IEnumerable<PayloadReaderTestDescriptor> CreateErrorDeeplyNestedReaderTestDescriptors(PayloadReaderTestDescriptor.Settings settings, int depthLimit) { ODataInternalExceptionPayload deeplyNestedInnerError = PayloadBuilder.InnerError(); // Create 'depthLimit' levels of depth (loop 'depthLimit - 1' times since we've already constructed one inner error). for (int index = 0; index < depthLimit - 1; index++) { deeplyNestedInnerError.InnerError(deeplyNestedInnerError.DeepCopy()); } // Add one more level of depth to create an invalid payload. ODataInternalExceptionPayload tooDeeplyNestedInnerError = PayloadBuilder.InnerError().InnerError(deeplyNestedInnerError.DeepCopy()); yield return new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(deeplyNestedInnerError), SkipTestConfiguration = tc => tc.IsRequest }; yield return new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(tooDeeplyNestedInnerError), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_RecursionDepthLimitReached", Convert.ToString(depthLimit)), SkipTestConfiguration = tc => tc.IsRequest }; }
/// <summary> /// Creates the input message for the test descriptor /// </summary> /// <param name="testConfiguration">the test configuration to use</param> /// <param name="readerTestDescriptor">The test descriptor</param> /// <param name="settings">The test descriptor settings</param> /// <param name="applyPayloadTransformations">Whether or not to apply payload transformations</param> /// <returns>The message for the test</returns> public static TestMessage CreateInputMessage(ReaderTestConfiguration testConfiguration, PayloadReaderTestDescriptor readerTestDescriptor, PayloadReaderTestDescriptor.Settings settings, bool? applyPayloadTransformations) { TestMessage testMessage; bool originalApplyTransformValue = false; var odataTransformFactory = settings.PayloadTransformFactory as ODataLibPayloadTransformFactory; try { if (applyPayloadTransformations.HasValue && odataTransformFactory != null) { originalApplyTransformValue = odataTransformFactory.ApplyTransform; odataTransformFactory.ApplyTransform = applyPayloadTransformations.Value; } if (readerTestDescriptor.TestDescriptorNormalizers != null) { foreach (var testDescriptorNormalizer in readerTestDescriptor.TestDescriptorNormalizers) { var normalizerAction = testDescriptorNormalizer(testConfiguration); if (normalizerAction != null) { normalizerAction(readerTestDescriptor); } } } MemoryStream memoryStream = new MemoryStream(GetPayload(testConfiguration, readerTestDescriptor.PayloadNormalizers, settings, readerTestDescriptor.PayloadElement)); TestStream messageStream = new TestStream(memoryStream); if (testConfiguration.Synchronous) { messageStream.FailAsynchronousCalls = true; } else { messageStream.FailSynchronousCalls = true; } testMessage = TestReaderUtils.CreateInputMessageFromStream( messageStream, testConfiguration, readerTestDescriptor.PayloadElement.GetPayloadKindFromPayloadElement(), readerTestDescriptor.PayloadElement.GetCustomContentTypeHeader(), readerTestDescriptor.UrlResolver); if (readerTestDescriptor.TestMessageWrapper != null) { testMessage = readerTestDescriptor.TestMessageWrapper(testMessage); } return testMessage; } finally { if (applyPayloadTransformations.HasValue && odataTransformFactory != null) { odataTransformFactory.ApplyTransform = originalApplyTransformValue; } } }