# encoding: utf-8 require 'helper' class TestPost < JekyllUnitTest def setup_post(file) Post.new(@site, source_dir, '', file) end def do_render(post) layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")} post.render(layouts, {"site" => {"posts" => []}}) end context "A Post" do setup do clear_dest @site = fixture_site end should "ensure valid posts are valid" do assert Post.valid?("2008-09-09-foo-bar.textile") assert Post.valid?("foo/bar/2008-09-09-foo-bar.textile") assert Post.valid?("2008-09-09-foo-bar.markdown") assert Post.valid?("foo/bar/2008-09-09-foo-bar.markdown") assert !Post.valid?("lol2008-09-09-foo-bar.textile") assert !Post.valid?("lol2008-09-09-foo-bar.markdown") assert !Post.valid?("blah") end should "make properties accessible through #[]" do post = setup_post('2013-12-20-properties.text') attrs = { categories: %w(foo bar baz MixedCase), content: "All the properties.\n\nPlus an excerpt.\n", date: Time.new(2013, 12, 20), dir: "/foo/bar/baz/mixedcase/2013/12/20", excerpt: "All the properties.\n\n", foo: 'bar', id: "/foo/bar/baz/mixedcase/2013/12/20/properties", layout: 'default', name: nil, path: "_posts/2013-12-20-properties.text", permalink: nil, published: nil, tags: %w(ay bee cee), title: 'Properties Post', url: "/foo/bar/baz/mixedcase/2013/12/20/properties.html" } attrs.each do |attr, val| attr_str = attr.to_s result = post[attr_str] assert_equal val, result, "For :" end end context "processing posts" do setup do @post = Post.allocate @post.site = @site @real_file = "2008-10-18-foo-bar.markdown" @fake_file = "2008-09-09-foo-bar.markdown" @source = source_dir('_posts') end should "keep date, title, and markup type" do @post.categories = [] @post.process(@fake_file) assert_equal Time.parse("2008-09-09"), @post.date assert_equal "foo-bar", @post.slug assert_equal ".markdown", @post.ext assert_equal "/2008/09/09", @post.dir assert_equal "/2008/09/09/foo-bar", @post.id end should "ignore subfolders" do post = Post.allocate post.categories = ['foo'] post.site = @site post.process("cat1/2008-09-09-foo-bar.textile") assert_equal 1, post.categories.size assert_equal "foo", post.categories[0] post = Post.allocate post.categories = ['foo', 'bar'] post.site = @site post.process("cat2/CAT3/2008-09-09-foo-bar.textile") assert_equal 2, post.categories.size assert_equal "foo", post.categories[0] assert_equal "bar", post.categories[1] end should "create url based on date and title" do @post.categories = [] @post.process(@fake_file) assert_equal "/2008/09/09/foo-bar.html", @post.url end should "raise a good error on invalid post date" do assert_raises Jekyll::Errors::FatalException do @post.process("2009-27-03-foo-bar.textile") end end should "escape urls" do @post.categories = [] @post.process("2009-03-12-hash-#1.markdown") assert_equal "/2009/03/12/hash-%231.html", @post.url assert_equal "/2009/03/12/hash-#1", @post.id end should "escape urls with non-alphabetic characters" do @post.categories = [] @post.process("2014-03-22-escape-+ %20[].markdown") assert_equal "/2014/03/22/escape-+%20%2520%5B%5D.html", @post.url assert_equal "/2014/03/22/escape-+ %20[]", @post.id end should "return a UTF-8 escaped string" do assert_equal Encoding::UTF_8, URL.escape_path("/rails笔记/2014/04/20/escaped/").encoding end should "return a UTF-8 unescaped string" do assert_equal Encoding::UTF_8, URL.unescape_path("/rails%E7%AC%94%E8%AE%B0/2014/04/20/escaped/".encode(Encoding::ASCII)).encoding end should "respect permalink in yaml front matter" do file = "2008-12-03-permalinked-post.textile" @post.process(file) @post.read_yaml(@source, file) assert_equal "my_category/permalinked-post", @post.permalink assert_equal "/my_category", @post.dir assert_equal "/my_category/permalinked-post", @post.url end should "not be writable outside of destination" do unexpected = File.expand_path("../../../baddie.html", dest_dir) File.delete unexpected if File.exist?(unexpected) post = setup_post("2014-01-06-permalink-traversal.md") do_render(post) post.write(dest_dir) assert !File.exist?(unexpected), "../../../baddie.html should not exist." assert File.exist?(File.expand_path("baddie.html", dest_dir)) end context "with CRLF linebreaks" do setup do @real_file = "2009-05-24-yaml-linebreak.markdown" @source = source_dir('win/_posts') end should "read yaml front-matter" do @post.read_yaml(@source, @real_file) assert_equal({"title" => "Test title", "layout" => "post", "tag" => "Ruby"}, @post.data) assert_equal "This is the content", @post.content end end context "with three dots ending YAML header" do setup do @real_file = "2014-03-03-yaml-with-dots.md" end should "should read the YAML header" do @post.read_yaml(@source, @real_file) assert_equal({"title" => "Test Post Where YAML Ends in Dots"}, @post.data) end end context "with embedded triple dash" do setup do @real_file = "2010-01-08-triple-dash.markdown" end should "consume the embedded dashes" do @post.read_yaml(@source, @real_file) assert_equal({"title" => "Foo --- Bar"}, @post.data) assert_equal "Triple the fun!", @post.content end end context "with site wide permalink" do setup do @post.categories = [] end context "with unspecified (date) style" do setup do @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/2008/09/09/foo-bar.html", @post.url end end context "with unspecified (date) style and a category" do setup do @post.categories << "beer" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/beer/2008/09/09/foo-bar.html", @post.url end end context "with unspecified (date) style and a numeric category" do setup do @post.categories << 2013 @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/2013/2008/09/09/foo-bar.html", @post.url end end context "with specified layout of nil" do setup do file = '2013-01-12-nil-layout.textile' @post = setup_post(file) @post.process(file) end should "layout of nil is respected" do assert_equal "nil", @post.data["layout"] end end context "with unspecified (date) style and categories" do setup do @post.categories << "food" @post.categories << "beer" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/food/beer/2008/09/09/foo-bar.html", @post.url end end context "with space (categories)" do setup do @post.categories << "french cuisine" @post.categories << "belgian beer" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/french%20cuisine/belgian%20beer/2008/09/09/foo-bar.html", @post.url end end context "with mixed case (category)" do setup do @post.categories << "MixedCase" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/mixedcase/2008/09/09/foo-bar.html", @post.url end end context "with duplicated mixed case (categories)" do setup do @post.categories << "MixedCase" @post.categories << "Mixedcase" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title.html", @post.template assert_equal "/mixedcase/2008/09/09/foo-bar.html", @post.url end end context "with none style" do setup do @post.site.permalink_style = :none @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:title.html", @post.template assert_equal "/foo-bar.html", @post.url end end context "with pretty style" do setup do @post.site.permalink_style = :pretty @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:month/:day/:title/", @post.template assert_equal "/2008/09/09/foo-bar/", @post.url end end context "with ordinal style" do setup do @post.site.permalink_style = :ordinal @post.process(@fake_file) end should "process the url correctly" do assert_equal "/:categories/:year/:y_day/:title.html", @post.template assert_equal "/2008/253/foo-bar.html", @post.url end end context "with custom date permalink" do setup do @post.site.permalink_style = '/:categories/:year/:i_month/:i_day/:title/' @post.process(@fake_file) end should "process the url correctly" do assert_equal "/2008/9/9/foo-bar/", @post.url end end context "with custom abbreviated month date permalink" do setup do @post.site.permalink_style = '/:categories/:year/:short_month/:day/:title/' @post.process(@fake_file) end should "process the url correctly" do assert_equal "/2008/Sep/09/foo-bar/", @post.url end end context "with prefix style and no extension" do setup do @post.site.permalink_style = "/prefix/:title" @post.process(@fake_file) end should "process the url correctly" do assert_equal "/prefix/:title", @post.template assert_equal "/prefix/foo-bar", @post.url end end end should "read yaml front-matter" do @post.read_yaml(@source, @real_file) assert_equal({"title" => "Foo Bar", "layout" => "default"}, @post.data) assert_equal "# {{ page.title }}\n\nBest **post** ever", @post.content end should "transform textile" do @post.process(@real_file) @post.read_yaml(@source, @real_file) assert_equal "

