public void BuildPropertyExtractorCollectionGivesPrecedenceToSchemaExtractorsOverPipelineExtractors()
        {
            // has to be called before ContextPropertyAnnotationMockInjectionScope overrides SchemaMetadata.For<>() factory method
            var schemaMetadata = SchemaMetadata.For <Any>();

            using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes("<root xmlns='urn:ns'></root>")))
                using (var contextPropertyAnnotationMockInjectionScope = new PropertyExtractorAnnotationMockInjectionScope())
                {
                    contextPropertyAnnotationMockInjectionScope.Extractors = new(
                        new XPathExtractor(BizTalkFactoryProperties.OutboundTransportLocation.QName, "/letter/*/to", ExtractionMode.Demote),
                        new XPathExtractor(BtsProperties.Operation.QName, "/letter/*/salutations"));

                    PipelineContextMock.Setup(pc => pc.GetDocumentSpecByType("urn:ns#root")).Returns(schemaMetadata.DocumentSpec);
                    MessageMock.Object.BodyPart.Data = inputStream;
                    MessageMock.Setup(m => m.GetProperty(BtsProperties.MessageType)).Returns("urn:ns#root");

                    var sut = new ContextPropertyExtractor {
                        Extractors = new[] {
                            new XPathExtractor(BizTalkFactoryProperties.OutboundTransportLocation.QName, "/letter/*/from", ExtractionMode.Promote),
                            new XPathExtractor(BtsProperties.OutboundTransportLocation.QName, "/letter/*/paragraph")
                        }
                    };
                    var extractors = sut.BuildPropertyExtractorCollection(PipelineContextMock.Object, MessageMock.Object);

                    extractors.Should().BeEquivalentTo(
                        new[] {
                        new XPathExtractor(BizTalkFactoryProperties.OutboundTransportLocation.QName, "/letter/*/to", ExtractionMode.Demote),
                        new XPathExtractor(BtsProperties.Operation.QName, "/letter/*/salutations"),
                        new XPathExtractor(BtsProperties.OutboundTransportLocation.QName, "/letter/*/paragraph")
                    });
                }
        }
        public void MessageContextManipulationsAreDelegatedToPropertyExtractors()
        {
            const string content = "<s1:letter xmlns:s1=\"urn-one\">"
                                   + "<s1:headers><s1:subject>inquiry</s1:subject></s1:headers>"
                                   + "<s1:body>"
                                   + "<s1:paragraph>paragraph-one</s1:paragraph>"
                                   + "<s1:footer>trail</s1:footer>"
                                   + "</s1:body>" +
                                   "</s1:letter>";

            using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
                using (var contextPropertyAnnotationMockInjectionScope = new PropertyExtractorAnnotationMockInjectionScope())
                {
                    var propertyExtractorMock = new Mock <PropertyExtractor>(BizTalkFactoryProperties.OutboundTransportLocation.QName, ExtractionMode.Clear)
                    {
                        CallBase = true
                    };
                    var constantExtractorMock = new Mock <ConstantExtractor>(BtsProperties.OutboundTransportLocation.QName, "OutboundTransportLocation", ExtractionMode.Write)
                    {
                        CallBase = true
                    };
                    var xpathExtractorMock = new Mock <XPathExtractor>(BtsProperties.Operation.QName, "/*[local-name()='letter']/*/*[local-name()='paragraph']", ExtractionMode.Write)
                    {
                        CallBase = true
                    };

                    contextPropertyAnnotationMockInjectionScope.Extractors = new(
                        propertyExtractorMock.Object,
                        constantExtractorMock.Object
                        );

                    MessageMock.Object.BodyPart.Data = inputStream;
                    MessageMock.Setup(m => m.GetProperty(BtsProperties.MessageType)).Returns("urn-one#letter");

                    var sut = new ContextPropertyExtractor {
                        Extractors = new[] {
                            new XPathExtractor(SBMessagingProperties.Label.QName, "/*[local-name()='letter']/*/*[local-name()='subject']", ExtractionMode.Promote),
                            xpathExtractorMock.Object,
                            new XPathExtractor(BizTalkFactoryProperties.MapTypeName.QName, "/*[local-name()='letter']/*/*[local-name()='footer']")
                        }
                    };
                    sut.Execute(PipelineContextMock.Object, MessageMock.Object);
                    MessageMock.Object.BodyPart.Data.Drain();

                    propertyExtractorMock.Verify(pe => pe.Execute(MessageMock.Object.Context));
                    constantExtractorMock.Verify(pe => pe.Execute(MessageMock.Object.Context));
                    xpathExtractorMock.Verify(pe => pe.Execute(MessageMock.Object.Context, "paragraph-one", ref It.Ref <string> .IsAny));

                    MessageMock.Verify(m => m.SetProperty(BizTalkFactoryProperties.OutboundTransportLocation, null));
                    MessageMock.Verify(m => m.SetProperty(BtsProperties.Operation, "paragraph-one"));
                    MessageMock.Verify(m => m.SetProperty(BtsProperties.OutboundTransportLocation, "OutboundTransportLocation"));
                    MessageMock.Verify(m => m.SetProperty(BizTalkFactoryProperties.MapTypeName, "trail"));
                    MessageMock.Verify(m => m.Promote(SBMessagingProperties.Label, "inquiry"));
                }
        }