コード例 #1
0
            public void DoesNotRenderLinkIfNoImage()
            {
                // Given
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>("Link", "/c/d"),
                    new KeyValuePair <string, string>("Target", "abc"),
                    new KeyValuePair <string, string>("Rel", "def"),
                    new KeyValuePair <string, string>("Alt", "ghi"),
                    new KeyValuePair <string, string>("Class", "jkl"),
                    new KeyValuePair <string, string>("Height", "100px"),
                    new KeyValuePair <string, string>("Width", "200px")
                };
                Figure shortcode = new Figure();

                // When
                IShortcodeResult result = shortcode.Execute(args, "foo bar", document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(
                        @"<figure class=""jkl"">
  <figcaption>foo bar</figcaption>
</figure>",
                        StringCompareShould.IgnoreLineEndings);
                }
            }
コード例 #2
0
            public void RendersLinkWithAlternateHost(string path, string expected)
            {
                // Given
                TestExecutionContext context = new TestExecutionContext();

                context.AddTypeConversion <string, FilePath>(x => new FilePath(x));
                context.AddTypeConversion <string, bool>(x => bool.Parse(x));
                context.Settings[Keys.Host] = "domain.com";
                TestDocument document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>("Path", path),
                    new KeyValuePair <string, string>("Host", "google.com")
                };
                Link shortcode = new Link();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(expected);
                }
            }
コード例 #3
0
            public void RendersFigureWithoutLink()
            {
                // Given
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>("Src", "/a/b"),
                    new KeyValuePair <string, string>("Alt", "ghi"),
                    new KeyValuePair <string, string>("Class", "jkl"),
                    new KeyValuePair <string, string>("Height", "100px"),
                    new KeyValuePair <string, string>("Width", "200px")
                };
                Figure shortcode = new Figure();

                // When
                IShortcodeResult result = shortcode.Execute(args, "foo bar", document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(
                        @"<figure class=""jkl"">
  <img src=""/a/b"" alt=""ghi"" height=""100px"" width=""200px"" />
  <figcaption>foo bar</figcaption>
</figure>",
                        StringCompareShould.IgnoreLineEndings);
                }
            }
コード例 #4
0
            public void RendersTableWithoutSettings()
            {
                // Given
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument();
                string content = @"
1 2 ""3 4""
a ""b c"" d
e f g
5 678
""h i""  j ""k""
l=m nop
";

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[] { };
                Table shortcode = new Table();

                // When
                IShortcodeResult result = shortcode.Execute(args, content, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(
                        @"<table>
  <tbody>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3 4</td>
    </tr>
    <tr>
      <td>a</td>
      <td>b c</td>
      <td>d</td>
    </tr>
    <tr>
      <td>e</td>
      <td>f</td>
      <td>g</td>
    </tr>
    <tr>
      <td>5</td>
      <td>678</td>
    </tr>
    <tr>
      <td>h i</td>
      <td>j</td>
      <td>k</td>
    </tr>
    <tr>
      <td>l=m</td>
      <td>nop</td>
    </tr>
  </tbody>
</table>",
                        StringCompareShould.IgnoreLineEndings);
                }
            }
コード例 #5
0
            public void IncludesFileRelativeToSource()
            {
                // Given
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddDirectory("/A/D");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };
                TestDocument document = new TestDocument()
                {
                    Source = new FilePath("/A/D/x.txt")
                };

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "../B/c.txt")
                };
                Include shortcode = new Include();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe("foo");
                }
            }
コード例 #6
0
            public void NullStreamForMissingMetadata()
            {
                // Given
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument(new MetadataItems
                {
                    { "Foo", "Bar" }
                });

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "Fizz")
                };
                Core.Shortcodes.Metadata.Meta shortcode = new Core.Shortcodes.Metadata.Meta();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                result.Stream.ShouldBeNull();
            }
コード例 #7
0
            public void RendersGistWithoutFile()
            {
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "abc"),
                    new KeyValuePair <string, string>(null, "def")
                };
                Gist shortcode = new Gist();

                // When
                IShortcodeResult result = shortcode.Execute(args, null, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(
                        "<script src=\"//gist.github.com/def/abc.js\" type=\"text/javascript\"></script>");
                }
            }
