diff --git a/test/helper.rb b/test/helper.rb index 7b1a2b4b..3ec9d75c 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -262,3 +262,35 @@ module TestWEBrick ) end end + +class TagUnitTest < JekyllUnitTest + def render_content(content, override = {}) + base_config = { + "source" => source_dir, + "destination" => dest_dir, + } + site = fixture_site(base_config.merge(override)) + + if override["read_posts"] + site.posts.docs.concat(PostReader.new(site).read_posts("")) + elsif override["read_collections"] + CollectionReader.new(site).read + elsif override["read_all"] + site.read + end + + @result = render_with(site, content) + end + + private + + def render_with(site, content) + converter = site.converters.find { |c| c.instance_of?(Jekyll::Converters::Markdown) } + payload = { "highlighter_prefix" => converter.highlighter_prefix, + "highlighter_suffix" => converter.highlighter_suffix, } + info = { :registers => { :site => site } } + converter.convert( + Liquid::Template.parse(content).render!(payload, info) + ) + end +end diff --git a/test/test_tag_highlight.rb b/test/test_tag_highlight.rb new file mode 100644 index 00000000..14a3bdee --- /dev/null +++ b/test/test_tag_highlight.rb @@ -0,0 +1,302 @@ +# frozen_string_literal: true + +require "helper" + +class TestTagHighlight < TagUnitTest + def render_content_with_text_to_highlight(code) + content = <<~CONTENT + --- + title: This is a test + --- + + This document has some highlighted code in it. + + {% highlight text %} + #{code} + {% endhighlight %} + + {% highlight text linenos %} + #{code} + {% endhighlight %} + CONTENT + render_content(content) + end + + # Syntax sugar for low-level version of: + # ``` + # {% highlight markup%}test{% endhighlight %} + # ``` + def highlight_block_with_markup(markup) + Jekyll::Tags::HighlightBlock.parse( + "highlight", + markup, + Liquid::Tokenizer.new("test{% endhighlight %}\n"), + Liquid::ParseContext.new + ) + end + + context "language name" do + should "match only the required set of chars" do + r = Jekyll::Tags::HighlightBlock::SYNTAX + [ + "ruby", + "c#", + "xml+cheetah", + "x.y", + "coffee-script", + "shell_session", + "ruby key=val", + "ruby a=b c=d", + ].each { |sample| assert_match(r, sample) } + + refute_match r, "blah^" + end + end + + context "highlight tag in unsafe mode" do + should "set the no options with just a language name" do + tag = highlight_block_with_markup("ruby ") + assert_equal({}, tag.instance_variable_get(:@highlight_options)) + end + + should "set the linenos option as 'inline' if no linenos value" do + tag = highlight_block_with_markup("ruby linenos ") + assert_equal( + { :linenos => "inline" }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "set the linenos option to 'table' " \ + "if the linenos key is given the table value" do + tag = highlight_block_with_markup("ruby linenos=table ") + assert_equal( + { :linenos => "table" }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "recognize nowrap option with linenos set" do + tag = highlight_block_with_markup("ruby linenos=table nowrap ") + assert_equal( + { :linenos => "table", :nowrap => true }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "recognize the cssclass option" do + tag = highlight_block_with_markup("ruby linenos=table cssclass=hl ") + assert_equal( + { :cssclass => "hl", :linenos => "table" }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "recognize the hl_linenos option and its value" do + tag = highlight_block_with_markup("ruby linenos=table cssclass=hl hl_linenos=3 ") + assert_equal( + { :cssclass => "hl", :linenos => "table", :hl_linenos => "3" }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "recognize multiple values of hl_linenos" do + tag = highlight_block_with_markup 'ruby linenos=table cssclass=hl hl_linenos="3 5 6" ' + assert_equal( + { :cssclass => "hl", :linenos => "table", :hl_linenos => %w(3 5 6) }, + tag.instance_variable_get(:@highlight_options) + ) + end + + should "treat language name as case insensitive" do + tag = highlight_block_with_markup("Ruby ") + assert_equal "ruby", tag.instance_variable_get(:@lang), "lexers should be case insensitive" + end + end + + context "with the rouge highlighter" do + context "post content has highlight tag" do + setup do + render_content_with_text_to_highlight "test" + end + + should "render markdown with rouge" do + assert_match( + %(
test
), + @result + ) + end + + should "render markdown with rouge with line numbers" do + assert_match( + %() + + %() + + %() + + %(
) + + %(
1\n
test\n
), + @result + ) + end + end + + context "post content has highlight with file reference" do + setup do + render_content_with_text_to_highlight "./jekyll.gemspec" + end + + should "not embed the file" do + assert_match( + '
' \
+          "./jekyll.gemspec
", + @result + ) + end + end + + context "post content has highlight tag with UTF character" do + setup do + render_content_with_text_to_highlight "Æ" + end + + should "render markdown with pygments line handling" do + assert_match( + '
Æ
', + @result + ) + end + end + + context "post content has highlight tag with preceding spaces & lines" do + setup do + render_content_with_text_to_highlight <<~EOS + + + [,1] [,2] + [1,] FALSE TRUE + [2,] FALSE TRUE + EOS + end + + should "only strip the preceding newlines" do + assert_match( + '
     [,1] [,2]',
+          @result
+        )
+      end
+    end
+
+    context "post content has highlight tag with preceding spaces & lines in several places" do
+      setup do
+        render_content_with_text_to_highlight <<~EOS
+
+
+               [,1] [,2]
+
+
+          [1,] FALSE TRUE
+          [2,] FALSE TRUE
+
+
+        EOS
+      end
+
+      should "only strip the newlines which precede and succeed the entire block" do
+        assert_match(
+          "
     [,1] [,2]\n\n\n" \
+          "[1,] FALSE TRUE\n[2,] FALSE TRUE
", + @result + ) + end + end + + context "post content has highlight tag with linenumbers" do + setup do + render_content <<~EOS + --- + title: This is a test + --- + + This is not yet highlighted + {% highlight php linenos %} + test + {% endhighlight %} + + This should not be highlighted, right? + EOS + end + + should "should stop highlighting at boundary with rouge" do + expected = <<~EOS +

This is not yet highlighted

+ +
1
+          
test
+          
+ +

This should not be highlighted, right?

+ EOS + assert_match(expected, @result) + end + end + + context "post content has highlight tag with " \ + "preceding spaces & Windows-style newlines" do + setup do + render_content_with_text_to_highlight "\r\n\r\n\r\n [,1] [,2]" + end + + should "only strip the preceding newlines" do + assert_match( + '
     [,1] [,2]',
+          @result
+        )
+      end
+    end
+
+    context "post content has highlight tag with only preceding spaces" do
+      setup do
+        render_content_with_text_to_highlight <<~EOS
+               [,1] [,2]
+          [1,] FALSE TRUE
+          [2,] FALSE TRUE
+        EOS
+      end
+
+      should "only strip the preceding newlines" do
+        assert_match(
+          '
     [,1] [,2]',
+          @result
+        )
+      end
+    end
+  end
+
+  context "simple post with markdown and pre tags" do
+    setup do
+      @content = <<~CONTENT
+        ---
+        title: Kramdown post with pre
+        ---
+
+        _FIGHT!_
+
+        {% highlight ruby %}
+        puts "3..2..1.."
+        {% endhighlight %}
+
+        *FINISH HIM*
+      CONTENT
+    end
+
+    context "using Kramdown" do
+      setup do
+        render_content(@content, "markdown" => "kramdown")
+      end
+
+      should "parse correctly" do
+        assert_match %r{FIGHT!}, @result
+        assert_match %r!FINISH HIM!, @result
+      end
+    end
+  end
+end
diff --git a/test/test_tag_include.rb b/test/test_tag_include.rb
new file mode 100644
index 00000000..59fbb17f
--- /dev/null
+++ b/test/test_tag_include.rb
@@ -0,0 +1,310 @@
+# frozen_string_literal: true
+
+require "helper"
+
+class TestTagInclude < TagUnitTest
+  context "include tag with parameters" do
+    context "with symlink'd include" do
+      should "not allow symlink includes" do
+        FileUtils.mkdir_p("tmp")
+        File.write("tmp/pages-test", "SYMLINK TEST")
+        assert_raises IOError do
+          content = <<~CONTENT
+            ---
+            title: Include symlink
+            ---
+
+            {% include tmp/pages-test %}
+
+          CONTENT
+          render_content(content, "safe" => true)
+        end
+        @result ||= ""
+        refute_match(%r!SYMLINK TEST!, @result)
+      end
+
+      should "not expose the existence of symlinked files" do
+        ex = assert_raises IOError do
+          content = <<~CONTENT
+            ---
+            title: Include symlink
+            ---
+
+            {% include tmp/pages-test-does-not-exist %}
+
+          CONTENT
+          render_content(content, "safe" => true)
+        end
+        assert_match(
+          "Could not locate the included file 'tmp/pages-test-does-not-exist' in any of " \
+          "[\"#{source_dir}/_includes\"]. Ensure it exists in one of those directories and is " \
+          "not a symlink as those are not allowed in safe mode.",
+          ex.message
+        )
+      end
+    end
+
+    context "with one parameter" do
+      setup do
+        content = <<~CONTENT
+          ---
+          title: Include tag parameters
+          ---
+
+          {% include sig.markdown myparam="test" %}
+
+          {% include params.html param="value" %}
+        CONTENT
+        render_content(content)
+      end
+
+      should "correctly output include variable" do
+        assert_match "value", @result.strip
+      end
+
+      should "ignore parameters if unused" do
+        assert_match "
\n

Tom Preston-Werner\ngithub.com/mojombo

\n", @result + end + end + + context "with simple syntax but multiline markup" do + setup do + content = <<~CONTENT + --- + title: Include tag parameters + --- + + {% include sig.markdown myparam="test" %} + + {% include params.html + param="value" %} + CONTENT + render_content(content) + end + + should "correctly output include variable" do + assert_match "value", @result.strip + end + + should "ignore parameters if unused" do + assert_match "
\n

Tom Preston-Werner\ngithub.com/mojombo

\n", @result + end + end + + context "with variable syntax but multiline markup" do + setup do + content = <<~CONTENT + --- + title: Include tag parameters + --- + + {% include sig.markdown myparam="test" %} + {% assign path = "params" | append: ".html" %} + {% include {{ path }} + param="value" %} + CONTENT + render_content(content) + end + + should "correctly output include variable" do + assert_match "value", @result.strip + end + + should "ignore parameters if unused" do + assert_match "
\n

Tom Preston-Werner\ngithub.com/mojombo

\n", @result + end + end + + context "with invalid parameter syntax" do + should "throw a ArgumentError" do + content = <<~CONTENT + --- + title: Invalid parameter syntax + --- + + {% include params.html param s="value" %} + CONTENT + assert_raises ArgumentError, %(Did not raise exception on invalid "include" syntax) do + render_content(content) + end + + content = <<~CONTENT + --- + title: Invalid parameter syntax + --- + + {% include params.html params="value %} + CONTENT + assert_raises ArgumentError, %(Did not raise exception on invalid "include" syntax) do + render_content(content) + end + end + end + + context "with several parameters" do + setup do + content = <<~CONTENT + --- + title: multiple include parameters + --- + + {% include params.html param1="new_value" param2="another" %} + CONTENT + render_content(content) + end + + should "list all parameters" do + assert_match "
  • param1 = new_value
  • ", @result + assert_match "
  • param2 = another
  • ", @result + end + + should "not include previously used parameters" do + assert_match "", @result + end + end + + context "without parameters" do + setup do + content = <<~CONTENT + --- + title: without parameters + --- + + {% include params.html %} + CONTENT + render_content(content) + end + + should "include file with empty parameters" do + assert_match "", @result + end + end + + context "with include file with special characters without params" do + setup do + content = <<~CONTENT + --- + title: special characters + --- + + {% include params@2.0.html %} + CONTENT + render_content(content) + end + + should "include file with empty parameters" do + assert_match "", @result + end + end + + context "with include file with special characters with params" do + setup do + content = <<~CONTENT + --- + title: special characters + --- + + {% include params@2.0.html param1="foobar" param2="bazbar" %} + CONTENT + render_content(content) + end + + should "include file with empty parameters" do + assert_match "
  • param1 = foobar
  • ", @result + assert_match "
  • param2 = bazbar
  • ", @result + end + end + + context "with custom includes directory" do + setup do + content = <<~CONTENT + --- + title: custom includes directory + --- + + {% include custom.html %} + CONTENT + + render_content(content, "includes_dir" => "_includes_custom") + end + + should "include file from custom directory" do + assert_match "custom_included", @result + end + end + + context "without parameters within if statement" do + setup do + content = <<~CONTENT + --- + title: without parameters within if statement + --- + + {% if true %}{% include params.html %}{% endif %} + CONTENT + render_content(content) + end + + should "include file with empty parameters within if statement" do + assert_match "", @result + end + end + + context "include missing file" do + setup do + @content = <<~CONTENT + --- + title: missing file + --- + + {% include missing.html %} + CONTENT + end + + should "raise error relative to source directory" do + exception = assert_raises IOError do + render_content(@content) + end + assert_match( + "Could not locate the included file 'missing.html' in any of " \ + "[\"#{source_dir}/_includes\"].", + exception.message + ) + end + end + + context "include tag with variable and liquid filters" do + setup do + site = fixture_site.tap do |s| + s.read + s.render + end + post = site.posts.docs.find do |p| + p.basename.eql? "2013-12-17-include-variable-filters.markdown" + end + @content = post.output + end + + should "include file as variable with liquid filters" do + assert_match(%r!1 included!, @content) + assert_match(%r!2 included!, @content) + assert_match(%r!3 included!, @content) + end + + should "include file as variable and liquid filters with arbitrary whitespace" do + assert_match(%r!4 included!, @content) + assert_match(%r!5 included!, @content) + assert_match(%r!6 included!, @content) + end + + should "include file as variable and filters with additional parameters" do + assert_match("
  • var1 = foo
  • ", @content) + assert_match("
  • var2 = bar
  • ", @content) + end + + should "include file as partial variable" do + assert_match(%r!8 included!, @content) + end + end + end +end diff --git a/test/test_tag_include_relative.rb b/test/test_tag_include_relative.rb new file mode 100644 index 00000000..a378c418 --- /dev/null +++ b/test/test_tag_include_relative.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require "helper" + +class TestTagIncludeRelative < TagUnitTest + context "include_relative tag with variable and liquid filters" do + setup do + site = fixture_site.tap do |s| + s.read + s.render + end + + post = site.posts.docs.find do |p| + p.basename.eql? "2014-09-02-relative-includes.markdown" + end + + @content = post.output + end + + should "include file as variable with liquid filters" do + assert_match(%r!1 relative_include!, @content) + assert_match(%r!2 relative_include!, @content) + assert_match(%r!3 relative_include!, @content) + end + + should "include file as variable and liquid filters with arbitrary whitespace" do + assert_match(%r!4 relative_include!, @content) + assert_match(%r!5 relative_include!, @content) + assert_match(%r!6 relative_include!, @content) + end + + should "include file as variable and filters with additional parameters" do + assert_match("
  • var1 = foo
  • ", @content) + assert_match("
  • var2 = bar
  • ", @content) + end + + should "include file as partial variable" do + assert_match(%r!8 relative_include!, @content) + end + + should "include files relative to self" do + assert_match(%r!9 —\ntitle: Test Post Where YAML!, @content) + end + + context "trying to do bad stuff" do + context "include missing file" do + setup do + @content = <<~CONTENT + --- + title: missing file + --- + + {% include_relative missing.html %} + CONTENT + end + + should "raise error relative to source directory" do + exception = assert_raises(IOError) { render_content(@content) } + assert_match "Could not locate the included file 'missing.html' in any of " \ + "[\"#{source_dir}\"].", exception.message + end + end + + context "include existing file above you" do + setup do + @content = <<~CONTENT + --- + title: higher file + --- + + {% include_relative ../README.markdown %} + CONTENT + end + + should "raise error relative to source directory" do + exception = assert_raises(ArgumentError) { render_content(@content) } + assert_equal( + "Invalid syntax for include tag. File contains invalid characters or " \ + "sequences:\n\n ../README.markdown\n\nValid syntax:\n\n " \ + "{% include_relative file.ext param='value' param2='value' %}\n\n", + exception.message + ) + end + end + end + + context "with symlink'd include" do + should "not allow symlink includes" do + FileUtils.mkdir_p("tmp") + File.write("tmp/pages-test", "SYMLINK TEST") + assert_raises IOError do + content = <<~CONTENT + --- + title: Include symlink + --- + + {% include_relative tmp/pages-test %} + + CONTENT + render_content(content, "safe" => true) + end + @result ||= "" + refute_match(%r!SYMLINK TEST!, @result) + end + + should "not expose the existence of symlinked files" do + exception = assert_raises IOError do + content = <<~CONTENT + --- + title: Include symlink + --- + + {% include_relative tmp/pages-test-does-not-exist %} + + CONTENT + render_content(content, "safe" => true) + end + assert_match( + "Ensure it exists in one of those directories and is not a symlink " \ + "as those are not allowed in safe mode.", + exception.message + ) + end + end + end +end diff --git a/test/test_tag_link.rb b/test/test_tag_link.rb new file mode 100644 index 00000000..e0d2a714 --- /dev/null +++ b/test/test_tag_link.rb @@ -0,0 +1,206 @@ +# frozen_string_literal: true + +require "helper" + +class TestTagLink < TagUnitTest + def render_content_with_collection(content, collection_label) + render_content( + content, + "collections" => { collection_label => { "output" => true } }, + "read_collections" => true + ) + end + + context "post content has raw tag" do + setup do + content = <<~CONTENT + --- + title: This is a test + --- + + ```liquid + {% raw %} + {% link _collection/name-of-document.md %} + {% endraw %} + ``` + CONTENT + render_content(content) + end + + should "render markdown with rouge" do + assert_match( + %(
    ) + + %(
    ),
    +        @result
    +      )
    +    end
    +  end
    +
    +  context "simple page with linking to a page" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: linking
    +        ---
    +
    +        {% link contacts.html %}
    +        {% link info.md %}
    +        {% link /css/screen.css %}
    +      CONTENT
    +      render_content(content, "read_all" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the URL to the 'contacts' item" do
    +      assert_match(%r!/contacts\.html!, @result)
    +    end
    +
    +    should "have the URL to the 'info' item" do
    +      assert_match(%r!/info\.html!, @result)
    +    end
    +
    +    should "have the URL to the 'screen.css' item" do
    +      assert_match(%r!/css/screen\.css!, @result)
    +    end
    +  end
    +
    +  context "simple page with dynamic linking to a page" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: linking
    +        ---
    +
    +        {% assign contacts_filename = 'contacts' %}
    +        {% assign contacts_ext = 'html' %}
    +        {% link {{contacts_filename}}.{{contacts_ext}} %}
    +        {% assign info_path = 'info.md' %}
    +        {% link {{\ info_path\ }} %}
    +        {% assign screen_css_path = '/css' %}
    +        {% link {{ screen_css_path }}/screen.css %}
    +      CONTENT
    +      render_content(content, "read_all" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the URL to the 'contacts' item" do
    +      assert_match(%r!/contacts\.html!, @result)
    +    end
    +
    +    should "have the URL to the 'info' item" do
    +      assert_match(%r!/info\.html!, @result)
    +    end
    +
    +    should "have the URL to the 'screen.css' item" do
    +      assert_match(%r!/css/screen\.css!, @result)
    +    end
    +  end
    +
    +  context "simple page with linking" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: linking
    +        ---
    +
    +        {% link _methods/yaml_with_dots.md %}
    +      CONTENT
    +      render_content_with_collection(content, "methods")
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the URL to the 'yaml_with_dots' item" do
    +      assert_match(%r!/methods/yaml_with_dots\.html!, @result)
    +    end
    +  end
    +
    +  context "simple page with dynamic linking" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: linking
    +        ---
    +
    +        {% assign yaml_with_dots_path = '_methods/yaml_with_dots.md' %}
    +        {% link {{yaml_with_dots_path}} %}
    +      CONTENT
    +      render_content_with_collection(content, "methods")
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the URL to the 'yaml_with_dots' item" do
    +      assert_match(%r!/methods/yaml_with_dots\.html!, @result)
    +    end
    +  end
    +
    +  context "simple page with nested linking" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: linking
    +        ---
    +
    +        - 1 {% link _methods/sanitized_path.md %}
    +        - 2 {% link _methods/site/generate.md %}
    +      CONTENT
    +      render_content_with_collection(content, "methods")
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the URL to the 'sanitized_path' item" do
    +      assert_match %r!1\s/methods/sanitized_path\.html!, @result
    +    end
    +
    +    should "have the URL to the 'site/generate' item" do
    +      assert_match %r!2\s/methods/site/generate\.html!, @result
    +    end
    +  end
    +
    +  context "simple page with invalid linking" do
    +    should "cause an error" do
    +      content = <<~CONTENT
    +        ---
    +        title: Invalid linking
    +        ---
    +
    +        {% link non-existent-collection-item %}
    +      CONTENT
    +
    +      assert_raises ArgumentError do
    +        render_content_with_collection(content, "methods")
    +      end
    +    end
    +  end
    +
    +  context "simple page with invalid dynamic linking" do
    +    should "cause an error" do
    +      content = <<~CONTENT
    +        ---
    +        title: Invalid linking
    +        ---
    +
    +        {% assign non_existent_path = 'non-existent-collection-item' %}
    +        {% link {{\ non_existent_path\ }} %}
    +      CONTENT
    +
    +      assert_raises ArgumentError do
    +        render_content_with_collection(content, "methods")
    +      end
    +    end
    +  end
    +end
    diff --git a/test/test_tag_post_url.rb b/test/test_tag_post_url.rb
    new file mode 100644
    index 00000000..5a48857b
    --- /dev/null
    +++ b/test/test_tag_post_url.rb
    @@ -0,0 +1,136 @@
    +# frozen_string_literal: true
    +
    +require "helper"
    +
    +class TestTagPostUrl < TagUnitTest
    +  context "simple page with post linking" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: Post linking
    +        ---
    +
    +        {% post_url 2008-11-21-complex %}
    +      CONTENT
    +
    +      render_content(content, "permalink" => "pretty", "read_posts" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match %r!markdown-html-error!, @result
    +    end
    +
    +    should "have the URL to the 'complex' post from 2008-11-21" do
    +      assert_match %r!/2008/11/21/complex/!, @result
    +    end
    +  end
    +
    +  context "simple page with post linking containing special characters" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: Post linking
    +        ---
    +
    +        {% post_url 2016-11-26-special-chars-(+) %}
    +      CONTENT
    +
    +      render_content(content, "permalink" => "pretty", "read_posts" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match %r!markdown-html-error!, @result
    +    end
    +
    +    should "have the URL to the 'special-chars' post from 2016-11-26" do
    +      assert_match %r!/2016/11/26/special-chars-\(\+\)/!, @result
    +    end
    +  end
    +
    +  context "simple page with nested post linking" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: Post linking
    +        ---
    +
    +        - 1 {% post_url 2008-11-21-complex %}
    +        - 2 {% post_url /2008-11-21-complex %}
    +        - 3 {% post_url es/2008-11-21-nested %}
    +        - 4 {% post_url /es/2008-11-21-nested %}
    +      CONTENT
    +
    +      render_content(content, "permalink" => "pretty", "read_posts" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match %r!markdown-html-error!, @result
    +    end
    +
    +    should "have the URL to the 'complex' post from 2008-11-21" do
    +      assert_match %r!1\s/2008/11/21/complex/!, @result
    +      assert_match %r!2\s/2008/11/21/complex/!, @result
    +    end
    +
    +    should "have the URL to the 'nested' post from 2008-11-21" do
    +      assert_match %r!3\s/2008/11/21/nested/!, @result
    +      assert_match %r!4\s/2008/11/21/nested/!, @result
    +    end
    +  end
    +
    +  context "simple page with nested post linking and path not used in `post_url`" do
    +    setup do
    +      content = <<~CONTENT
    +        ---
    +        title: Deprecated Post linking
    +        ---
    +
    +        - 1 {% post_url 2008-11-21-nested %}
    +      CONTENT
    +
    +      render_content(content, "permalink" => "pretty", "read_posts" => true)
    +    end
    +
    +    should "not cause an error" do
    +      refute_match(%r!markdown-html-error!, @result)
    +    end
    +
    +    should "have the url to the 'nested' post from 2008-11-21" do
    +      assert_match %r!1\s/2008/11/21/nested/!, @result
    +    end
    +
    +    should "throw a deprecation warning" do
    +      deprecation_warning = "       Deprecation: A call to '{% post_url 2008-11-21-nested %}' " \
    +                            "did not match a post using the new matching method of checking " \
    +                            "name (path-date-slug) equality. Please make sure that you change " \
    +                            "this tag to match the post's name exactly."
    +      assert_includes Jekyll.logger.messages, deprecation_warning
    +    end
    +  end
    +
    +  context "simple page with invalid post name linking" do
    +    should "cause an error" do
    +      assert_raises Jekyll::Errors::PostURLError do
    +        render_content(<<~CONTENT, "read_posts" => true)
    +          ---
    +          title: Invalid post name linking
    +          ---
    +
    +          {% post_url abc2008-11-21-complex %}
    +        CONTENT
    +      end
    +    end
    +
    +    should "cause an error with a bad date" do
    +      assert_raises Jekyll::Errors::InvalidDateError do
    +        render_content(<<~CONTENT, "read_posts" => true)
    +          ---
    +          title: Invalid post name linking
    +          ---
    +
    +          {% post_url 2008-42-21-complex %}
    +        CONTENT
    +      end
    +    end
    +  end
    +end
    diff --git a/test/test_tags.rb b/test/test_tags.rb
    deleted file mode 100644
    index a82a6f2e..00000000
    --- a/test/test_tags.rb
    +++ /dev/null
    @@ -1,1191 +0,0 @@
    -# frozen_string_literal: true
    -
    -require "helper"
    -
    -class TestTags < JekyllUnitTest
    -  def setup
    -    FileUtils.mkdir_p("tmp")
    -  end
    -
    -  def create_post(content, override = {}, converter_class = Jekyll::Converters::Markdown)
    -    site = fixture_site({ "highlighter" => "rouge" }.merge(override))
    -
    -    site.posts.docs.concat(PostReader.new(site).read_posts("")) if override["read_posts"]
    -    CollectionReader.new(site).read if override["read_collections"]
    -    site.read if override["read_all"]
    -
    -    info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
    -    @converter = site.converters.find { |c| c.instance_of?(converter_class) }
    -    payload = { "highlighter_prefix" => @converter.highlighter_prefix,
    -                "highlighter_suffix" => @converter.highlighter_suffix, }
    -
    -    @result = Liquid::Template.parse(content).render!(payload, info)
    -    @result = @converter.convert(@result)
    -  end
    -
    -  def fill_post(code, override = {})
    -    content = <<~CONTENT
    -      ---
    -      title: This is a test
    -      ---
    -
    -      This document has some highlighted code in it.
    -
    -      {% highlight text %}
    -      #{code}
    -      {% endhighlight %}
    -      {% highlight text linenos %}
    -      #{code}
    -      {% endhighlight %}
    -    CONTENT
    -    create_post(content, override)
    -  end
    -
    -  def highlight_block_with_opts(options_string)
    -    Jekyll::Tags::HighlightBlock.parse(
    -      "highlight",
    -      options_string,
    -      Liquid::Tokenizer.new("test{% endhighlight %}\n"),
    -      Liquid::ParseContext.new
    -    )
    -  end
    -
    -  context "language name" do
    -    should "match only the required set of chars" do
    -      r = Jekyll::Tags::HighlightBlock::SYNTAX
    -      assert_match r, "ruby"
    -      assert_match r, "c#"
    -      assert_match r, "xml+cheetah"
    -      assert_match r, "x.y"
    -      assert_match r, "coffee-script"
    -      assert_match r, "shell_session"
    -
    -      refute_match r, "blah^"
    -
    -      assert_match r, "ruby key=val"
    -      assert_match r, "ruby a=b c=d"
    -    end
    -  end
    -
    -  context "highlight tag in unsafe mode" do
    -    should "set the no options with just a language name" do
    -      tag = highlight_block_with_opts("ruby ")
    -      assert_equal({}, tag.instance_variable_get(:@highlight_options))
    -    end
    -
    -    should "set the linenos option as 'inline' if no linenos value" do
    -      tag = highlight_block_with_opts("ruby linenos ")
    -      assert_equal(
    -        { :linenos => "inline" },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "set the linenos option to 'table' " \
    -           "if the linenos key is given the table value" do
    -      tag = highlight_block_with_opts("ruby linenos=table ")
    -      assert_equal(
    -        { :linenos => "table" },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "recognize nowrap option with linenos set" do
    -      tag = highlight_block_with_opts("ruby linenos=table nowrap ")
    -      assert_equal(
    -        { :linenos => "table", :nowrap => true },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "recognize the cssclass option" do
    -      tag = highlight_block_with_opts("ruby linenos=table cssclass=hl ")
    -      assert_equal(
    -        { :cssclass => "hl", :linenos => "table" },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "recognize the hl_linenos option and its value" do
    -      tag = highlight_block_with_opts("ruby linenos=table cssclass=hl hl_linenos=3 ")
    -      assert_equal(
    -        { :cssclass => "hl", :linenos => "table", :hl_linenos => "3" },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "recognize multiple values of hl_linenos" do
    -      tag = highlight_block_with_opts 'ruby linenos=table cssclass=hl hl_linenos="3 5 6" '
    -      assert_equal(
    -        { :cssclass => "hl", :linenos => "table", :hl_linenos => %w(3 5 6) },
    -        tag.instance_variable_get(:@highlight_options)
    -      )
    -    end
    -
    -    should "treat language name as case insensitive" do
    -      tag = highlight_block_with_opts("Ruby ")
    -      assert_equal(
    -        "ruby",
    -        tag.instance_variable_get(:@lang),
    -        "lexers should be case insensitive"
    -      )
    -    end
    -  end
    -
    -  context "with the rouge highlighter" do
    -    context "post content has highlight tag" do
    -      setup do
    -        fill_post("test")
    -      end
    -
    -      should "render markdown with rouge" do
    -        assert_match(
    -          %(
    test
    ), - @result - ) - end - - should "render markdown with rouge with line numbers" do - assert_match( - %() + - %() + - %() + - %(
    ) + - %(
    1\n
    test\n
    ), - @result - ) - end - end - - context "post content has raw tag" do - setup do - content = <<~CONTENT - --- - title: This is a test - --- - - ```liquid - {% raw %} - {{ site.baseurl }}{% link _collection/name-of-document.md %} - {% endraw %} - ``` - CONTENT - create_post(content) - end - - should "render markdown with rouge" do - assert_match( - %(
    ) + - %(
    ),
    -          @result
    -        )
    -      end
    -    end
    -
    -    context "post content has highlight with file reference" do
    -      setup do
    -        fill_post("./jekyll.gemspec")
    -      end
    -
    -      should "not embed the file" do
    -        assert_match(
    -          '
    ' \
    -          "./jekyll.gemspec
    ", - @result - ) - end - end - - context "post content has highlight tag with UTF character" do - setup do - fill_post("Æ") - end - - should "render markdown with pygments line handling" do - assert_match( - '
    Æ
    ', - @result - ) - end - end - - context "post content has highlight tag with preceding spaces & lines" do - setup do - fill_post <<~EOS - - - [,1] [,2] - [1,] FALSE TRUE - [2,] FALSE TRUE - EOS - end - - should "only strip the preceding newlines" do - assert_match( - '
         [,1] [,2]',
    -          @result
    -        )
    -      end
    -    end
    -
    -    context "post content has highlight tag with " \
    -            "preceding spaces & lines in several places" do
    -      setup do
    -        fill_post <<~EOS
    -
    -
    -               [,1] [,2]
    -
    -
    -          [1,] FALSE TRUE
    -          [2,] FALSE TRUE
    -
    -
    -        EOS
    -      end
    -
    -      should "only strip the newlines which precede and succeed the entire block" do
    -        assert_match(
    -          "
         [,1] [,2]\n\n\n" \
    -          "[1,] FALSE TRUE\n[2,] FALSE TRUE
    ", - @result - ) - end - end - - context "post content has highlight tag with linenumbers" do - setup do - create_post <<~EOS - --- - title: This is a test - --- - - This is not yet highlighted - {% highlight php linenos %} - test - {% endhighlight %} - - This should not be highlighted, right? - EOS - end - - should "should stop highlighting at boundary with rouge" do - expected = <<~EOS -

    This is not yet highlighted

    \n -
    1
    -          
    test\n
    \n -

    This should not be highlighted, right?

    - EOS - assert_match(expected, @result) - end - end - - context "post content has highlight tag with " \ - "preceding spaces & Windows-style newlines" do - setup do - fill_post "\r\n\r\n\r\n [,1] [,2]" - end - - should "only strip the preceding newlines" do - assert_match( - '
         [,1] [,2]',
    -          @result
    -        )
    -      end
    -    end
    -
    -    context "post content has highlight tag with only preceding spaces" do
    -      setup do
    -        fill_post <<~EOS
    -               [,1] [,2]
    -          [1,] FALSE TRUE
    -          [2,] FALSE TRUE
    -        EOS
    -      end
    -
    -      should "only strip the preceding newlines" do
    -        assert_match(
    -          '
         [,1] [,2]',
    -          @result
    -        )
    -      end
    -    end
    -  end
    -
    -  context "simple post with markdown and pre tags" do
    -    setup do
    -      @content = <<~CONTENT
    -        ---
    -        title: Kramdown post with pre
    -        ---
    -
    -        _FIGHT!_
    -
    -        {% highlight ruby %}
    -        puts "3..2..1.."
    -        {% endhighlight %}
    -
    -        *FINISH HIM*
    -      CONTENT
    -    end
    -
    -    context "using Kramdown" do
    -      setup do
    -        create_post(@content, "markdown" => "kramdown")
    -      end
    -
    -      should "parse correctly" do
    -        assert_match %r{FIGHT!}, @result
    -        assert_match %r!FINISH HIM!, @result
    -      end
    -    end
    -  end
    -
    -  context "simple page with post linking" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: Post linking
    -        ---
    -
    -        {% post_url 2008-11-21-complex %}
    -      CONTENT
    -      create_post(content,
    -                  "permalink"   => "pretty",
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_posts"  => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'complex' post from 2008-11-21" do
    -      assert_match %r!/2008/11/21/complex/!, @result
    -    end
    -  end
    -
    -  context "simple page with post linking containing special characters" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: Post linking
    -        ---
    -
    -        {% post_url 2016-11-26-special-chars-(+) %}
    -      CONTENT
    -      create_post(content,
    -                  "permalink"   => "pretty",
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_posts"  => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'special-chars' post from 2016-11-26" do
    -      assert_match %r!/2016/11/26/special-chars-\(\+\)/!, @result
    -    end
    -  end
    -
    -  context "simple page with nested post linking" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: Post linking
    -        ---
    -
    -        - 1 {% post_url 2008-11-21-complex %}
    -        - 2 {% post_url /2008-11-21-complex %}
    -        - 3 {% post_url es/2008-11-21-nested %}
    -        - 4 {% post_url /es/2008-11-21-nested %}
    -      CONTENT
    -      create_post(content,
    -                  "permalink"   => "pretty",
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_posts"  => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'complex' post from 2008-11-21" do
    -      assert_match %r!1\s/2008/11/21/complex/!, @result
    -      assert_match %r!2\s/2008/11/21/complex/!, @result
    -    end
    -
    -    should "have the URL to the 'nested' post from 2008-11-21" do
    -      assert_match %r!3\s/2008/11/21/nested/!, @result
    -      assert_match %r!4\s/2008/11/21/nested/!, @result
    -    end
    -  end
    -
    -  context "simple page with nested post linking and path not used in `post_url`" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: Deprecated Post linking
    -        ---
    -
    -        - 1 {% post_url 2008-11-21-nested %}
    -      CONTENT
    -      create_post(content,
    -                  "permalink"   => "pretty",
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_posts"  => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the url to the 'nested' post from 2008-11-21" do
    -      assert_match %r!1\s/2008/11/21/nested/!, @result
    -    end
    -
    -    should "throw a deprecation warning" do
    -      deprecation_warning = "       Deprecation: A call to '{% post_url 2008-11-21-nested %}' " \
    -                            "did not match a post using the new matching method of checking " \
    -                            "name (path-date-slug) equality. Please make sure that you change " \
    -                            "this tag to match the post's name exactly."
    -      assert_includes Jekyll.logger.messages, deprecation_warning
    -    end
    -  end
    -
    -  context "simple page with invalid post name linking" do
    -    should "cause an error" do
    -      content = <<~CONTENT
    -        ---
    -        title: Invalid post name linking
    -        ---
    -
    -        {% post_url abc2008-11-21-complex %}
    -      CONTENT
    -
    -      assert_raises Jekyll::Errors::PostURLError do
    -        create_post(content,
    -                    "permalink"   => "pretty",
    -                    "source"      => source_dir,
    -                    "destination" => dest_dir,
    -                    "read_posts"  => true)
    -      end
    -    end
    -
    -    should "cause an error with a bad date" do
    -      content = <<~CONTENT
    -        ---
    -        title: Invalid post name linking
    -        ---
    -
    -        {% post_url 2008-42-21-complex %}
    -      CONTENT
    -
    -      assert_raises Jekyll::Errors::InvalidDateError do
    -        create_post(content,
    -                    "permalink"   => "pretty",
    -                    "source"      => source_dir,
    -                    "destination" => dest_dir,
    -                    "read_posts"  => true)
    -      end
    -    end
    -  end
    -
    -  context "simple page with linking to a page" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: linking
    -        ---
    -
    -        {% link contacts.html %}
    -        {% link info.md %}
    -        {% link /css/screen.css %}
    -      CONTENT
    -      create_post(content,
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_all"    => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'contacts' item" do
    -      assert_match(%r!/contacts\.html!, @result)
    -    end
    -
    -    should "have the URL to the 'info' item" do
    -      assert_match(%r!/info\.html!, @result)
    -    end
    -
    -    should "have the URL to the 'screen.css' item" do
    -      assert_match(%r!/css/screen\.css!, @result)
    -    end
    -  end
    -
    -  context "simple page with dynamic linking to a page" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: linking
    -        ---
    -
    -        {% assign contacts_filename = 'contacts' %}
    -        {% assign contacts_ext = 'html' %}
    -        {% link {{contacts_filename}}.{{contacts_ext}} %}
    -        {% assign info_path = 'info.md' %}
    -        {% link {{\ info_path\ }} %}
    -        {% assign screen_css_path = '/css' %}
    -        {% link {{ screen_css_path }}/screen.css %}
    -      CONTENT
    -      create_post(content,
    -                  "source"      => source_dir,
    -                  "destination" => dest_dir,
    -                  "read_all"    => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'contacts' item" do
    -      assert_match(%r!/contacts\.html!, @result)
    -    end
    -
    -    should "have the URL to the 'info' item" do
    -      assert_match(%r!/info\.html!, @result)
    -    end
    -
    -    should "have the URL to the 'screen.css' item" do
    -      assert_match(%r!/css/screen\.css!, @result)
    -    end
    -  end
    -
    -  context "simple page with linking" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: linking
    -        ---
    -
    -        {% link _methods/yaml_with_dots.md %}
    -      CONTENT
    -      create_post(content,
    -                  "source"           => source_dir,
    -                  "destination"      => dest_dir,
    -                  "collections"      => { "methods" => { "output" => true } },
    -                  "read_collections" => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'yaml_with_dots' item" do
    -      assert_match(%r!/methods/yaml_with_dots\.html!, @result)
    -    end
    -  end
    -
    -  context "simple page with dynamic linking" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: linking
    -        ---
    -
    -        {% assign yaml_with_dots_path = '_methods/yaml_with_dots.md' %}
    -        {% link {{yaml_with_dots_path}} %}
    -      CONTENT
    -      create_post(content,
    -                  "source"           => source_dir,
    -                  "destination"      => dest_dir,
    -                  "collections"      => { "methods" => { "output" => true } },
    -                  "read_collections" => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'yaml_with_dots' item" do
    -      assert_match(%r!/methods/yaml_with_dots\.html!, @result)
    -    end
    -  end
    -
    -  context "simple page with nested linking" do
    -    setup do
    -      content = <<~CONTENT
    -        ---
    -        title: linking
    -        ---
    -
    -        - 1 {% link _methods/sanitized_path.md %}
    -        - 2 {% link _methods/site/generate.md %}
    -      CONTENT
    -      create_post(content,
    -                  "source"           => source_dir,
    -                  "destination"      => dest_dir,
    -                  "collections"      => { "methods" => { "output" => true } },
    -                  "read_collections" => true)
    -    end
    -
    -    should "not cause an error" do
    -      refute_match(%r!markdown-html-error!, @result)
    -    end
    -
    -    should "have the URL to the 'sanitized_path' item" do
    -      assert_match %r!1\s/methods/sanitized_path\.html!, @result
    -    end
    -
    -    should "have the URL to the 'site/generate' item" do
    -      assert_match %r!2\s/methods/site/generate\.html!, @result
    -    end
    -  end
    -
    -  context "simple page with invalid linking" do
    -    should "cause an error" do
    -      content = <<~CONTENT
    -        ---
    -        title: Invalid linking
    -        ---
    -
    -        {% link non-existent-collection-item %}
    -      CONTENT
    -
    -      assert_raises ArgumentError do
    -        create_post(content,
    -                    "source"           => source_dir,
    -                    "destination"      => dest_dir,
    -                    "collections"      => { "methods" => { "output" => true } },
    -                    "read_collections" => true)
    -      end
    -    end
    -  end
    -
    -  context "simple page with invalid dynamic linking" do
    -    should "cause an error" do
    -      content = <<~CONTENT
    -        ---
    -        title: Invalid linking
    -        ---
    -
    -        {% assign non_existent_path = 'non-existent-collection-item' %}
    -        {% link {{\ non_existent_path\ }} %}
    -      CONTENT
    -
    -      assert_raises ArgumentError do
    -        create_post(content,
    -                    "source"           => source_dir,
    -                    "destination"      => dest_dir,
    -                    "collections"      => { "methods" => { "output" => true } },
    -                    "read_collections" => true)
    -      end
    -    end
    -  end
    -
    -  context "include tag with parameters" do
    -    context "with symlink'd include" do
    -      should "not allow symlink includes" do
    -        File.write("tmp/pages-test", "SYMLINK TEST")
    -        assert_raises IOError do
    -          content = <<~CONTENT
    -            ---
    -            title: Include symlink
    -            ---
    -
    -            {% include tmp/pages-test %}
    -
    -          CONTENT
    -          create_post(content,
    -                      "permalink"   => "pretty",
    -                      "source"      => source_dir,
    -                      "destination" => dest_dir,
    -                      "read_posts"  => true,
    -                      "safe"        => true)
    -        end
    -        @result ||= ""
    -        refute_match(%r!SYMLINK TEST!, @result)
    -      end
    -
    -      should "not expose the existence of symlinked files" do
    -        ex = assert_raises IOError do
    -          content = <<~CONTENT
    -            ---
    -            title: Include symlink
    -            ---
    -
    -            {% include tmp/pages-test-does-not-exist %}
    -
    -          CONTENT
    -          create_post(content,
    -                      "permalink"   => "pretty",
    -                      "source"      => source_dir,
    -                      "destination" => dest_dir,
    -                      "read_posts"  => true,
    -                      "safe"        => true)
    -        end
    -        assert_match(
    -          "Could not locate the included file 'tmp/pages-test-does-not-exist' " \
    -          "in any of [\"#{source_dir}/_includes\"]. Ensure it exists in one of " \
    -          "those directories and is not a symlink as those are not allowed in " \
    -          "safe mode.",
    -          ex.message
    -        )
    -      end
    -    end
    -
    -    context "with one parameter" do
    -      setup do
    -        content = <<~CONTENT
    -          ---
    -          title: Include tag parameters
    -          ---
    -
    -          {% include sig.markdown myparam="test" %}
    -
    -          {% include params.html param="value" %}
    -        CONTENT
    -        create_post(content,
    -                    "permalink"   => "pretty",
    -                    "source"      => source_dir,
    -                    "destination" => dest_dir,
    -                    "read_posts"  => true)
    -      end
    -
    -      should "correctly output include variable" do
    -        assert_match "value", @result.strip
    -      end
    -
    -      should "ignore parameters if unused" do
    -        assert_match "
    \n

    Tom Preston-Werner\ngithub.com/mojombo

    \n", @result - end - end - - context "with simple syntax but multiline markup" do - setup do - content = <<~CONTENT - --- - title: Include tag parameters - --- - - {% include sig.markdown myparam="test" %} - - {% include params.html - param="value" %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "correctly output include variable" do - assert_match "value", @result.strip - end - - should "ignore parameters if unused" do - assert_match "
    \n

    Tom Preston-Werner\ngithub.com/mojombo

    \n", @result - end - end - - context "with variable syntax but multiline markup" do - setup do - content = <<~CONTENT - --- - title: Include tag parameters - --- - - {% include sig.markdown myparam="test" %} - {% assign path = "params" | append: ".html" %} - {% include {{ path }} - param="value" %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "correctly output include variable" do - assert_match "value", @result.strip - end - - should "ignore parameters if unused" do - assert_match "
    \n

    Tom Preston-Werner\ngithub.com/mojombo

    \n", @result - end - end - - context "with invalid parameter syntax" do - should "throw a ArgumentError" do - content = <<~CONTENT - --- - title: Invalid parameter syntax - --- - - {% include params.html param s="value" %} - CONTENT - assert_raises ArgumentError, "Did not raise exception on invalid " \ - '"include" syntax' do - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - content = <<~CONTENT - --- - title: Invalid parameter syntax - --- - - {% include params.html params="value %} - CONTENT - assert_raises ArgumentError, "Did not raise exception on invalid " \ - '"include" syntax' do - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - end - end - - context "with several parameters" do - setup do - content = <<~CONTENT - --- - title: multiple include parameters - --- - - {% include params.html param1="new_value" param2="another" %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "list all parameters" do - assert_match "
  • param1 = new_value
  • ", @result - assert_match "
  • param2 = another
  • ", @result - end - - should "not include previously used parameters" do - assert_match "", @result - end - end - - context "without parameters" do - setup do - content = <<~CONTENT - --- - title: without parameters - --- - - {% include params.html %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "include file with empty parameters" do - assert_match "", @result - end - end - - context "with include file with special characters without params" do - setup do - content = <<~CONTENT - --- - title: special characters - --- - - {% include params@2.0.html %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "include file with empty parameters" do - assert_match "", @result - end - end - - context "with include file with special characters with params" do - setup do - content = <<~CONTENT - --- - title: special characters - --- - - {% include params@2.0.html param1="foobar" param2="bazbar" %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "include file with empty parameters" do - assert_match "
  • param1 = foobar
  • ", @result - assert_match "
  • param2 = bazbar
  • ", @result - end - end - - context "with custom includes directory" do - setup do - content = <<~CONTENT - --- - title: custom includes directory - --- - - {% include custom.html %} - CONTENT - create_post(content, - "includes_dir" => "_includes_custom", - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "include file from custom directory" do - assert_match "custom_included", @result - end - end - - context "without parameters within if statement" do - setup do - content = <<~CONTENT - --- - title: without parameters within if statement - --- - - {% if true %}{% include params.html %}{% endif %} - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - - should "include file with empty parameters within if statement" do - assert_match "", @result - end - end - - context "include missing file" do - setup do - @content = <<~CONTENT - --- - title: missing file - --- - - {% include missing.html %} - CONTENT - end - - should "raise error relative to source directory" do - exception = assert_raises IOError do - create_post(@content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - assert_match( - "Could not locate the included file 'missing.html' in any of " \ - "[\"#{source_dir}/_includes\"].", - exception.message - ) - end - end - - context "include tag with variable and liquid filters" do - setup do - site = fixture_site("pygments" => true).tap(&:read).tap(&:render) - post = site.posts.docs.find do |p| - p.basename.eql? "2013-12-17-include-variable-filters.markdown" - end - @content = post.output - end - - should "include file as variable with liquid filters" do - assert_match(%r!1 included!, @content) - assert_match(%r!2 included!, @content) - assert_match(%r!3 included!, @content) - end - - should "include file as variable and liquid filters with arbitrary whitespace" do - assert_match(%r!4 included!, @content) - assert_match(%r!5 included!, @content) - assert_match(%r!6 included!, @content) - end - - should "include file as variable and filters with additional parameters" do - assert_match("
  • var1 = foo
  • ", @content) - assert_match("
  • var2 = bar
  • ", @content) - end - - should "include file as partial variable" do - assert_match(%r!8 included!, @content) - end - end - end - - context "relative include tag with variable and liquid filters" do - setup do - site = fixture_site("pygments" => true).tap(&:read).tap(&:render) - post = site.posts.docs.find do |p| - p.basename.eql? "2014-09-02-relative-includes.markdown" - end - @content = post.output - end - - should "include file as variable with liquid filters" do - assert_match(%r!1 relative_include!, @content) - assert_match(%r!2 relative_include!, @content) - assert_match(%r!3 relative_include!, @content) - end - - should "include file as variable and liquid filters with arbitrary whitespace" do - assert_match(%r!4 relative_include!, @content) - assert_match(%r!5 relative_include!, @content) - assert_match(%r!6 relative_include!, @content) - end - - should "include file as variable and filters with additional parameters" do - assert_match("
  • var1 = foo
  • ", @content) - assert_match("
  • var2 = bar
  • ", @content) - end - - should "include file as partial variable" do - assert_match(%r!8 relative_include!, @content) - end - - should "include files relative to self" do - assert_match(%r!9 —\ntitle: Test Post Where YAML!, @content) - end - - context "trying to do bad stuff" do - context "include missing file" do - setup do - @content = <<~CONTENT - --- - title: missing file - --- - - {% include_relative missing.html %} - CONTENT - end - - should "raise error relative to source directory" do - exception = assert_raises IOError do - create_post(@content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - assert_match "Could not locate the included file 'missing.html' in any of " \ - "[\"#{source_dir}\"].", exception.message - end - end - - context "include existing file above you" do - setup do - @content = <<~CONTENT - --- - title: higher file - --- - - {% include_relative ../README.markdown %} - CONTENT - end - - should "raise error relative to source directory" do - exception = assert_raises ArgumentError do - create_post(@content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true) - end - assert_equal( - "Invalid syntax for include tag. File contains invalid characters or " \ - "sequences:\n\n ../README.markdown\n\nValid syntax:\n\n " \ - "{% include_relative file.ext param='value' param2='value' %}\n\n", - exception.message - ) - end - end - end - - context "with symlink'd include" do - should "not allow symlink includes" do - File.write("tmp/pages-test", "SYMLINK TEST") - assert_raises IOError do - content = <<~CONTENT - --- - title: Include symlink - --- - - {% include_relative tmp/pages-test %} - - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true, - "safe" => true) - end - @result ||= "" - refute_match(%r!SYMLINK TEST!, @result) - end - - should "not expose the existence of symlinked files" do - ex = assert_raises IOError do - content = <<~CONTENT - --- - title: Include symlink - --- - - {% include_relative tmp/pages-test-does-not-exist %} - - CONTENT - create_post(content, - "permalink" => "pretty", - "source" => source_dir, - "destination" => dest_dir, - "read_posts" => true, - "safe" => true) - end - assert_match( - "Ensure it exists in one of those directories and is not a symlink " \ - "as those are not allowed in safe mode.", - ex.message - ) - end - end - end -end