{{ page.title }}

\n\n

Best post ever

", @post.transform.strip end context "#excerpt" do setup do file = "2013-01-02-post-excerpt.markdown" @post = setup_post(file) @post.process(file) @post.read_yaml(@source, file) do_render(@post) end should "return first paragraph by default" do assert @post.excerpt.include?("First paragraph"), "contains first paragraph" assert !@post.excerpt.include?("Second paragraph"), "does not contains second paragraph" assert !@post.excerpt.include?("Third paragraph"), "does not contains third paragraph" end should "correctly resolve link references" do assert @post.excerpt.include?("www.jekyllrb.com"), "contains referenced link URL" end should "return rendered HTML" do assert_equal "

First paragraph with link ref.

\n\n", @post.excerpt end context "with excerpt_separator setting" do setup do file = "2013-01-02-post-excerpt.markdown" @post.site.config['excerpt_separator'] = "\n---\n" @post.process(file) @post.read_yaml(@source, file) @post.transform end should "respect given separator" do assert @post.excerpt.include?("First paragraph"), "contains first paragraph" assert @post.excerpt.include?("Second paragraph"), "contains second paragraph" assert !@post.excerpt.include?("Third paragraph"), "does not contains third paragraph" end should "replace separator with new-lines" do assert !@post.excerpt.include?("---"), "does not contains separator" end end context "with page's excerpt_separator setting" do setup do file = "2015-01-08-post-excerpt-separator.markdown" @post.process(file) @post.read_yaml(@source, file) @post.transform end should "respect given separator" do assert @post.excerpt.include?("First paragraph"), "contains first paragraph" assert @post.excerpt.include?("Second paragraph"), "contains second paragraph" assert !@post.excerpt.include?("Third paragraph"), "does not contains third paragraph" end end context "with custom excerpt" do setup do file = "2013-04-11-custom-excerpt.markdown" @post = setup_post(file) do_render(@post) end should "use custom excerpt" do assert_equal("I can set a custom excerpt", @post.excerpt) end should "expose custom excerpt to liquid" do assert @post.content.include?("I can use the excerpt: I can set a custom excerpt"), "Exposes incorrect excerpt to liquid." end end end end context "when in a site" do setup do clear_dest @site = fixture_site @site.posts = [setup_post('2008-02-02-published.textile'), setup_post('2009-01-27-categories.textile')] end should "have next post" do assert_equal(@site.posts.last, @site.posts.first.next) end should "have previous post" do assert_equal(@site.posts.first, @site.posts.last.previous) end should "not have previous post if first" do assert_equal(nil, @site.posts.first.previous) end should "not have next post if last" do assert_equal(nil, @site.posts.last.next) end end context "initializing posts" do should "recognize date in yaml" do post = setup_post("2010-01-09-date-override.markdown") do_render(post) assert_equal Time, post.date.class assert_equal Time, post.to_liquid["date"].class assert_equal "/2010/01/10/date-override.html", post.url assert_equal "