コード例 #8
0
            public void RendersMetadata()
            {
                // Given
                TestExecutionContext context  = new TestExecutionContext();
                TestDocument         document = new TestDocument(new MetadataItems
                {
                    { "Foo", "Bar" }
                });

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "Foo")
                };
                Core.Shortcodes.Metadata.Meta shortcode = new Core.Shortcodes.Metadata.Meta();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe("Bar");
                }
            }
コード例 #9
0
            public void NullResultIfFileDoesNotExist()
            {
                // Given
                ThrowOnTraceEventType(System.Diagnostics.TraceEventType.Error);
                TestFileProvider fileProvider = new TestFileProvider();

                fileProvider.AddDirectory("/");
                fileProvider.AddDirectory("/A");
                fileProvider.AddDirectory("/A/B");
                fileProvider.AddFile("/A/B/c.txt", "foo");
                TestFileSystem fileSystem = new TestFileSystem
                {
                    FileProvider = fileProvider
                };

                fileSystem.InputPaths.Clear();
                fileSystem.InputPaths.Add("/A");

                TestExecutionContext context = new TestExecutionContext
                {
                    FileSystem = fileSystem
                };
                TestDocument document = new TestDocument();

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>(null, "B/d.txt")
                };
                Include shortcode = new Include();

                // When
                IShortcodeResult result = shortcode.Execute(args, string.Empty, document, context);

                // Then
                result.Stream.ShouldBeNull();
            }
コード例 #10
0
        // The inputStream will be disposed if this returns <c>true</c> but will not otherwise
        private bool ProcessShortcodes(Stream inputStream, IDocument input, IExecutionContext context, out IDocument result)
        {
            // Parse the input stream looking for shortcodes
            ShortcodeParser parser = new ShortcodeParser(_startDelimiter, _endDelimiter, context.Shortcodes);

            if (!inputStream.CanSeek)
            {
                inputStream = new SeekableStream(inputStream, true);
            }
            List <ShortcodeLocation> locations = parser.Parse(inputStream);

            // Reset the position because we're going to use the stream again when we do replacements
            inputStream.Position = 0;

            // Return the original document if we didn't find any
            if (locations.Count == 0)
            {
                result = null;
                return(false);
            }

            // Otherwise, create a shortcode instance for each named shortcode
            Dictionary <string, IShortcode> shortcodes =
                locations
                .Select(x => x.Name)
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToDictionary(x => x, x => context.Shortcodes.CreateInstance(x), StringComparer.OrdinalIgnoreCase);

            // Execute each of the shortcodes in order
            List <InsertingStreamLocation> insertingLocations = locations
                                                                .Select(x =>
            {
                // Execute the shortcode
                IShortcodeResult shortcodeResult = shortcodes[x.Name].Execute(x.Arguments, x.Content, input, context);

                // Merge output metadata with the current input document
                // Creating a new document is the easiest way to ensure all the metadata from shortcodes gets accumulated correctly
                if (shortcodeResult?.Metadata != null)
                {
                    input = context.GetDocument(input, shortcodeResult.Metadata);
                }

                // Recursively parse shortcodes
                Stream shortcodeResultStream = shortcodeResult?.Stream;
                if (shortcodeResultStream != null)
                {
                    // Don't process nested shortcodes if it's the raw shortcode
                    if (!x.Name.Equals(nameof(Core.Shortcodes.Contents.Raw), StringComparison.OrdinalIgnoreCase))
                    {
                        if (!shortcodeResultStream.CanSeek)
                        {
                            shortcodeResultStream = new SeekableStream(shortcodeResultStream, true);
                        }
                        if (ProcessShortcodes(shortcodeResultStream, input, context, out IDocument nestedResult))
                        {
                            input = nestedResult;
                            shortcodeResultStream = nestedResult.GetStream();      // Will get disposed in the replacement operation below
                        }
                        else
                        {
                            shortcodeResultStream.Position = 0;
                        }
                    }
                    return(new InsertingStreamLocation(x.FirstIndex, x.LastIndex, shortcodeResultStream));
                }

                return(new InsertingStreamLocation(x.FirstIndex, x.LastIndex, null));
            })
                                                                .ToList();

            // Dispose any shortcodes that implement IDisposable
            foreach (IDisposable disposableShortcode
                     in shortcodes.Values.Select(x => x as IDisposable).Where(x => x != null))
            {
                disposableShortcode.Dispose();
            }

            // Construct a new stream with the shortcode results inserted
            // We have to use all TextWriter/TextReaders over the streams to ensure consistent encoding
            Stream resultStream = context.GetContentStream();

            char[] buffer = new char[4096];
            using (TextWriter writer = new StreamWriter(resultStream, Encoding.UTF8, 4096, true))
            {
                // The input stream will get disposed when the reader is
                using (TextReader reader = new StreamReader(inputStream))
                {
                    int position = 0;
                    int length   = 0;
                    foreach (InsertingStreamLocation insertingLocation in insertingLocations)
                    {
                        // Copy up to the start of this shortcode
                        length = insertingLocation.FirstIndex - position;
                        Read(reader, writer, length, ref buffer);
                        position += length;

                        // Copy the shortcode content to the result stream
                        if (insertingLocation.Stream != null)
                        {
                            // This will dispose the shortcode content stream when done
                            using (TextReader insertingReader = new StreamReader(insertingLocation.Stream))
                            {
                                Read(insertingReader, writer, null, ref buffer);
                            }
                        }

                        // Skip the shortcode text
                        length = insertingLocation.LastIndex - insertingLocation.FirstIndex + 1;
                        Read(reader, null, length, ref buffer);
                        position += length;
                    }

                    // Copy remaining
                    Read(reader, writer, null, ref buffer);
                }
            }
            result = context.GetDocument(input, resultStream);
            return(true);
        }
