public void GetContent_CachesRemoteSourcesInFiles()
        {
            // Arrange
            // Arbitrary permalink
            const string                url            = "https://raw.githubusercontent.com/JeringTech/Markdig.Extensions.FlexiBlocks/6998b1c27821d8393ad39beb54f782515c39d98b/test/FlexiBlocks.Tests/exampleInclude.md";
            var                         dummyUri       = new Uri(url);
            IContentRetrieverService    testSubject    = _serviceProvider.GetRequiredService <IContentRetrieverService>();
            ReadOnlyCollection <string> expectedResult = testSubject.GetContent(dummyUri, _fixture.TempDirectory);

            ((IDisposable)_serviceProvider).Dispose(); // Avoid retrieving from in-memory cache

            Mock <IHttpClientService> mockHttpClientService = _mockRepository.Create <IHttpClientService>();
            var services = new ServiceCollection();

            services.AddFlexiBlocks();
            services.AddSingleton(mockHttpClientService.Object);
            _serviceProvider = services.BuildServiceProvider();
            testSubject      = _serviceProvider.GetRequiredService <IContentRetrieverService>();

            // Act
            ReadOnlyCollection <string> result = testSubject.GetContent(dummyUri, _fixture.TempDirectory);

            // Assert
            Assert.Equal(expectedResult, result);
            mockHttpClientService.Verify(h => h.GetAsync(It.IsAny <Uri>(), HttpCompletionOption.ResponseHeadersRead, default), Times.Never);
        }
        public void GetContent_CachesSourcesInMemory()
        {
            // Arrange
            const string dummySource = "this\nis\na\ndummy\nsource";
            var          dummyUri    = new Uri(_dummyFile);

            using (FileStream fileStream = File.Open(_dummyFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                byte[] bytes = Encoding.UTF8.GetBytes(dummySource);
                fileStream.Write(bytes, 0, bytes.Length);
            }
            IContentRetrieverService testSubject = _serviceProvider.GetRequiredService <IContentRetrieverService>();

            // Act
            var threads = new List <Thread>();
            var results = new ConcurrentBag <ReadOnlyCollection <string> >();

            for (int i = 0; i < 3; i++)
            {
                var thread = new Thread(() => results.Add(testSubject.GetContent(dummyUri)));
                thread.Start();
                threads.Add(thread);
            }
            foreach (Thread thread in threads)
            {
                thread.Join();
            }

            // Assert
            ReadOnlyCollection <string>[] resultsArr = results.ToArray();
            Assert.Equal(3, resultsArr.Length);
            Assert.Equal(dummySource.Split('\n'), resultsArr[0]);
            Assert.Same(resultsArr[0], resultsArr[1]); // Result should get cached after first call
            Assert.Same(resultsArr[1], resultsArr[2]); // The same relation is transitive, so we do not need to check if the item at index 0 is the same as the item at index 2
        }
Beispiel #3
0
        internal virtual void ProcessFlexiIncludeBlock(FlexiIncludeBlock flexiIncludeBlock, ProxyJsonBlock proxyJsonBlock, BlockProcessor blockProcessor)
        {
            // If the FlexiIncludeBlock's type is markdown, we need to ensure we don't have a cycle of includes.
            bool isMarkdown = flexiIncludeBlock.Type == FlexiIncludeType.Markdown;
            Stack <FlexiIncludeBlock> closingFlexiIncludeBlocks = null;

            if (isMarkdown)
            {
                closingFlexiIncludeBlocks = GetOrCreateClosingFlexiIncludeBlocks(blockProcessor);
                CheckForCycle(closingFlexiIncludeBlocks, flexiIncludeBlock);
                closingFlexiIncludeBlocks.Push(flexiIncludeBlock);
            }

            // Retrieve source
            ReadOnlyCollection <string> content = _contentRetrieverService.GetContent(flexiIncludeBlock.Source, flexiIncludeBlock.CacheDirectory);

            // Parent of new blocks
            ContainerBlock parentOfNewBlocks = proxyJsonBlock.Parent;

            parentOfNewBlocks.Remove(proxyJsonBlock);

            try
            {
                // Convert content into blocks and add them to parentOfNewBlocks
                ProcessContent(blockProcessor, flexiIncludeBlock, parentOfNewBlocks, content);
            }
            catch (Exception exception)
            {
                // FlexiIncludeBlocks can reference sources other than the entry markdown document. If an exception is thrown while processing content from such sources,
                // we must provide context. Specifically, we must specify which source and where within the source the unrecoverable situation was encountered.
                throw new BlockException(flexiIncludeBlock,
                                         string.Format(Strings.BlockException_FlexiIncludeBlockFactory_ExceptionOccurredWhileProcessingContent, flexiIncludeBlock.Source.AbsoluteUri),
                                         exception);
            }

            // Remove FlexiIncludeBlock from stack used to check for cycles
            if (isMarkdown)
            {
                closingFlexiIncludeBlocks.Pop();
            }

            // Add to trees if FlexiIncludeBlock is a root block
            TryAddToFlexiIncludeBlockTrees(flexiIncludeBlock, blockProcessor);
        }