Post with a front matter date

\n\n

10 Jan 2010

", post.output.strip end should "recognize time in yaml" do post = setup_post("2010-01-09-time-override.markdown") do_render(post) assert_equal Time, post.date.class assert_equal Time, post.to_liquid["date"].class assert_equal "/2010/01/10/time-override.html", post.url assert_equal "

Post with a front matter time

\n\n

10 Jan 2010

", post.output.strip end should "recognize time with timezone in yaml" do post = setup_post("2010-01-09-timezone-override.markdown") do_render(post) assert_equal Time, post.date.class assert_equal Time, post.to_liquid["date"].class assert_equal "/2010/01/10/timezone-override.html", post.url assert_equal "

Post with a front matter time with timezone

\n\n

10 Jan 2010

", post.output.strip end should "to_liquid prioritizes post attributes over data" do post = setup_post("2010-01-16-override-data.textile") assert_equal Array, post.tags.class assert_equal Array, post.to_liquid["tags"].class assert_equal Time, post.date.class assert_equal Time, post.to_liquid["date"].class end should "to_liquid should consider inheritance" do klass = Class.new(Jekyll::Post) assert_gets_called = false klass.send(:define_method, :assert_gets_called) { assert_gets_called = true } klass.const_set(:EXCERPT_ATTRIBUTES_FOR_LIQUID, Jekyll::Post::EXCERPT_ATTRIBUTES_FOR_LIQUID + ['assert_gets_called']) post = klass.new(@site, source_dir, '', "2008-02-02-published.textile") do_render(post) assert assert_gets_called, 'assert_gets_called did not get called on post.' end should "recognize category in yaml" do post = setup_post("2009-01-27-category.textile") assert post.categories.include?('foo') end should "recognize several categories in yaml" do post = setup_post("2009-01-27-categories.textile") assert post.categories.include?('foo') assert post.categories.include?('bar') assert post.categories.include?('baz') end should "recognize empty category in yaml" do post = setup_post("2009-01-27-empty-category.textile") assert_equal [], post.categories end should "recognize empty categories in yaml" do post = setup_post("2009-01-27-empty-categories.textile") assert_equal [], post.categories end should "recognize number category in yaml" do post = setup_post("2013-05-10-number-category.textile") assert post.categories.include?('2013') assert !post.categories.include?(2013) end should "recognize mixed case category in yaml" do post = setup_post("2014-07-05-mixed-case-category.markdown") assert post.categories.include?('MixedCase') assert !post.categories.include?('mixedcase') end should "recognize tag in yaml" do post = setup_post("2009-05-18-tag.textile") assert post.tags.include?('code') end should "recognize tags in yaml" do post = setup_post("2009-05-18-tags.textile") assert post.tags.include?('food') assert post.tags.include?('cooking') assert post.tags.include?('pizza') end should "recognize empty tag in yaml" do post = setup_post("2009-05-18-empty-tag.textile") assert_equal [], post.tags end should "recognize empty tags in yaml" do post = setup_post("2009-05-18-empty-tags.textile") assert_equal [], post.tags end should "allow no yaml" do post = setup_post("2009-06-22-no-yaml.textile") assert_equal "No YAML.", post.content end should "allow empty yaml" do post = setup_post("2009-06-22-empty-yaml.textile") assert_equal "Empty YAML.", post.content end context "rendering" do setup do clear_dest end should "render properly" do post = setup_post("2008-10-18-foo-bar.markdown") do_render(post) assert_equal "<<<