コード例 #11
0
            public void RendersTableWithSettings()
            {
                // Given
                TestExecutionContext context = new TestExecutionContext();

                context.AddTypeConversion <string, int>(x => int.Parse(x));
                TestDocument document = new TestDocument();
                string       content  = @"
1 2 ""3 4""
a ""b c"" d
e f g
5 678
""h i""  j ""k""
l=m nop
";

                KeyValuePair <string, string>[] args = new KeyValuePair <string, string>[]
                {
                    new KeyValuePair <string, string>("Class", "tclass"),
                    new KeyValuePair <string, string>("HeaderRows", "1"),
                    new KeyValuePair <string, string>("FooterRows", "2"),
                    new KeyValuePair <string, string>("HeaderCols", "1"),
                    new KeyValuePair <string, string>("HeaderClass", "hclass"),
                    new KeyValuePair <string, string>("BodyClass", "bclass"),
                    new KeyValuePair <string, string>("FooterClass", "fclass")
                };
                Table shortcode = new Table();

                // When
                IShortcodeResult result = shortcode.Execute(args, content, document, context);

                // Then
                using (TextReader reader = new StreamReader(result.Stream))
                {
                    reader.ReadToEnd().ShouldBe(
                        @"<table class=""tclass"">
  <thead class=""hclass"">
    <tr>
      <th>1</th>
      <th>2</th>
      <th>3 4</th>
    </tr>
  </thead>
  <tbody class=""bclass"">
    <tr>
      <th>a</th>
      <td>b c</td>
      <td>d</td>
    </tr>
    <tr>
      <th>e</th>
      <td>f</td>
      <td>g</td>
    </tr>
    <tr>
      <th>5</th>
      <td>678</td>
    </tr>
  </tbody>
  <tfoot class=""fclass"">
    <tr>
      <th>h i</th>
      <td>j</td>
      <td>k</td>
    </tr>
    <tr>
      <th>l=m</th>
      <td>nop</td>
    </tr>
  </tfoot>
</table>",
                        StringCompareShould.IgnoreLineEndings);
                }
            }