/// <summary> /// Returns all interesting payloads for a property. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single entry with a single property. /// The entry is not going to be used, but the property from it will.</param> /// <returns>Enumeration of test descriptors which will include the original property in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > PropertyPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataResource tempEntry = testDescriptor.PayloadItems[0] as ODataResource; Debug.Assert(tempEntry != null, "A single entry payload is expected."); ODataProperty property = tempEntry.Properties.First(); // Note - the property can be null - it is a valid test case !!!! var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Single property on an entry { GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.Properties = new ODataProperty[] { property }; return(new ODataItem[] { entry }); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractPropertiesFromEntry(result).Element(TestAtomConstants.ODataXNamespace + property.Name)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // TODO: Add other interesting payloads for properties - more properties in an entry, inside a complex property, inside a collection of complex and so on }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
private void InvokeWriterAction(ODataMessageWriterTestWrapper messageWriter, ODataWriter writer, WriterAction writerAction) { switch (writerAction) { case WriterAction.StartResource: writer.WriteStart(ObjectModelUtils.CreateDefaultEntry()); break; case WriterAction.StartFeed: writer.WriteStart(ObjectModelUtils.CreateDefaultFeed()); break; case WriterAction.StartLink: writer.WriteStart(ObjectModelUtils.CreateDefaultCollectionLink()); break; case WriterAction.End: writer.WriteEnd(); break; case WriterAction.Error: messageWriter.WriteError(new ODataError(), false); break; } }
public void EntryValidationTest() { var testCases = new[] { new { // type name must not be empty InvalidateEntry = new Action <ODataResource>(entry => entry.TypeName = string.Empty), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_TypeNameMustNotBeEmpty") }, }; // Convert test cases to test descriptions var testDescriptors = testCases.Select(testCase => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); testCase.InvalidateEntry(entry); return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException })); }); // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => false), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
/// <summary> /// Returns all interesting payloads for a navigation link itself. That is the ODataNestedResourceInfo without any subsequent events. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single navigation link.</param> /// <returns>Enumeration of test descriptors which will include the original navigation link in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > NavigationLinkOnlyPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataNestedResourceInfo navigationLink = testDescriptor.PayloadItems[0] as ODataNestedResourceInfo; Debug.Assert(navigationLink != null, "Navigation link payload expected."); Debug.Assert(navigationLink.IsCollection.HasValue, "ODataNestedResourceInfo.IsCollection required."); var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Just the link as non-expanded { GetPayloadItems = () => new ODataItem[] { navigationLink } }, new WriterPayloadCase <ODataItem>() // The link with expanded entry { GetPayloadItems = () => { if (navigationLink.IsCollection.Value) { return(new ODataItem[] { navigationLink, ObjectModelUtils.CreateDefaultFeed() }); } else { return(new ODataItem[] { navigationLink, ObjectModelUtils.CreateDefaultEntry() }); } } } }; // Apply the cases here and then wrap the link in some entry/feed cases return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases).PayloadCases(NavigationLinkPayloads)); }
/// <summary> /// Returns all interesting payloads for a value. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single entry with a single property. /// The entry is not going to be used, the property is not going to be used, but the property value from it will.</param> /// <returns>Enumeration of test descriptors which will include the original value in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > ValuePayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataResource tempEntry = testDescriptor.PayloadItems[0] as ODataResource; Debug.Assert(tempEntry != null, "A single entry payload is expected."); ODataProperty property = tempEntry.Properties.First(); Debug.Assert(property != null, "A single property is expected."); object propertyValue = property.Value; var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Value of a property { GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.Properties = new ODataProperty[] { new ODataProperty() { Name = "TestProperty", Value = propertyValue } }; return(new ODataItem[] { entry }); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractPropertiesFromEntry(result).Element(TestAtomConstants.ODataXNamespace + property.Name)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, new WriterPayloadCase <ODataItem>() // Value as item in a collection { ShouldSkip = testConfiguration => propertyValue is ODataCollectionValue, GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.Properties = new ODataProperty[] { new ODataProperty() { Name = "TestProperty", Value = new ODataCollectionValue() { Items = new object[] { propertyValue } } } }; return(new ODataItem[] { entry }); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractPropertiesFromEntry(result).Element(TestAtomConstants.ODataXNamespace + property.Name)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // TODO: Add other interesting payloads for property values }; // Combine with property payloads to get interesting places where the property itself is used. return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases).PayloadCases(PropertyPayloads)); }
public void FatalExceptionTest() { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); this.CombinatorialEngineProvider.RunCombinations( new ODataItem[] { entry }, new bool[] { true, false }, // flush // TODO: also enable this test for the sync scenarios this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => !tc.Synchronous), (payload, flush, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); using (var memoryStream = new TestStream()) using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert)) { ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false); ODataWriterCoreInspector inspector = new ODataWriterCoreInspector(writer); // close the memory stream so that any attempt to flush will cause a fatal error memoryStream.CloseInner(); // write the payload and call FlushAsync() to trigger a fatal exception Exception ex = TestExceptionUtils.RunCatching(() => TestWriterUtils.WritePayload(messageWriter, writer, true, entry)); this.Assert.IsNotNull(ex, "Expected exception but none was thrown."); NotSupportedException notSupported = null; #if SILVERLIGHT || WINDOWS_PHONE var baseEx = ex.GetBaseException(); this.Assert.IsNotNull(baseEx, "BaseException of exception:" + ex.ToString() + " should not be null"); notSupported = baseEx as NotSupportedException; this.Assert.IsNotNull(notSupported, "Expected NotSupportedException but " + baseEx.GetType().FullName + " was reported."); #else notSupported = TestExceptionUtils.UnwrapAggregateException(ex, this.Assert) as NotSupportedException; this.Assert.IsNotNull(notSupported, "Expected NotSupportedException but " + ex.ToString() + " was reported."); #endif this.Assert.AreEqual("Stream does not support writing.", notSupported.Message, "Did not find expected error message."); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'Error' state."); if (flush) { // Flush should work in error state. writer.Flush(); } // in all cases we have to be able to dispose the writer without problems. } }); }
private Action <WriterTestConfiguration> WriteEntry(Func <XElement, XElement> fragmentExtractor, Func <ODataVersion, string> expectedXml) { return((testConfiguration) => TestWriterUtils.WriteAndVerifyODataPayload( new PayloadWriterTestDescriptor <ODataItem>( this.Settings, ObjectModelUtils.CreateDefaultEntry(), expectedXml(testConfiguration.Version), null, fragmentExtractor, null, /*disableXmlNamespaceNormalization*/ true), testConfiguration, this.Assert, this.Logger)); }
public void DefaultStreamValidationTest() { var testCases = new[] { new { // empty content type is invalid InvalidateDefaultStream = new Action <ODataStreamReferenceValue>(mediaResource => mediaResource.ContentType = string.Empty), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_StreamReferenceValueEmptyContentType"), }, new { // null read link and non-empty content type is invalid InvalidateDefaultStream = new Action <ODataStreamReferenceValue>(mediaResource => { mediaResource.ReadLink = null; mediaResource.ContentType = "mime/type"; }), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_DefaultStreamWithContentTypeWithoutReadLink"), }, new { // non-null read link and null content type is invalid InvalidateDefaultStream = new Action <ODataStreamReferenceValue>(mediaResource => { mediaResource.ReadLink = new Uri("http://odata.org"); mediaResource.ContentType = null; }), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_DefaultStreamWithReadLinkWithoutContentType"), }, new { // etag without an edit link is invalid InvalidateDefaultStream = new Action <ODataStreamReferenceValue>(mediaResource => { mediaResource.ETag = "someetag"; mediaResource.EditLink = null; }), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_StreamReferenceValueMustHaveEditLinkToHaveETag"), }, }; var testDescriptors = testCases.Select(testCase => { ODataStreamReferenceValue mediaResource = ObjectModelUtils.CreateDefaultStream(); testCase.InvalidateDefaultStream(mediaResource); ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.MediaResource = mediaResource; return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, entry, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException })); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void WriteAfterExceptionTest() { // create a default entry and then set both read and edit links to null to provoke an exception during writing ODataResource faultyEntry = ObjectModelUtils.CreateDefaultEntry(); this.Assert.IsNull(faultyEntry.EditLink, "entry.EditLink == null"); ODataResource defaultEntry = ObjectModelUtils.CreateDefaultEntry(); ODataResourceSet defaultFeed = ObjectModelUtils.CreateDefaultFeed(); this.CombinatorialEngineProvider.RunCombinations( new ODataItem[] { faultyEntry }, new ODataItem[] { defaultFeed, defaultEntry }, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations, (faultyPayload, contentPayload, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); using (var memoryStream = new TestStream()) using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert)) { ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false); ODataWriterCoreInspector inspector = new ODataWriterCoreInspector(writer); // write the invalid entry and expect an exception this.Assert.ExpectedException( () => TestWriterUtils.WritePayload(messageWriter, writer, false, faultyEntry), ODataExpectedExceptions.ODataException("WriterValidationUtils_EntriesMustHaveNonEmptyId"), this.ExceptionVerifier); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state."); // now write some non-error content which is invalid to do Exception ex = TestExceptionUtils.RunCatching(() => TestWriterUtils.WritePayload(messageWriter, writer, false, contentPayload)); ex = TestExceptionUtils.UnwrapAggregateException(ex, this.Assert); this.Assert.IsNotNull(ex, "Expected exception but none was thrown"); this.Assert.IsTrue(ex is ODataException, "Expected an ODataException instance but got a " + ex.GetType().FullName + "."); this.Assert.IsTrue(ex.Message.Contains("Cannot transition from state 'Error' to state "), "Did not find expected start of error message."); this.Assert.IsTrue(ex.Message.Contains("Nothing can be written once the writer entered the error state."), "Did not find expected end of error message in '" + ex.Message + "'."); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state."); writer.Flush(); } }); }
/// <summary> /// Returns all interesting payloads for a navigation link. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single navigation link.</param> /// <returns>Enumeration of test descriptors which will include the original navigation link in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > NavigationLinkPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataNestedResourceInfo navigationLink = testDescriptor.PayloadItems[0] as ODataNestedResourceInfo; Debug.Assert(navigationLink != null, "Link payload expected."); var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Single link on top-level entry { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry() }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Where(linkElement => linkElement.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value.StartsWith(TestAtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix)) .First()); }, }, // TODO: Add other interesting payloads for links - in expanded entry, in expanded feed }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
public void BaseUriValidationTest() { string relativeUriString = "abc/pqr/"; Uri absoluteUri = new Uri("http://odata.org"); Uri relativeUri = absoluteUri.MakeRelativeUri(new Uri(absoluteUri, relativeUriString)); string expectedError = "The base URI '" + relativeUriString + "' specified in ODataMessageWriterSettings.BaseUri is invalid; it must either be null or an absolute URI."; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); var testDescriptors = new [] { new { BaseUri = relativeUri, TestDescriptor = new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedODataExceptionMessage = expectedError }) } }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations, (testDescriptor, testConfiguration) => { // clone the test configuration and set an invalid base Uri ODataMessageWriterSettings settings = testConfiguration.MessageWriterSettings.Clone(); settings.BaseUri = testDescriptor.BaseUri; WriterTestConfiguration config = new WriterTestConfiguration(testConfiguration.Format, settings, testConfiguration.IsRequest, testConfiguration.Synchronous); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor.TestDescriptor, config, this.Assert, this.Logger); }); }
public void WriteAfterDisposeTest() { this.CombinatorialEngineProvider.RunCombinations( this.WriterTestConfigurationProvider.ExplicitFormatConfigurations, (testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); using (var stream = new TestStream()) { ODataWriter writer; using (var messageWriter = TestWriterUtils.CreateMessageWriter(stream, testConfiguration, this.Assert)) { writer = messageWriter.CreateODataWriter(isFeed: true); // Message writer is disposed outside of this scope. } this.VerifyWriterAlreadyDisposed(() => writer.WriteStart(ObjectModelUtils.CreateDefaultFeed())); this.VerifyWriterAlreadyDisposed(() => writer.WriteStart(ObjectModelUtils.CreateDefaultEntry())); this.VerifyWriterAlreadyDisposed(() => writer.WriteStart(ObjectModelUtils.CreateDefaultCollectionLink())); } }); }
public void AssociationLinkOnNavigationLinkTest() { EdmModel model = new EdmModel(); var container = new EdmEntityContainer("TestModel", "Default"); model.AddElement(container); var edmEntityTypeOrderType = new EdmEntityType("TestModel", "OrderType"); model.AddElement(edmEntityTypeOrderType); var edmEntityTypeCustomerType = new EdmEntityType("TestModel", "CustomerType"); var edmNavigationPropertyAssociationLinkOne = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "NavProp1", Target = edmEntityTypeOrderType, TargetMultiplicity = EdmMultiplicity.One }); var edmNavigationPropertyAssociationLinkTwo = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "NavProp2", Target = edmEntityTypeOrderType, TargetMultiplicity = EdmMultiplicity.Many }); model.AddElement(edmEntityTypeCustomerType); var customerSet = container.AddEntitySet("Customers", edmEntityTypeCustomerType); var orderSet = container.AddEntitySet("Orders", edmEntityTypeOrderType); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkOne, orderSet); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkTwo, orderSet); var testCases = new[] { // Both nav link URL and association link URL new { NavigationLink = new ODataNestedResourceInfo() { Name = "NavProp1", IsCollection = false, Url = new Uri("http://odata.org/navlink"), AssociationLinkUrl = new Uri("http://odata.org/assoclink") }, PropertyName = "NavProp1", Atom = BuildXmlNavigationLink("NavProp1", "application/atom+xml;type=entry", "http://odata.org/navlink"), JsonLight = "\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + "\":\"http://odata.org/navlink\"," + "\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + "\":\"http://odata.org/assoclink\"" }, // Just nav link URL new { NavigationLink = new ODataNestedResourceInfo() { Name = "NavProp1", IsCollection = false, Url = new Uri("http://odata.org/navlink"), AssociationLinkUrl = null }, PropertyName = "NavProp1", Atom = BuildXmlNavigationLink("NavProp1", "application/atom+xml;type=entry", "http://odata.org/navlink"), JsonLight = "\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + "\":\"http://odata.org/navlink\"" }, // Just association link URL new { NavigationLink = new ODataNestedResourceInfo() { Name = "NavProp1", IsCollection = false, Url = null, AssociationLinkUrl = new Uri("http://odata.org/assoclink") }, PropertyName = "NavProp1", Atom = (string)null, JsonLight = "\"" + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + "\":\"http://odata.org/assoclink\"" }, // Navigation link with both URLs null new { NavigationLink = new ODataNestedResourceInfo() { Name = "NavProp1", IsCollection = false, Url = null, AssociationLinkUrl = null }, PropertyName = "NavProp1", Atom = (string)null, JsonLight = string.Empty } }; IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testDescriptors = testCases.Select(testCase => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = "TestModel.CustomerType"; return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { entry, testCase.NavigationLink, null }, (testConfiguration) => { if (testConfiguration.Format == ODataFormat.Json) { return new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = string.Join( "$(NL)", "{", testCase.JsonLight, "}"), FragmentExtractor = (result) => { var links = result.Object().GetPropertyAnnotations(testCase.PropertyName).ToList(); var jsonResult = new JsonObject(); links.ForEach(l => { // NOTE we remove all annoatations here and in particular the text annotations to be able to easily compare // against the expected results. This however means that we do not distinguish between the indented and non-indented case here. l.RemoveAllAnnotations(true); jsonResult.Add(l); }); return jsonResult; } }; } else { this.Settings.Assert.Fail("Unknown format '{0}'.", testConfiguration.Format); return null; } }) { Model = model, PayloadEdmElementContainer = customerSet }); }); // With and without model testDescriptors = testDescriptors.SelectMany(td => new[] { td, new PayloadWriterTestDescriptor <ODataItem>(td) { Model = null, PayloadEdmElementContainer = null } }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent.Where(testConfiguration => !testConfiguration.IsRequest), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); if (testDescriptor.Model == null && testConfiguration.Format == ODataFormat.Json) { return; } if (testDescriptor.IsGeneratedPayload && testDescriptor.Model != null) { return; } TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void DisposeAfterExceptionTest() { // create a default entry and then set both read and edit links to null to provoke an exception during writing ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); this.Assert.IsNull(entry.EditLink, "entry.EditLink == null"); this.CombinatorialEngineProvider.RunCombinations( new ODataItem[] { entry }, new bool[] { true, false }, // writeError new bool[] { true, false }, // flush this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(c => c.IsRequest == false), (payload, writeError, flush, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); // try writing to a memory stream using (var memoryStream = new TestStream()) using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert)) { ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false); ODataWriterCoreInspector inspector = new ODataWriterCoreInspector(writer); try { // write the invalid entry and expect an exception TestExceptionUtils.ExpectedException( this.Assert, () => TestWriterUtils.WritePayload(messageWriter, writer, false, entry), ODataExpectedExceptions.ODataException("WriterValidationUtils_EntriesMustHaveNonEmptyId"), this.ExceptionVerifier); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state."); if (writeError) { // now write an error which is the only valid thing to do ODataAnnotatedError error = new ODataAnnotatedError { Error = new ODataError() { Message = "DisposeAfterExceptionTest error message." } }; Exception ex = TestExceptionUtils.RunCatching(() => TestWriterUtils.WritePayload(messageWriter, writer, false, error)); this.Assert.IsNull(ex, "Unexpected error '" + (ex == null ? "<none>" : ex.Message) + "' while writing an error."); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state."); } if (flush) { writer.Flush(); } } catch (ODataException oe) { if (writeError && !flush) { this.Assert.AreEqual("A writer or stream has been disposed with data still in the buffer. You must call Flush or FlushAsync before calling Dispose when some data has already been written.", oe.Message, "Did not find expected error message"); this.Assert.IsTrue(inspector.IsInErrorState, "Writer is not in expected 'error' state."); } else { this.Assert.Fail("Caught an unexpected ODataException: " + oe.Message + "."); } } } }); }
private void WriterStatesTestImplementation(bool feedWriter) { var testCases = new WriterStatesTestDescriptor[] { // Start new WriterStatesTestDescriptor { Setup = null, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, feedWriter ? ODataExpectedExceptions.ODataException("ODataWriterCore_CannotWriteTopLevelResourceWithResourceSetWriter") : (ExpectedException)null }, { WriterAction.StartFeed, feedWriter ? (ExpectedException)null : ODataExpectedExceptions.ODataException("ODataWriterCore_CannotWriteTopLevelResourceSetWithResourceWriter") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromStart", "Start", "NavigationLink") }, { WriterAction.End, ODataExpectedExceptions.ODataException("ODataWriterCore_WriteEndCalledInInvalidState", "Start") }, { WriterAction.Error, null }, } }, // Entry new WriterStatesTestDescriptor { Setup = (mw, w, s) => { if (feedWriter) { w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); } w.WriteStart(ObjectModelUtils.CreateDefaultEntry()); }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromResource", "Entry", "Entry") }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromResource", "Entry", "Feed") }, { WriterAction.StartLink, null }, { WriterAction.End, null }, { WriterAction.Error, null }, } }, // Feed new WriterStatesTestDescriptor { Setup = (mw, w, s) => { if (feedWriter) { w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); } else { w.WriteStart(ObjectModelUtils.CreateDefaultEntry()); w.WriteStart(ObjectModelUtils.CreateDefaultCollectionLink()); w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); } }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, null }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromResourceSet", "Feed", "Feed") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromResourceSet", "Feed", "NavigationLink") }, { WriterAction.End, null }, { WriterAction.Error, null }, } }, // Link - single new WriterStatesTestDescriptor { Setup = (mw, w, s) => { if (feedWriter) { w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); } w.WriteStart(ObjectModelUtils.CreateDefaultEntry()); w.WriteStart(new ODataNestedResourceInfo { Name = ObjectModelUtils.DefaultLinkName, Url = ObjectModelUtils.DefaultLinkUrl, IsCollection = false }); }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, null }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetContent", "http://odata.org/link") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidStateTransition", "NavigationLink", "NavigationLink") }, { WriterAction.End, null }, { WriterAction.Error, null }, }, SkipForTestConfiguration = tc => tc.IsRequest }, // Link - collection new WriterStatesTestDescriptor { Setup = (mw, w, s) => { if (feedWriter) { w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); } w.WriteStart(ObjectModelUtils.CreateDefaultEntry()); w.WriteStart(ObjectModelUtils.CreateDefaultCollectionLink()); }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceContent", "http://odata.org/link") }, { WriterAction.StartFeed, null }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidStateTransition", "NavigationLink", "NavigationLink") }, { WriterAction.End, null }, { WriterAction.Error, null }, }, SkipForTestConfiguration = tc => tc.IsRequest }, // Expanded link - there's no way to get to the expanded link state alone since the writer will always // immediately transition to either entry or feed state instead. // Completed new WriterStatesTestDescriptor { Setup = (mw, w, s) => { if (feedWriter) { w.WriteStart(ObjectModelUtils.CreateDefaultFeed()); w.WriteEnd(); } else { w.WriteStart(ObjectModelUtils.CreateDefaultEntry()); w.WriteEnd(); } }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromCompleted", "Completed", "Entry") }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromCompleted", "Completed", "Feed") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromCompleted", "Completed", "NavigationLink") }, { WriterAction.End, ODataExpectedExceptions.ODataException("ODataWriterCore_WriteEndCalledInInvalidState", "Completed") }, { WriterAction.Error, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromCompleted", "Completed", "Error") }, } }, // ODataExceptionThrown new WriterStatesTestDescriptor { Setup = (mw, w, s) => { TestExceptionUtils.RunCatching(() => w.WriteStart(ObjectModelUtils.CreateDefaultCollectionLink())); }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "Entry") }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "Feed") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "NavigationLink") }, { WriterAction.End, ODataExpectedExceptions.ODataException("ODataWriterCore_WriteEndCalledInInvalidState", "Error") }, { WriterAction.Error, null }, }, SkipForTestConfiguration = tc => tc.IsRequest, }, // Error new WriterStatesTestDescriptor { Setup = (mw, w, s) => { mw.WriteError(new ODataError(), false); }, ExpectedResults = new Dictionary <WriterAction, ExpectedException> { { WriterAction.StartResource, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "Entry") }, { WriterAction.StartFeed, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "Feed") }, { WriterAction.StartLink, ODataExpectedExceptions.ODataException("ODataWriterCore_InvalidTransitionFromError", "Error", "NavigationLink") }, { WriterAction.End, ODataExpectedExceptions.ODataException("ODataWriterCore_WriteEndCalledInInvalidState", "Error") }, { WriterAction.Error, ODataExpectedExceptions.ODataException("ODataMessageWriter_WriteErrorAlreadyCalled") }, }, SkipForTestConfiguration = tc => tc.IsRequest, }, }; ExpectedException errorNotAllowedException = ODataExpectedExceptions.ODataException("ODataMessageWriter_ErrorPayloadInRequest"); this.CombinatorialEngineProvider.RunCombinations( testCases, EnumExtensionMethods.GetValues <WriterAction>().Cast <WriterAction>(), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testCase, writerAction, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); if (testCase.SkipForTestConfiguration != null && testCase.SkipForTestConfiguration(testConfiguration)) { return; } ExpectedException expectedExceptionOnError; if (testCase.ExpectedResults.TryGetValue(WriterAction.Error, out expectedExceptionOnError)) { if (testConfiguration.IsRequest) { testCase = new WriterStatesTestDescriptor(testCase); testCase.ExpectedResults[WriterAction.Error] = errorNotAllowedException; } } using (TestStream stream = new TestStream()) { // We purposely don't use the using pattern around the messageWriter here. Disposing the message writer will // fail here because the writer is not left in a valid state. var messageWriter = TestWriterUtils.CreateMessageWriter(stream, testConfiguration, this.Assert); ODataWriter writer = messageWriter.CreateODataWriter(feedWriter); TestExceptionUtils.ExpectedException( this.Assert, () => { if (testCase.Setup != null) { testCase.Setup(messageWriter, writer, stream); } this.InvokeWriterAction(messageWriter, writer, writerAction); }, testCase.ExpectedResults[writerAction], this.ExceptionVerifier); } }); }
public void EntryDefaultStreamTest() { string readLink = "http://odata.org/read"; Uri readLinkUri = new Uri(readLink); string editLink = "http://odata.org/edit"; Uri editLinkUri = new Uri(editLink); string contentType = "application/binary"; string etag = "\"myetagvalue\""; string atomEscapedEtag = ""myetagvalue""; string outOfContentProperties = "<m:properties xmlns:m=\"" + TestAtomConstants.ODataMetadataNamespace + "\"><d:ID xmlns:d=\"" + TestAtomConstants.ODataNamespace + "\">foo</d:ID></m:properties>"; var testCases = new[] { new { // Completely empty default stream is valid and should not produce any MLE/MR related values in the payload DefaultStream = new ODataStreamReferenceValue(), Atom = outOfContentProperties, }, new { // Bare minimum for valid default stream DefaultStream = new ODataStreamReferenceValue() { ReadLink = readLinkUri, EditLink = null, ContentType = contentType, ETag = null }, Atom = "<content type=\"" + contentType + "\" src=\"" + readLinkUri + "\" xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + outOfContentProperties }, new { // with edit link DefaultStream = new ODataStreamReferenceValue() { ReadLink = readLinkUri, EditLink = editLinkUri, ContentType = contentType, ETag = null }, Atom = "<content type=\"" + contentType + "\" src=\"" + readLinkUri + "\" xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + "<link rel=\"edit-media\" href=\"" + editLink + "\" xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + outOfContentProperties }, new { // just edit link DefaultStream = new ODataStreamReferenceValue() { ReadLink = null, EditLink = editLinkUri, ContentType = null, ETag = null }, Atom = "<link rel=\"edit-media\" href=\"" + editLink + "\" xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + outOfContentProperties }, // etag without edit link is invalid and is covered in input validation tests new { // with edit link and etag DefaultStream = new ODataStreamReferenceValue() { ReadLink = readLinkUri, EditLink = editLinkUri, ContentType = contentType, ETag = etag }, Atom = "<content type=\"" + contentType + "\" src=\"" + readLinkUri + "\" xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + "<link rel=\"edit-media\" href=\"" + editLink + "\" p2:etag=\"" + atomEscapedEtag + "\" xmlns:p2=\"" + TestAtomConstants.ODataMetadataNamespace + "\" " + "xmlns=\"" + TestAtomConstants.AtomNamespace + "\" />" + outOfContentProperties } }; var testDescriptors = testCases.Select(testCase => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); entry.Properties = new ODataProperty[] { new ODataProperty { Name = "ID", Value = "foo" } }; entry.MediaResource = testCase.DefaultStream; return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, entry, (testConfiguration) => { return new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = "<DefaultStream>" + testCase.Atom + "</DefaultStream>", FragmentExtractor = (result) => { var content = result.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomContentElementName); content = content == null ? null : new XElement(content.Name, content.Attributes()); var mediaEditLink = result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Where(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.ODataStreamPropertyEditMediaSegmentName); var properties = result.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.AtomPropertiesElementName); return new XElement("DefaultStream", content, mediaEditLink, properties); } }; })); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurationsWithIndent, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void FeedUserExceptionTests() { IEdmModel edmModel = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); ODataFeed cityFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntry cityEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.CityType"); ODataNavigationLink cityHallCollectionLink = ObjectModelUtils.CreateDefaultCollectionLink("CityHall"); ODataNavigationLink policeStationSingletonLink = ObjectModelUtils.CreateDefaultSingletonLink("PoliceStation"); ODataFeed officeFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntry officeEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeType"); var container = edmModel.FindEntityContainer("DefaultContainer"); var citySet = container.FindEntitySet("Cities") as EdmEntitySet; var cityType = edmModel.FindType("TestModel.CityType") as EdmEntityType; ODataItem[] writerPayload = new ODataItem[] { cityFeed, cityEntry, null, cityEntry, cityHallCollectionLink, officeFeed, officeEntry, null, null, null, null, cityEntry, null, cityEntry, policeStationSingletonLink, officeEntry, null, null, null, }; IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testDescriptors = new PayloadWriterTestDescriptor <ODataItem>[] { new PayloadWriterTestDescriptor <ODataItem>( this.Settings, writerPayload, tc => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException = new Exception("User code triggered an exception."), } ) { Model = edmModel, PayloadEdmElementContainer = citySet, PayloadEdmElementType = cityType, } }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.FeedPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent, (testDescriptor, testConfiguration) => { if (testDescriptor.IsGeneratedPayload && (testConfiguration.Format == ODataFormat.Json || testDescriptor.Model != null)) { return; } foreach (int throwUserExceptionAt in Enumerable.Range(0, testDescriptor.PayloadItems.Count + 1)) { var configuredTestDescriptor = new PayloadWriterTestDescriptor <ODataItem>(this.Settings, testDescriptor.PayloadItems, testDescriptor.ExpectedResultCallback) { Model = testDescriptor.Model, PayloadEdmElementContainer = testDescriptor.PayloadEdmElementContainer, PayloadEdmElementType = testDescriptor.PayloadEdmElementType, ThrowUserExceptionAt = throwUserExceptionAt, }; TestWriterUtils.WriteAndVerifyODataEdmPayload(configuredTestDescriptor, testConfiguration, this.Assert, this.Logger); } }); }
public void FeedMetadataWriterTest() { AtomTextConstruct testRights = new AtomTextConstruct { Text = "Copyright Data Fx team." }; AtomTextConstruct testTitle = new AtomTextConstruct { Text = "Test title" }; AtomTextConstruct testSubtitle = new AtomTextConstruct { Text = "Test subtitle" }; const string testUpdated = "2010-11-01T00:04:00Z"; const string testIcon = "http://odata.org/icon"; const string testLogo = "http://odata.org/logo"; const string testAuthorName = "Test Author 1"; const string testAuthorEmail = "*****@*****.**"; const string testAuthorUri = "http://odata.org/authors/1"; var testAuthors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testAuthorEmail, Name = testAuthorName, Uri = new Uri(testAuthorUri) } }; const string testCategoryTerm = "Test category 1 term"; const string testCategoryLabel = "Test category 1 label"; const string testCategoryScheme = "http://odata.org/categories/1"; var testCategories = new AtomCategoryMetadata[] { new AtomCategoryMetadata() { Term = testCategoryTerm, Label = testCategoryLabel, Scheme = testCategoryScheme } }; const string testContributorName = "Test Contributor 1"; const string testContributorEmail = "*****@*****.**"; const string testContributorUri = "http://odata.org/contributors/1"; var testContributors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testContributorEmail, Name = testContributorName, Uri = new Uri(testContributorUri) } }; const string testGeneratorName = "Test generator"; const string testGeneratorUri = "http://odata.org/generator"; const string testGeneratorVersion = "3.0"; var testGenerator = new AtomGeneratorMetadata() { Name = testGeneratorName, Uri = new Uri(testGeneratorUri), Version = testGeneratorVersion }; const string testLinkRelation = "http://odata.org/links/1"; const string testLinkTitle = "Test link 1"; const string testLinkHref = "http://odata.org/links/1"; const string testLinkHrefLang = "de-AT"; int? testLinkLength = 999; const string testLinkMediaType = "image/png"; var testLinks = new AtomLinkMetadata[] { new AtomLinkMetadata() { Relation = testLinkRelation, Title = testLinkTitle, Href = new Uri(testLinkHref), HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType } }; var selfLink = new AtomLinkMetadata() { Relation = TestAtomConstants.AtomSelfRelationAttributeValue, Title = testLinkTitle, Href = new Uri(testLinkHref), HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }; Func <string, Func <XElement, XElement> > fragmentExtractor = (localName) => (e) => e.Element(TestAtomConstants.AtomXNamespace + localName); // TODO, ckerer: specify an Id via metadata if the entry does not specify one; we first have to decide what rules // we want to apply to merging of metadata and ODataLib OM data. var testCases = new FeedMetadataTestCase[] { new FeedMetadataTestCase { // specify an icon via metadata CustomizeMetadata = metadata => metadata.Icon = new Uri(testIcon), Xml = @"<icon xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testIcon + @"</icon>", Extractor = fragmentExtractor(TestAtomConstants.AtomIconElementName) }, new FeedMetadataTestCase { // specify a logo via metadata CustomizeMetadata = metadata => metadata.Logo = new Uri(testLogo), Xml = @"<logo xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testLogo + @"</logo>", Extractor = fragmentExtractor(TestAtomConstants.AtomLogoElementName) }, new FeedMetadataTestCase { // specify rights via metadata CustomizeMetadata = metadata => metadata.Rights = testRights, Xml = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>", Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName) }, new FeedMetadataTestCase { // specify a subtitle via metadata CustomizeMetadata = metadata => metadata.Subtitle = testSubtitle, Xml = @"<subtitle type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSubtitle.Text + @"</subtitle>", Extractor = fragmentExtractor(TestAtomConstants.AtomSubtitleElementName) }, new FeedMetadataTestCase { // specify a title via metadata CustomizeMetadata = metadata => metadata.Title = testTitle, Xml = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>", Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName) }, new FeedMetadataTestCase { // specify an updated date via metadata CustomizeMetadata = metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated), Xml = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>", Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName) }, new FeedMetadataTestCase { // no author specified, the default author with empty name is written CustomizeMetadata = metadata => metadata.Authors = null, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new FeedMetadataTestCase { // specify an author via metadata CustomizeMetadata = metadata => metadata.Authors = testAuthors, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new FeedMetadataTestCase { // no author specified but some entries written, no author should be written CustomizeMetadata = metadata => metadata.Authors = null, CustomizePayload = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() }, Xml = "<authors />", Extractor = result => new XElement("authors", fragmentExtractor(TestAtomConstants.AtomAuthorElementName)(result)) }, new FeedMetadataTestCase { // specify an author via metadata and some entries (the author should be written anyway) CustomizeMetadata = metadata => metadata.Authors = testAuthors, CustomizePayload = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() }, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new FeedMetadataTestCase { // specify a category via metadata CustomizeMetadata = metadata => metadata.Categories = testCategories, Xml = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName) }, new FeedMetadataTestCase { // specify a contributor via metadata CustomizeMetadata = metadata => metadata.Contributors = testContributors, Xml = string.Join( "$(NL)", @"<contributor xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testContributorName + @"</name>", @" <uri>" + testContributorUri + @"</uri>", @" <email>" + testContributorEmail + @"</email>", @"</contributor>"), Extractor = fragmentExtractor(TestAtomConstants.AtomContributorElementName) }, new FeedMetadataTestCase { // specify a generator via metadata CustomizeMetadata = metadata => metadata.Generator = testGenerator, Xml = @"<generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testGeneratorName + @"</generator>", Extractor = fragmentExtractor(TestAtomConstants.AtomGeneratorElementName) }, new FeedMetadataTestCase { // specify a link via metadata CustomizeMetadata = metadata => metadata.Links = testLinks, Xml = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Single() }, new FeedMetadataTestCase { // no self link specified CustomizeMetadata = metadata => metadata.SelfLink = null, Xml = @"<selflink/>", Extractor = (e) => new XElement("selflink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue)) }, new FeedMetadataTestCase { // Some self link specified CustomizeMetadata = metadata => metadata.SelfLink = selfLink, Xml = @"<link rel=""" + TestAtomConstants.AtomSelfRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue) }, new FeedMetadataTestCase { // Non-self relation CustomizeMetadata = metadata => metadata.SelfLink = new AtomLinkMetadata { Relation = "SelF", Href = new Uri(testLinkHref) }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "self", "SelF"), }, new FeedMetadataTestCase { // no next link on either OM or metadata specified CustomizeMetadata = metadata => metadata.NextPageLink = null, Xml = @"<nextlink/>", Extractor = (e) => new XElement("nextlink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // the next link is only specified on metadata - nothing is written CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = "next", Href = new Uri(testLinkHref) }, Xml = @"<nextlink/>", Extractor = (e) => new XElement("nextlink", e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified only on the OM CustomizeMetadata = metadata => metadata.NextPageLink = null, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" href=""" + testLinkHref + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts cause values are identical CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = TestAtomConstants.AtomNextRelationAttributeValue, Href = new Uri(testLinkHref), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, Xml = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on relation CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Relation = "Next", Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "next", "Next"), SkipTestConfiguration = tc => tc.IsRequest }, new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on href CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata { Href = new Uri("http://odata.org/different"), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType }, CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); }, ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkHrefsMustMatch", testLinkHref, "http://odata.org/different"), SkipTestConfiguration = tc => tc.IsRequest }, }; this.CreateTestDescriptorsAndRunTests(testCases, WriterPayloads.FeedPayloads); }
/// <summary> /// Returns all interesting payloads for a feed. /// </summary> /// <param name="testDescriptor">The test descriptor which will end up writing a single feed.</param> /// <returns>Enumeration of test descriptors which will include the original feed in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > FeedPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { Debug.Assert(testDescriptor.PayloadItems[0] is ODataResourceSet, "The payload does not specify a feed."); var payloadCases = new WriterPayloadCase <ODataItem>[] { // Top-level feed with an entry that has an expanded link containing the feed new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultFeed(), ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName) .Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing the feed new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing a feed with a single entry; // that entry has another expanded link containing the payload feed new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), ObjectModelUtils.CreateDefaultFeed(), ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName) .Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
/// <summary> /// Returns all interesting payloads for a named stream. /// </summary> /// <param name="testDescriptor">Test descriptor which will end up writing a single entry with a single named stream. /// The entry is not going to be used, but the named stream from it will.</param> /// <returns>Enumeration of test descriptors which will include the original named stream in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > NamedStreamPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { ODataResource tempEntry = testDescriptor.PayloadItems[0] as ODataResource; Debug.Assert(tempEntry != null, "A single entry payload is expected."); ODataProperty namedStreamProperty = tempEntry.Properties.FirstOrDefault(p => p != null && p.Value is ODataStreamReferenceValue); // Note - the named stream can be null - it is a valid test case !!!! var payloadCases = new WriterPayloadCase <ODataItem>[] { new WriterPayloadCase <ODataItem>() // Single named stream on an entry { GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = "TestModel.EntityWithStreamProperty"; entry.Properties = new ODataProperty[] { namedStreamProperty }; return(new ODataItem[] { entry }); }, ModelBuilder = (model) => { model = model.Clone(); model.EntityType("EntityWithStreamProperty", "TestModel") .StreamProperty(namedStreamProperty.Name); return(model); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractNamedStreamLinksFromEntry(result, namedStreamProperty.Name)); }, JsonLightFragmentExtractor = (testConfiguration, result) => { return(new JsonObject().AddProperties(result.Object().GetPropertyAnnotationsAndProperty(namedStreamProperty.Name))); }, }, new WriterPayloadCase <ODataItem>() // Single named stream on an entry with other properties before/after it { GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = "TestModel.EntityWithStreamPropertyAndOtherProperties"; entry.Properties = new ODataProperty[] { new ODataProperty { Name = "Id", Value = 1 }, new ODataProperty { Name = "Name", Value = "Clemens" }, namedStreamProperty, new ODataProperty { Name = "Address", Value = new ODataComplexValue { TypeName = "TestModel.AddressType", Properties = new ODataProperty[] { new ODataProperty { Name = "Street", Value = "Am Euro Platz" }, new ODataProperty { Name = "City", Value = "Vienna" } } } } }; return(new ODataItem[] { entry }); }, ModelBuilder = (model) => { model = model.Clone(); var addressType = model.ComplexType("AddressType", "TestModel") .Property("Street", EdmPrimitiveTypeKind.String) .Property("City", EdmPrimitiveTypeKind.String); model.EntityType("EntityWithStreamPropertyAndOtherProperties", "TestModel") .KeyProperty("Id", (EdmTypeReference)EdmCoreModel.Instance.GetInt32(false)) .Property("Name", EdmPrimitiveTypeKind.String) .StreamProperty(namedStreamProperty.Name) .Property("Address", new EdmComplexTypeReference(addressType, false)); return(model); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractNamedStreamLinksFromEntry(result, namedStreamProperty.Name)); }, JsonLightFragmentExtractor = (testConfiguration, result) => { return(new JsonObject().AddProperties(result.Object().GetPropertyAnnotationsAndProperty(namedStreamProperty.Name))); }, }, new WriterPayloadCase <ODataItem>() // Multiple named stream properties on an entry { GetPayloadItems = () => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = "TestModel.EntityWithSeveralStreamProperties"; entry.Properties = new ODataProperty[] { new ODataProperty { Name = "Id", Value = 1 }, new ODataProperty { Name = "__Stream1", Value = new ODataStreamReferenceValue { ReadLink = new Uri("http://odata.org/stream1/readlink") } }, new ODataProperty { Name = "__Stream2", Value = new ODataStreamReferenceValue { EditLink = new Uri("http://odata.org/stream2/editlink") } }, namedStreamProperty, new ODataProperty { Name = "__Stream3", Value = new ODataStreamReferenceValue { ReadLink = new Uri("http://odata.org/stream3/readlink"), ContentType = "stream3:contenttype" } }, }; return(new ODataItem[] { entry }); }, ModelBuilder = (model) => { model = model.Clone(); model.EntityType("EntityWithSeveralStreamProperties", "TestModel") .KeyProperty("Id", (EdmTypeReference)EdmCoreModel.Instance.GetInt32(false)) .StreamProperty("__Stream1") .StreamProperty("__Stream2") .StreamProperty(namedStreamProperty.Name) .StreamProperty("__Stream3"); return(model); }, AtomFragmentExtractor = (testConfiguration, result) => { return(TestAtomUtils.ExtractNamedStreamLinksFromEntry(result, namedStreamProperty.Name)); }, JsonLightFragmentExtractor = (testConfiguration, result) => { return(new JsonObject().AddProperties(result.Object().GetPropertyAnnotationsAndProperty(namedStreamProperty.Name))); }, }, }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
public void ActionAndFunctionTest() { // <m:action Metadata=URI title?="title" target=URI /> Uri actionMetadata = new Uri("http://odata.org/test/$metadata#defaultAction"); Uri actionMetadata2 = new Uri("#action escaped relative metadata", UriKind.Relative); Uri actionMetadata3 = new Uri("../#action escaped relative metadata", UriKind.Relative); string actionTitle = "Default Action"; Uri actionTarget = new Uri("http://odata.org/defaultActionTarget"); Uri actionTarget2 = new Uri("http://odata.org/defaultActionTarget2"); ODataAction action_r1_t1 = new ODataAction() { Metadata = actionMetadata, Title = actionTitle, Target = actionTarget }; ODataAction action_r1_t2 = new ODataAction() { Metadata = actionMetadata, Title = actionTitle, Target = actionTarget2 }; ODataAction action_r2_t1 = new ODataAction() { Metadata = actionMetadata2, Title = actionTitle, Target = actionTarget }; ODataAction action_r3_t1 = new ODataAction() { Metadata = actionMetadata3, Title = actionTitle, Target = actionTarget }; Uri functionMetadata = new Uri("http://odata.org/test/$metadata#defaultFunction"); Uri functionMetadata2 = new Uri("#function escaped relative metadata", UriKind.Relative); Uri functionMetadata3 = new Uri("\\#function escaped relative metadata", UriKind.Relative); string functionTitle = "Default Function"; Uri functionTarget = new Uri("http://odata.org/defaultFunctionTarget"); Uri functionTarget2 = new Uri("http://odata.org/defaultFunctionTarget2"); ODataFunction function_r1_t1 = new ODataFunction() { Metadata = functionMetadata, Title = functionTitle, Target = functionTarget }; ODataFunction function_r1_t2 = new ODataFunction() { Metadata = functionMetadata, Title = functionTitle, Target = functionTarget2 }; ODataFunction function_r2_t1 = new ODataFunction() { Metadata = functionMetadata2, Title = functionTitle, Target = functionTarget }; ODataFunction function_r3_t1 = new ODataFunction() { Metadata = functionMetadata3, Title = functionTitle, Target = functionTarget }; var actionCases = new[] { new { ODataActions = new ODataAction[] { action_r1_t1 }, Atom = GetAtom(action_r1_t1), JsonLight = GetJsonLightForRelGroup(action_r1_t1), }, new { ODataActions = new ODataAction[] { action_r1_t1, action_r1_t2 }, Atom = GetAtom(action_r1_t1) + GetAtom(action_r1_t2), JsonLight = GetJsonLightForRelGroup(action_r1_t1, action_r1_t2), }, new { ODataActions = new ODataAction[] { action_r1_t1, action_r2_t1 }, Atom = GetAtom(action_r1_t1) + GetAtom(action_r2_t1), JsonLight = GetJsonLightForRelGroup(action_r1_t1) + "," + GetJsonLightForRelGroup(action_r2_t1), }, new { ODataActions = new ODataAction[] { action_r1_t1, action_r2_t1, action_r1_t2 }, Atom = GetAtom(action_r1_t1) + GetAtom(action_r2_t1) + GetAtom(action_r1_t2), JsonLight = GetJsonLightForRelGroup(action_r1_t1, action_r1_t2) + "," + GetJsonLightForRelGroup(action_r2_t1), }, new { ODataActions = new ODataAction[] { action_r3_t1 }, Atom = GetAtom(action_r3_t1), JsonLight = GetJsonLightForRelGroup(action_r3_t1), }, }; var functionCases = new[] { new { ODataFunctions = new ODataFunction[] { function_r1_t1 }, Atom = GetAtom(function_r1_t1), JsonLight = GetJsonLightForRelGroup(function_r1_t1), }, new { ODataFunctions = new ODataFunction[] { function_r1_t1, function_r1_t2 }, Atom = GetAtom(function_r1_t1) + GetAtom(function_r1_t2), JsonLight = GetJsonLightForRelGroup(function_r1_t1, function_r1_t2), }, new { ODataFunctions = new ODataFunction[] { function_r1_t1, function_r2_t1 }, Atom = GetAtom(function_r1_t1) + GetAtom(function_r2_t1), JsonLight = GetJsonLightForRelGroup(function_r1_t1) + "," + GetJsonLightForRelGroup(function_r2_t1), }, new { ODataFunctions = new ODataFunction[] { function_r1_t1, function_r2_t1, function_r1_t2 }, Atom = GetAtom(function_r1_t1) + GetAtom(function_r2_t1) + GetAtom(function_r1_t2), JsonLight = GetJsonLightForRelGroup(function_r1_t1, function_r1_t2) + "," + GetJsonLightForRelGroup(function_r2_t1), }, new { ODataFunctions = new ODataFunction[] { function_r3_t1 }, Atom = GetAtom(function_r3_t1), JsonLight = GetJsonLightForRelGroup(function_r3_t1), }, }; var queryResults = from actionCase in actionCases from functionCase in functionCases select new { actionCase.ODataActions, functionCase.ODataFunctions, Atom = string.Concat(actionCase.Atom, functionCase.Atom), JsonLight = string.Join(",", new[] { actionCase.JsonLight, functionCase.JsonLight }.Where(x => x != null)) }; EdmModel model = new EdmModel(); EdmEntityType edmEntityTypeCustomer = model.EntityType("Customer", "TestModel"); EdmEntityContainer edmEntityContainer = model.EntityContainer("DefaultContainer", "TestModel"); EdmEntitySet edmEntitySetCustermors = model.EntitySet("Customers", edmEntityTypeCustomer); var testDescriptors = queryResults.Select(testCase => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry("TestModel.Customer"); if (testCase.ODataActions != null) { foreach (var action in testCase.ODataActions) { entry.AddAction(action); } } if (testCase.ODataFunctions != null) { foreach (var function in testCase.ODataFunctions) { entry.AddFunction(function); } } return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, entry, (testConfiguration) => { if (testConfiguration.Format == ODataFormat.Json) { return new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = string.Join( "$(NL)", "{", testCase.JsonLight, "}"), ExpectedException2 = entry.Actions != null && entry.Actions.Contains(null) ? ODataExpectedExceptions.ODataException("ValidationUtils_EnumerableContainsANullItem", "ODataResource.Actions") : testConfiguration.IsRequest && entry.Actions != null && entry.Actions.Any() ? ODataExpectedExceptions.ODataException("WriterValidationUtils_OperationInRequest", GetFirstOperationMetadata(entry)) : entry.Actions != null && entry.Actions.Any(a => !a.Metadata.IsAbsoluteUri && !a.Metadata.OriginalString.StartsWith("#")) ? ODataExpectedExceptions.ODataException("ValidationUtils_InvalidMetadataReferenceProperty", entry.Actions.First(a => a.Metadata.OriginalString.Contains(" ")).Metadata.OriginalString) : entry.Functions != null && entry.Functions.Contains(null) ? ODataExpectedExceptions.ODataException("ValidationUtils_EnumerableContainsANullItem", "ODataResource.Functions") : testConfiguration.IsRequest && entry.Functions != null && entry.Functions.Any() ? ODataExpectedExceptions.ODataException("WriterValidationUtils_OperationInRequest", GetFirstOperationMetadata(entry)) : entry.Functions != null && entry.Functions.Any(f => !f.Metadata.IsAbsoluteUri && !f.Metadata.OriginalString.StartsWith("#")) ? ODataExpectedExceptions.ODataException("ValidationUtils_InvalidMetadataReferenceProperty", entry.Functions.First(f => f.Metadata.OriginalString.Contains(" ")).Metadata.OriginalString) : null, FragmentExtractor = (result) => { var actionsAndFunctions = result.Object().Properties.Where(p => p.Name.Contains("#")).ToList(); var jsonResult = new JsonObject(); actionsAndFunctions.ForEach(p => { // NOTE we remove all annotations here and in particular the text annotations to be able to easily compare // against the expected results. This however means that we do not distinguish between the indented and non-indented case here. p.RemoveAllAnnotations(true); jsonResult.Add(p); }); return jsonResult; } }; } else { string formatName = testConfiguration.Format == null ? "null" : testConfiguration.Format.GetType().Name; throw new NotSupportedException("Invalid format detected: " + formatName); } })); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); if (testConfiguration.Format == ODataFormat.Json) { if (testDescriptor.IsGeneratedPayload) { return; } // We need a model, entity set and entity type for JSON Light testDescriptor = new PayloadWriterTestDescriptor <ODataItem>(testDescriptor) { Model = model, PayloadEdmElementContainer = edmEntitySetCustermors, PayloadEdmElementType = edmEntityTypeCustomer, }; } TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void AssociationLinkMetadataValidationTest() { EdmModel model = new EdmModel(); var container = new EdmEntityContainer("TestModel", "Default"); model.AddElement(container); var edmEntityTypeOrderType = new EdmEntityType("TestModel", "OrderType"); model.AddElement(edmEntityTypeOrderType); var edmEntityTypeCustomerType = new EdmEntityType("TestModel", "CustomerType"); edmEntityTypeCustomerType.AddKeys(new EdmStructuralProperty(edmEntityTypeCustomerType, "ID", EdmCoreModel.Instance.GetInt32(false))); edmEntityTypeCustomerType.AddStructuralProperty("PrimitiveProperty", EdmCoreModel.Instance.GetString(true)); var edmNavigationPropertyAssociationLinkOne = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "Orders", Target = edmEntityTypeOrderType, TargetMultiplicity = EdmMultiplicity.Many }); var edmNavigationPropertyAssociationLinkTwo = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = "BestFriend", Target = edmEntityTypeCustomerType, TargetMultiplicity = EdmMultiplicity.One }); model.AddElement(edmEntityTypeCustomerType); var edmEntityTypeOpenCustomerType = new EdmEntityType("TestModel", "OpenCustomerType", edmEntityTypeCustomerType, isAbstract: false, isOpen: true); model.AddElement(edmEntityTypeOpenCustomerType); var customerSet = container.AddEntitySet("Customers", edmEntityTypeCustomerType); var orderSet = container.AddEntitySet("Orders", edmEntityTypeOrderType); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkOne, orderSet); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkTwo, customerSet); Uri associationLinkUrl = new Uri("http://odata.org/associationlink"); var testCases = new[] { // Valid collection new { TypeName = "TestModel.CustomerType", NavigationLink = ObjectModelUtils.CreateDefaultCollectionLink("Orders"), ExpectedException = (ExpectedException)null, }, // Valid singleton new { TypeName = "TestModel.CustomerType", NavigationLink = ObjectModelUtils.CreateDefaultSingletonLink("BestFriend"), ExpectedException = (ExpectedException)null, }, // Undeclared on closed type new { TypeName = "TestModel.CustomerType", NavigationLink = ObjectModelUtils.CreateDefaultCollectionLink("NonExistant"), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", "NonExistant", "TestModel.CustomerType"), }, // Undeclared on open type new { TypeName = "TestModel.OpenCustomerType", NavigationLink = ObjectModelUtils.CreateDefaultCollectionLink("NonExistant"), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_OpenNavigationProperty", "NonExistant", "TestModel.OpenCustomerType"), }, // Declared but of wrong kind new { TypeName = "TestModel.CustomerType", NavigationLink = ObjectModelUtils.CreateDefaultSingletonLink("PrimitiveProperty"), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_NavigationPropertyExpected", "PrimitiveProperty", "TestModel.CustomerType", "Structural"), }, }; var testDescriptors = testCases.Select(testCase => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = testCase.TypeName; ODataNestedResourceInfo navigationLink = testCase.NavigationLink; navigationLink.AssociationLinkUrl = associationLinkUrl; return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { entry, navigationLink }, tc => (WriterTestExpectedResults) new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException }) { Model = model, PayloadEdmElementContainer = customerSet }); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.AtomFormatConfigurations .Where(testConfiguration => !testConfiguration.IsRequest), (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void AssociationLinkTest() { string associationLinkName1 = "AssociationLinkOne"; string linkUrl1 = "http://odata.org/associationlink"; Uri linkUrlUri1 = new Uri(linkUrl1); string associationLinkName2 = "AssociationLinkTwo"; string linkUrl2 = "http://odata.org/associationlink2"; Uri linkUrlUri2 = new Uri(linkUrl2); EdmModel model = new EdmModel(); var edmEntityTypeOrderType = new EdmEntityType("TestModel", "OrderType"); model.AddElement(edmEntityTypeOrderType); var edmEntityTypeCustomerType = new EdmEntityType("TestModel", "CustomerType"); var edmNavigationPropertyAssociationLinkOne = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = associationLinkName1, Target = edmEntityTypeOrderType, TargetMultiplicity = EdmMultiplicity.One }); var edmNavigationPropertyAssociationLinkTwo = edmEntityTypeCustomerType.AddUnidirectionalNavigation( new EdmNavigationPropertyInfo { Name = associationLinkName2, Target = edmEntityTypeOrderType, TargetMultiplicity = EdmMultiplicity.Many }); model.AddElement(edmEntityTypeCustomerType); var container = new EdmEntityContainer("TestModel", "Default"); model.AddElement(container); var customerSet = container.AddEntitySet("Customers", edmEntityTypeCustomerType); var orderSet = container.AddEntitySet("Orders", edmEntityTypeOrderType); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkOne, orderSet); customerSet.AddNavigationTarget(edmNavigationPropertyAssociationLinkTwo, orderSet); var testCases = new[] { new { NavigationLink = ObjectModelUtils.CreateDefaultNavigationLink(associationLinkName1, linkUrlUri1), Atom = BuildXmlAssociationLink(associationLinkName1, "application/xml", linkUrl1), JsonLight = (string)null, }, new { NavigationLink = ObjectModelUtils.CreateDefaultNavigationLink(associationLinkName2, linkUrlUri2), Atom = BuildXmlAssociationLink(associationLinkName2, "application/xml", linkUrl2), JsonLight = (string)null }, }; var testCasesWithMultipleLinks = testCases.Variations() .Select(tcs => new { NavigationLinks = tcs.Select(tc => tc.NavigationLink), Atom = string.Concat(tcs.Select(tc => tc.Atom)), JsonLight = string.Join(",", tcs.Where(tc => tc.JsonLight != null).Select(tc => tc.JsonLight)) }); var testDescriptors = testCasesWithMultipleLinks.Select(testCase => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.TypeName = "TestModel.CustomerType"; List <ODataItem> items = new ODataItem[] { entry }.ToList(); foreach (var navLink in testCase.NavigationLinks) { items.Add(navLink); items.Add(null); } return(new PayloadWriterTestDescriptor <ODataItem>( this.Settings, items, (testConfiguration) => { var firstAssocLink = testCase.NavigationLinks == null ? null : testCase.NavigationLinks.FirstOrDefault(); if (testConfiguration.Format == ODataFormat.Json) { return new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = string.Join( "$(NL)", "{", testCase.JsonLight, "}"), FragmentExtractor = (result) => { var associationLinks = result.Object().GetAnnotationsWithName("@" + JsonLightConstants.ODataAssociationLinkUrlAnnotationName).ToList(); var jsonResult = new JsonObject(); associationLinks.ForEach(l => { // NOTE we remove all annoatations here and in particular the text annotations to be able to easily compare // against the expected results. This however means that we do not distinguish between the indented and non-indented case here. l.RemoveAllAnnotations(true); jsonResult.Add(l); }); return jsonResult; }, }; } else { this.Settings.Assert.Fail("Unknown format '{0}'.", testConfiguration.Format); return null; } }) { Model = model, PayloadEdmElementContainer = customerSet }); }); // With and without model testDescriptors = testDescriptors.SelectMany(td => new[] { td, new PayloadWriterTestDescriptor <ODataItem>(td) { Model = null, PayloadEdmElementContainer = null } }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); if (testDescriptor.Model == null && testConfiguration.Format == ODataFormat.Json) { return; } if (testDescriptor.IsGeneratedPayload && testDescriptor.Model != null) { return; } TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
/// <summary> /// Returns all interesting payloads for an entry. /// </summary> /// <param name="testDescriptor">The test descriptor which will end up writing a single entry.</param> /// <returns>Enumeration of test descriptors which will include the original entry in some interesting scenarios.</returns> public static IEnumerable <PayloadWriterTestDescriptor <ODataItem> > EntryPayloads(PayloadWriterTestDescriptor <ODataItem> testDescriptor) { Debug.Assert(testDescriptor.PayloadItems[0] is ODataResource, "The payload does not specify an entry."); var payloadCases = new WriterPayloadCase <ODataItem>[] { // Feed with a single entry new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultFeed() }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName).First()); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Feed with three (identical) entries, picking the second one new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultFeed() } .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)) .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)) .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)), AtomFragmentExtractor = (testConfiguration, result) => { var entries = result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName); Debug.Assert(entries.Count() == 3, "Expected three entries in the feed."); return(entries.ElementAt(2)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing a single entry new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultSingletonLink(), }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing a feed with a single entry new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), ObjectModelUtils.CreateDefaultFeed() }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing a feed with three entries; picking the second one new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), ObjectModelUtils.CreateDefaultFeed() } .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)) .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)) .Concat(testDescriptor.PayloadItems) .Concat(LinqExtensions.FromSingle((ODataItem)null)), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName) .Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName) .ElementAt(2)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, // Top-level entry with an expanded link containing a feed with a single entry; // that entry has another expanded link containing a feed with the payload entry new WriterPayloadCase <ODataItem>() { GetPayloadItems = () => new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), ObjectModelUtils.CreateDefaultFeed(), ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultCollectionLink(), ObjectModelUtils.CreateDefaultFeed(), }.Concat(testDescriptor.PayloadItems), AtomFragmentExtractor = (testConfiguration, result) => { return(result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName) .Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomFeedElementName) .Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName)); }, //ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight }, }; return(ApplyPayloadCases <ODataItem>(testDescriptor, payloadCases)); }
public void EntryMetadataWriterTest() { const string testPublished = "2010-10-20T20:10:00Z"; AtomTextConstruct testRights = new AtomTextConstruct { Text = "Copyright Data Fx team." }; AtomTextConstruct testSummary = new AtomTextConstruct { Text = "Test summary." }; AtomTextConstruct testTitle = new AtomTextConstruct { Text = "Test title" }; const string testUpdated = "2010-11-01T00:04:00Z"; const string testIcon = "http://odata.org/icon"; const string testSourceId = "http://odata.org/id/random"; const string testLogo = "http://odata.org/logo"; AtomTextConstruct testSubtitle = new AtomTextConstruct { Text = "Test subtitle." }; const string testAuthorName = "Test Author 1"; const string testAuthorEmail = "*****@*****.**"; const string testAuthorUri = "http://odata.org/authors/1"; var testAuthors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testAuthorEmail, Name = testAuthorName, Uri = new Uri(testAuthorUri) } }; var testAuthors2 = new AtomPersonMetadata[0]; const string testCategoryTerm = "Test category 1 term"; const string testCategoryLabel = "Test category 1 label"; const string testCategoryScheme = "http://odata.org/categories/1"; var testCategories = new AtomCategoryMetadata[] { new AtomCategoryMetadata() { Term = testCategoryTerm, Label = testCategoryLabel, Scheme = testCategoryScheme } }; const string testContributorName = "Test Contributor 1"; const string testContributorEmail = "*****@*****.**"; const string testContributorUri = "http://odata.org/contributors/1"; var testContributors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testContributorEmail, Name = testContributorName, Uri = new Uri(testContributorUri) } }; const string testGeneratorName = "Test generator"; const string testGeneratorUri = "http://odata.org/generator"; const string testGeneratorVersion = "3.0"; var testGenerator = new AtomGeneratorMetadata() { Name = testGeneratorName, Uri = new Uri(testGeneratorUri), Version = testGeneratorVersion }; const string testLinkRelation = "http://odata.org/links/1"; const string testLinkTitle = "Test link 1"; const string testLinkHref = "http://odata.org/links/1"; const string testLinkHrefLang = "de-AT"; int? testLinkLength = 999; const string testLinkMediaType = "image/png"; var testLinks = new AtomLinkMetadata[] { new AtomLinkMetadata() { Relation = testLinkRelation, Title = testLinkTitle, Href = new Uri(testLinkHref), HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType } }; AtomFeedMetadata testSource = new AtomFeedMetadata() { Authors = testAuthors, Categories = testCategories, Contributors = testContributors, Generator = testGenerator, Icon = new Uri(testIcon), SourceId = new Uri(testSourceId), Links = testLinks, Logo = new Uri(testLogo), Rights = testRights, Subtitle = testSubtitle, Title = testTitle, Updated = DateTimeOffset.Parse(testUpdated) }; Func <string, Func <XElement, XElement> > fragmentExtractor = (localName) => (e) => e.Element(TestAtomConstants.AtomXNamespace + localName); // TODO, ckerer: specify an Id via metadata if the entry does not specify one; we first have to decide what rules // we want to apply to merging of metadata and ODataLib OM data. var testCases = new[] { new { // specify an author via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify an empty author array via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors2), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify no authors via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = null), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @"$(Indent)<name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify a category via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Categories = testCategories), Xml = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName) }, new { // specify a contributor via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Contributors = testContributors), Xml = string.Join( "$(NL)", @"<contributor xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testContributorName + @"</name>", @" <uri>" + testContributorUri + @"</uri>", @" <email>" + testContributorEmail + @"</email>", @"</contributor>"), Extractor = fragmentExtractor(TestAtomConstants.AtomContributorElementName) }, new { // specify a link via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Links = testLinks), Xml = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = new Func <XElement, XElement>( (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Where(l => l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value != TestAtomConstants.AtomSelfRelationAttributeValue) .Single()) }, new { // specify a published date via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Published = DateTimeOffset.Parse(testPublished)), Xml = @"<published xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testPublished + @"</published>", Extractor = fragmentExtractor(TestAtomConstants.AtomPublishedElementName) }, new { // specify rights via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Rights = testRights), Xml = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>", Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName) }, new { // specify a source via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = testSource), Xml = string.Join( "$(NL)", @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <id>" + testSourceId + "</id>", @" <title type=""text"">" + testTitle.Text + @"</title>", @" <subtitle type=""text"">" + testSubtitle.Text + @"</subtitle>", @" <updated>" + testUpdated + @"</updated>", @" <link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""/>", @" <category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" />", @" <logo>" + testLogo + @"</logo>", @" <rights type=""text"">" + testRights.Text + @"</rights>", @" <contributor>", @" <name>" + testContributorName + @"</name>", @" <uri>" + testContributorUri + @"</uri>", @" <email>" + testContributorEmail + @"</email>", @" </contributor>", @" <generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""">" + testGeneratorName + @"</generator>", @" <icon>" + testIcon + @"</icon>", @" <author>", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @" </author>", @"</source>"), Extractor = fragmentExtractor(TestAtomConstants.AtomSourceElementName) }, new { // specify default feed metadata as source CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = new AtomFeedMetadata()), Xml = string.Join( "$(NL)", @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <id />", @" <title />", @" <updated />", @"</source>"), Extractor = new Func <XElement, XElement>(result => { var source = fragmentExtractor(TestAtomConstants.AtomSourceElementName)(result); // Remove the value of updates as it can't be reliably predicted source.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomUpdatedElementName).Nodes().Remove(); return(source); }) }, new { // specify a summary via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Summary = testSummary), Xml = @"<summary type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSummary.Text + @"</summary>", Extractor = fragmentExtractor(TestAtomConstants.AtomSummaryElementName) }, new { // specify a title via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Title = testTitle), Xml = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>", Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName) }, new { // specify an updated date via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated)), Xml = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>", Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName) }, }; // Convert test cases to test descriptions IEnumerable <Func <ODataEntry> > entryCreators = new Func <ODataEntry>[] { () => ObjectModelUtils.CreateDefaultEntry(), () => ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(), }; var testDescriptors = testCases.SelectMany(testCase => entryCreators.Select(entryCreator => { ODataEntry entry = entryCreator(); AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); testCase.CustomizeMetadata(metadata); return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, FragmentExtractor = testCase.Extractor })); })); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void ExpandedLinkWithNullNavigationTests() { ODataNavigationLink expandedEntryLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink.IsCollection = false; ODataNavigationLink expandedEntryLink2 = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink2.IsCollection = false; expandedEntryLink2.Name = expandedEntryLink2.Name + "2"; ODataEntry defaultEntry = ObjectModelUtils.CreateDefaultEntry(); ODataFeed defaultFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntry nullEntry = ObjectModelUtils.ODataNullEntry; PayloadWriterTestDescriptor.WriterTestExpectedResultCallback successCallback = (testConfiguration) => { if (testConfiguration.Format == ODataFormat.Atom) { return(new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName).ToString(), FragmentExtractor = (result) => { return result.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .First(e => e.Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName) != null) .Element(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInlineElementName); } }); } else { return(new JsonWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Json = "null", //new JsonPrimitiveValue(null).ToText(testConfiguration.MessageWriterSettings.Indent), FragmentExtractor = (result) => { return JsonUtils.UnwrapTopLevelValue(testConfiguration, result).Object().Properties.First(p => p.Name == ObjectModelUtils.DefaultLinkName).Value; } }); } }; Func <ExpectedException, PayloadWriterTestDescriptor.WriterTestExpectedResultCallback> errorCallback = (expectedException) => { return((testConfiguration) => { return new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = expectedException, }; }); }; var testCases = new PayloadWriterTestDescriptor <ODataItem>[] { // navigation to a null entry new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry }, successCallback), // navigation to a null entry twice new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry, null, null, expandedEntryLink2, nullEntry, null }, successCallback), // top level null entry. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), // navigation to a null entry twice in expanded link // this actually throws ArgumentNullException when WriteStart() for the second nullEntry is called since // the state has been changed from NavigationLink to ExpandedLink after the first one. // TODO: check if ArgumentNullException needs to change the WriterState. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultEntry, expandedEntryLink, nullEntry, null, nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), // Null entry inside a feed, same as above this throws ArgumentNullException but state is not put to error state. new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { defaultFeed, nullEntry }, errorCallback(new ExpectedException(typeof(ArgumentNullException)))), }; // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testCases, this.WriterTestConfigurationProvider.ExplicitFormatConfigurationsWithIndent.Where(tc => tc.Format == ODataFormat.Atom), (testCase, testConfig) => { testConfig = testConfig.Clone(); testConfig.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testCase, testConfig, this.Assert, this.Logger); }); }
public void EntityReferenceLinkValidationTest() { var testCases = new[] { new { InvalidateEntityReferenceLink = new Action <ODataEntityReferenceLink>(entityReferenceLink => entityReferenceLink.Url = null), ExpectedException = ODataExpectedExceptions.ODataException("WriterValidationUtils_EntityReferenceLinkUrlMustNotBeNull"), }, }; var testDescriptors = testCases.SelectMany(testCase => { ODataEntityReferenceLink entityReferenceLink = ObjectModelUtils.CreateDefaultEntityReferenceLink(); testCase.InvalidateEntityReferenceLink(entityReferenceLink); ODataEntityReferenceLinks entityReferenceLinks = ObjectModelUtils.CreateDefaultEntityReferenceLinks(); testCase.InvalidateEntityReferenceLink(entityReferenceLinks.Links.First()); return(new PayloadWriterTestDescriptor[] { // Top level entity reference link new PayloadWriterTestDescriptor <ODataEntityReferenceLink>( this.Settings, entityReferenceLink, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testCase.ExpectedException }), // Entity reference link in entity reference links new PayloadWriterTestDescriptor <ODataEntityReferenceLinks>( this.Settings, entityReferenceLinks, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { // Top-level EntityReferenceLinks payload write requests are not allowed. ExpectedException2 = testConfiguration.IsRequest ? ODataExpectedExceptions.ODataException("ODataMessageWriter_EntityReferenceLinksInRequestNotAllowed") : testCase.ExpectedException }), new PayloadWriterTestDescriptor <ODataItem>( this.Settings, new ODataItem[] { ObjectModelUtils.CreateDefaultEntry(), ObjectModelUtils.CreateDefaultSingletonLink(), entityReferenceLink, null, null }, testConfiguration => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = testConfiguration.IsRequest ? testCase.ExpectedException : ODataExpectedExceptions.ODataException("ODataWriterCore_EntityReferenceLinkInResponse") }), }); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); PayloadWriterTestDescriptor <ODataEntityReferenceLink> entityReferenceLinkTestDescriptor = testDescriptor as PayloadWriterTestDescriptor <ODataEntityReferenceLink>; if (entityReferenceLinkTestDescriptor != null) { TestWriterUtils.WriteAndVerifyTopLevelContent( entityReferenceLinkTestDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLink(entityReferenceLinkTestDescriptor.PayloadItems.Single()), this.Assert, baselineLogger: this.Logger); return; } PayloadWriterTestDescriptor <ODataEntityReferenceLinks> entityReferenceLinksTestDescriptor = testDescriptor as PayloadWriterTestDescriptor <ODataEntityReferenceLinks>; if (entityReferenceLinksTestDescriptor != null) { TestWriterUtils.WriteAndVerifyTopLevelContent( entityReferenceLinksTestDescriptor, testConfiguration, (messageWriter) => messageWriter.WriteEntityReferenceLinks(entityReferenceLinksTestDescriptor.PayloadItems.Single()), this.Assert, baselineLogger: this.Logger); return; } TestWriterUtils.WriteAndVerifyODataPayload((PayloadWriterTestDescriptor <ODataItem>)testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void ExpandedLinkWithMultiplicityTests() { ODataNavigationLink expandedEntryLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedEntryLink.IsCollection = false; ODataNavigationLink expandedFeedLink = ObjectModelUtils.CreateDefaultCollectionLink(); expandedFeedLink.IsCollection = true; ODataEntry defaultEntry = ObjectModelUtils.CreateDefaultEntry(); ODataFeed defaultFeed = ObjectModelUtils.CreateDefaultFeed(); ODataEntityReferenceLink defaultEntityReferenceLink = ObjectModelUtils.CreateDefaultEntityReferenceLink(); ODataEntry officeEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeType"); ODataEntry officeWithNumberEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeWithNumberType"); ODataEntry cityEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.CityType"); // CityHall is a nav prop with multiplicity '*' of type 'TestModel.OfficeType' ODataNavigationLink cityHallLinkIsCollectionNull = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ null); ODataNavigationLink cityHallLinkIsCollectionTrue = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ true); ODataNavigationLink cityHallLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ false); // PoliceStation is a nav prop with multiplicity '1' of type 'TestModel.OfficeType' ODataNavigationLink policeStationLinkIsCollectionNull = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ null); ODataNavigationLink policeStationLinkIsCollectionTrue = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ true); ODataNavigationLink policeStationLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ false); ExpectedException expandedEntryLinkWithFeedContentError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedContent", "http://odata.org/link"); ExpectedException expandedFeedLinkWithEntryContentError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryContent", "http://odata.org/link"); ExpectedException expandedFeedLinkWithEntryMetadataError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkWithFeedMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata", "http://odata.org/link"); ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorRequest = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithFeedPayloadAndEntryMetadata", "http://odata.org/link"); ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithEntryMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkPayloadWithFeedMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithFeedMetadata", "http://odata.org/link"); ExpectedException expandedEntryLinkPayloadWithFeedMetadataError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithEntryPayloadAndFeedMetadata", "http://odata.org/link"); ExpectedException multipleItemsInExpandedLinkError = ODataExpectedExceptions.ODataException("ODataWriterCore_MultipleItemsInNavigationLinkContent", "http://odata.org/link"); ExpectedException entityReferenceLinkInResponseError = ODataExpectedExceptions.ODataException("ODataWriterCore_EntityReferenceLinkInResponse"); IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel(); var testCases = new ExpandedLinkMultiplicityTestCase[] { #region IsCollection flag does not match payload new ExpandedLinkMultiplicityTestCase { // Expanded link with IsCollection is 'false' and feed payload Items = new ODataItem[] { defaultEntry, expandedEntryLink, defaultFeed }, ExpectedError = tc => expandedEntryLinkWithFeedContentError, }, new ExpandedLinkMultiplicityTestCase { // Expanded link with IsCollection is 'true' and entry payload Items = new ODataItem[] { defaultEntry, expandedFeedLink, defaultEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, }, #endregion IsCollection flag does not match payload #region IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection value and an entry of a non-matching entity type; Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, cityEntry }, ExpectedError = tc => tc.Format == ODataFormat.Atom || !tc.IsRequest ? ODataExpectedExceptions.ODataException("WriterValidationUtils_EntryTypeInExpandedLinkNotCompatibleWithNavigationPropertyType", "TestModel.CityType", "TestModel.OfficeType") : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection value and an entry of a matching entity type; no error expected. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of singleton type without IsCollection and an entry of a derived entity type; no error expected. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeWithNumberEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection value and an entry of a non-matching entity type; Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, cityEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? ODataExpectedExceptions.ODataException("WriterValidationUtils_EntryTypeInExpandedLinkNotCompatibleWithNavigationPropertyType", "TestModel.CityType", "TestModel.OfficeType") : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection value and an entry of a matching entity type; no error expected. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, new ExpandedLinkMultiplicityTestCase { // Expanded link of collection type without IsCollection and an entry of a derived entity type; no error expected. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeWithNumberEntry }, ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall"), Model = model, }, #endregion IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link #region Expanded link with entry content new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, officeEntry }, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, officeEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedEntryLinkPayloadWithFeedMetadataError : expandedEntryLinkPayloadWithFeedMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == true, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, officeEntry }, ExpectedError = tc => expandedFeedLinkWithEntryContentError, Model = model }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == null, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry }, ExpectedError = tc => tc.IsRequest || tc.Format == ODataFormat.Atom ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "PoliceStation") : null, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Entry content, IsCollection == null, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, officeEntry }, ExpectedError = tc => expandedEntryLinkPayloadWithFeedMetadataError, Model = model, }, #endregion Expanded collection link with entry content #region Expanded link with feed content new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == false, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultFeed, officeEntry }, ExpectedError = tc => expandedEntryLinkWithFeedContentError, }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedFeedLinkPayloadWithEntryMetadataErrorRequest : expandedFeedLinkPayloadWithEntryMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest ? expandedEntryLinkWithFeedContentError : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultFeed, officeEntry }, Model = model }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == null, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => expandedFeedLinkPayloadWithEntryMetadataErrorRequest, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Feed content, IsCollection == null, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry }, ExpectedError = tc => tc.IsRequest || tc.Format == ODataFormat.Atom ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NavigationLinkMustSpecifyIsCollection", "CityHall") : null, Model = model, }, #endregion Expanded collection link with entry content #region Expanded link with entity reference link content new ExpandedLinkMultiplicityTestCase { // Single ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : entityReferenceLinkInResponseError, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink }, ExpectedError = tc => expandedFeedLinkWithEntryMetadataError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == true, singleton nav prop; should fail. Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => expandedFeedLinkWithEntryMetadataError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == false, collection nav prop; should not fail (metadata mismatch explicitly allowed). Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == false, collection nav prop; should fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : expandedEntryLinkWithFeedMetadataErrorResponse, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Single ERL content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError, Model = model, }, new ExpandedLinkMultiplicityTestCase { // Multiple ERL content, IsCollection == true, collection nav prop; should not fail. Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink }, ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError, Model = model, }, //// NOTE: Not testing the cases where IsCollection == null here since ERL payloads are only allowed in //// requests where IsCollection is required (in ATOM and JSON) #endregion Expanded link with entity reference link content }; // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight this.CombinatorialEngineProvider.RunCombinations( testCases, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => tc.Format == ODataFormat.Atom), (testCase, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); using (var memoryStream = new TestStream()) using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert, null, testCase.Model)) { ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false); TestExceptionUtils.ExpectedException( this.Assert, () => TestWriterUtils.WritePayload(messageWriter, writer, true, testCase.Items), testCase.ExpectedError == null ? null : testCase.ExpectedError(testConfiguration), this.ExceptionVerifier); } }); }
public void BaseUriErrorTest() { Uri baseUri = new Uri("http://odata.org"); Uri testUri = new Uri("http://odata.org/relative"); IEnumerable <Func <Uri, BaseUriErrorTestCase> > testCaseFuncs = new Func <Uri, BaseUriErrorTestCase>[] { relativeUri => new BaseUriErrorTestCase { // next page link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); feed.NextPageLink = relativeUri; return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // entry read link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.ReadLink = relativeUri; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // entry edit link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.EditLink = relativeUri; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // media resource (default stream) read link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataStreamReferenceValue mediaResource = new ODataStreamReferenceValue(); mediaResource.ContentType = "image/jpg"; mediaResource.ReadLink = relativeUri; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.MediaResource = mediaResource; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // media resource (default stream) edit link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataStreamReferenceValue mediaResource = new ODataStreamReferenceValue(); mediaResource.ContentType = "image/jpg"; // required mediaResource.ReadLink = testUri; // required mediaResource.EditLink = relativeUri; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); entry.MediaResource = mediaResource; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // link Url ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataNestedResourceInfo link = ObjectModelUtils.CreateDefaultCollectionLink(); link.Url = relativeUri; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); return(new ODataItem[] { entry, link }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // association link Url ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataNestedResourceInfo link = ObjectModelUtils.CreateDefaultSingletonLink(); link.AssociationLinkUrl = relativeUri; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); return(new ODataItem[] { entry, link }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // named stream read link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataStreamReferenceValue namedStream = new ODataStreamReferenceValue() { ContentType = "image/jpg", ReadLink = relativeUri, }; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); ODataProperty property = new ODataProperty() { Name = "NamedStream", Value = namedStream }; entry.Properties = new[] { property }; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // named stream edit link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataStreamReferenceValue namedStream = new ODataStreamReferenceValue() { ContentType = "image/jpg", ReadLink = testUri, EditLink = relativeUri }; ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); ODataProperty property = new ODataProperty() { Name = "NamedStream", Value = namedStream }; entry.Properties = new[] { property }; return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed generator Uri ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed logo ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed icon ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed author ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed contributor ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResourceSet feed = ObjectModelUtils.CreateDefaultFeed(); return(new [] { feed }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry author ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry contributor ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry link ItemFunc = new Func <IEnumerable <ODataItem> >(() => { ODataResource entry = ObjectModelUtils.CreateDefaultEntry(); return(new [] { entry }); }), Formats = new [] { ODataFormat.Json } }, }; // ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight Uri testRelativeUri = baseUri.MakeRelativeUri(testUri); Uri invalidRelativeUri = new Uri("../invalid/relative/uri", UriKind.Relative); this.CombinatorialEngineProvider.RunCombinations( testCaseFuncs, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(c => false), new Uri[] { testRelativeUri, invalidRelativeUri }, new bool[] { false, true }, (testCaseFunc, testConfiguration, uri, implementUrlResolver) => { var testCase = testCaseFunc(uri); var testDescriptor = new { Descriptor = new PayloadWriterTestDescriptor <ODataItem>( this.Settings, testCase.ItemFunc(), testConfig => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = ODataExpectedExceptions.ODataException("ODataWriter_RelativeUriUsedWithoutBaseUriSpecified", uri.OriginalString) }), Formats = testCase.Formats }; if (testDescriptor.Formats.Contains(testConfiguration.Format)) { PayloadWriterTestDescriptor <ODataItem> payloadTestDescriptor = testDescriptor.Descriptor; TestUrlResolver urlResolver = null; if (implementUrlResolver) { payloadTestDescriptor = new PayloadWriterTestDescriptor <ODataItem>(payloadTestDescriptor); urlResolver = new TestUrlResolver(); payloadTestDescriptor.UrlResolver = urlResolver; } testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(payloadTestDescriptor, testConfiguration, this.Assert, this.Logger); if (implementUrlResolver) { this.Assert.AreEqual(1, urlResolver.Calls.Where(call => call.Value.OriginalString == uri.OriginalString).Count(), "The resolver should be called exactly once for each URL."); } } }); }
public void FeedAndEntryUpdatedTimeTests() { ODataFeed defaultFeedWithEmptyMetadata = ObjectModelUtils.CreateDefaultFeed(); defaultFeedWithEmptyMetadata.SetAnnotation <AtomFeedMetadata>(new AtomFeedMetadata()); ODataEntry defaultEntryWithEmptyMetadata = ObjectModelUtils.CreateDefaultEntry(); defaultEntryWithEmptyMetadata.SetAnnotation <AtomEntryMetadata>(new AtomEntryMetadata()); IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testPayloads = new[] { new PayloadWriterTestDescriptor <ODataItem>(this.Settings, ObjectModelUtils.CreateDefaultFeed()), new PayloadWriterTestDescriptor <ODataItem>(this.Settings, defaultFeedWithEmptyMetadata), new PayloadWriterTestDescriptor <ODataItem>(this.Settings, ObjectModelUtils.CreateDefaultFeedWithAtomMetadata()), }.PayloadCases(WriterPayloads.FeedPayloads) .Concat((new[] { new PayloadWriterTestDescriptor <ODataItem>(this.Settings, ObjectModelUtils.CreateDefaultEntry()), new PayloadWriterTestDescriptor <ODataItem>(this.Settings, defaultEntryWithEmptyMetadata), new PayloadWriterTestDescriptor <ODataItem>(this.Settings, ObjectModelUtils.CreateDefaultEntryWithAtomMetadata()), }.PayloadCases(WriterPayloads.EntryPayloads))); this.CombinatorialEngineProvider.RunCombinations( testPayloads, this.WriterTestConfigurationProvider.AtomFormatConfigurationsWithIndent.Where(tc => !tc.IsRequest), (testPayload, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); string lastUpdatedTimeStr = null; using (var memoryStream = new MemoryStream()) { using (var testMemoryStream = TestWriterUtils.CreateTestStream(testConfiguration, memoryStream, ignoreDispose: true)) { bool feedWriter = testPayload.PayloadItems[0] is ODataFeed; TestMessage testMessage = null; Exception exception = TestExceptionUtils.RunCatching(() => { using (var messageWriter = TestWriterUtils.CreateMessageWriter(testMemoryStream, testConfiguration, this.Assert, out testMessage, null, testPayload.Model)) { ODataWriter writer = messageWriter.CreateODataWriter(feedWriter); TestWriterUtils.WritePayload(messageWriter, writer, true, testPayload.PayloadItems, testPayload.ThrowUserExceptionAt); } }); this.Assert.IsNull(exception, "Received exception but expected none."); } memoryStream.Position = 0; XElement result = XElement.Load(memoryStream); foreach (XElement updated in result.Descendants(((XNamespace)TestAtomConstants.AtomNamespace) + "updated")) { if (updated.Value != ObjectModelUtils.DefaultFeedUpdated && updated.Value != ObjectModelUtils.DefaultEntryUpdated) { if (lastUpdatedTimeStr == null) { lastUpdatedTimeStr = updated.Value; } else { this.Assert.AreEqual(lastUpdatedTimeStr, updated.Value, "<atom:updated> should contain the same value."); } } } } }); }