Foo Bar

\n\n

Best post ever

\n >>>", post.output end should "write properly" do post = setup_post("2008-10-18-foo-bar.markdown") do_render(post) post.write(dest_dir) assert File.directory?(dest_dir) assert File.exist?(File.join(dest_dir, '2008', '10', '18', 'foo-bar.html')) end should "write properly when url has hash" do post = setup_post("2009-03-12-hash-#1.markdown") do_render(post) post.write(dest_dir) assert File.directory?(dest_dir) assert File.exist?(File.join(dest_dir, '2009', '03', '12', 'hash-#1.html')) end should "write properly when url has space" do post = setup_post("2014-03-22-escape-+ %20[].markdown") do_render(post) post.write(dest_dir) assert File.directory?(dest_dir) assert File.exist?(File.join(dest_dir, '2014', '03', '22', 'escape-+ %20[].html')) end should "write properly when category has different letter case" do %w(2014-07-05-mixed-case-category.markdown 2014-07-05-another-mixed-case-category.markdown).each do |file| post = setup_post(file) do_render(post) post.write(dest_dir) end assert File.directory?(dest_dir) assert File.exist?(File.join(dest_dir, 'mixedcase', '2014', '07', '05', 'mixed-case-category.html')) assert File.exist?(File.join(dest_dir, 'mixedcase', '2014', '07', '05', 'another-mixed-case-category.html')) end should "write properly without html extension" do post = setup_post("2008-10-18-foo-bar.markdown") post.site.permalink_style = ":title/" do_render(post) post.write(dest_dir) assert File.directory?(dest_dir) assert File.exist?(File.join(dest_dir, 'foo-bar', 'index.html')) end should "insert data" do post = setup_post("2008-11-21-complex.markdown") do_render(post) assert_equal "<<<

url: /2008/11/21/complex.html\ndate: #{Time.parse("2008-11-21")}\nid: /2008/11/21/complex

\n >>>", post.output end should "include templates" do post = setup_post("2008-12-13-include.markdown") do_render(post) assert_equal "<<<
\n

Tom Preston-Werner\ngithub.com/mojombo

\n\n

This is cool

\n >>>", post.output end should "render date specified in front matter properly" do post = setup_post("2010-01-09-date-override.markdown") do_render(post) assert_equal "

Post with a front matter date

\n\n

10 Jan 2010

", post.output.strip end should "render time specified in front matter properly" do post = setup_post("2010-01-09-time-override.markdown") do_render(post) assert_equal "

Post with a front matter time

\n\n

10 Jan 2010

", post.output.strip end end end should "generate categories and topics" do post = Post.new(@site, File.join(File.dirname(__FILE__), *%w[source]), 'foo', 'bar/2008-12-12-topical-post.textile') assert_equal ['foo'], post.categories end end context "converter file extension settings" do setup do @site = fixture_site end should "process .md as markdown under default configuration" do post = setup_post '2011-04-12-md-extension.md' conv = post.converters.first assert conv.kind_of? Jekyll::Converters::Markdown end should "process .text as identity under default configuration" do post = setup_post '2011-04-12-text-extension.text' conv = post.converters.first assert conv.kind_of? Jekyll::Converters::Identity end should "process .text as markdown under alternate configuration" do @site.config['markdown_ext'] = 'markdown,mdw,mdwn,md,text' post = setup_post '2011-04-12-text-extension.text' conv = post.converters.first assert conv.kind_of? Jekyll::Converters::Markdown end should "process .md as markdown under alternate configuration" do @site.config['markdown_ext'] = 'markdown,mkd,mkdn,md,text' post = setup_post '2011-04-12-text-extension.text' conv = post.converters.first assert conv.kind_of? Jekyll::Converters::Markdown end should "process .mkdn under text if it is not in the markdown config" do @site.config['markdown_ext'] = 'markdown,mkd,md,text' post = setup_post '2013-08-01-mkdn-extension.mkdn' conv = post.converters.first assert conv.kind_of? Jekyll::Converters::Identity end should "process .Rmd under text if it is not in the markdown config" do @site.config['markdown_ext'] = 'markdown,mkd,md,text' post = setup_post '2014-11-24-Rmd-extension.Rmd' assert_equal 1, post.converters.size conv = post.converters.first assert conv.kind_of?(Jekyll::Converters::Identity), "The converter for .Rmd should be the Identity converter." end end context "site config with category" do setup do front_matter_defaults = { 'defaults' => [{ 'scope' => { 'path' => '' }, 'values' => { 'category' => 'article' } }] } @site = fixture_site(front_matter_defaults) end should "return category if post does not specify category" do post = setup_post("2009-01-27-no-category.textile") assert post.categories.include?('article'), "Expected post.categories to include 'article' but did not." end should "override site category if set on post" do post = setup_post("2009-01-27-category.textile") assert post.categories.include?('foo'), "Expected post.categories to include 'foo' but did not." assert !post.categories.include?('article'), "Did not expect post.categories to include 'article' but it did." end end context "site config with categories" do setup do front_matter_defaults = { 'defaults' => [{ 'scope' => { 'path' => '' }, 'values' => { 'categories' => ['article'] } }] } @site = fixture_site(front_matter_defaults) end should "return categories if post does not specify categories" do post = setup_post("2009-01-27-no-category.textile") assert post.categories.include?('article'), "Expected post.categories to include 'article' but did not." end should "override site categories if set on post" do post = setup_post("2009-01-27-categories.textile") ['foo', 'bar', 'baz'].each do |category| assert post.categories.include?(category), "Expected post.categories to include '#{category}' but did not." end assert !post.categories.include?('article'), "Did not expect post.categories to include 'article' but it did." end end end