Expose a per-post fediverse_creator frontmatter field plus a site-wide default in config.toml ([site].fediverse_creator). The handle is returned in the post and site payloads, rendered as <dc:creator> in the RSS feed and as authors[].name in the JSON feed, so a front-end can drop it into <meta name="fediverse:creator"> on rendered pages. Per-post value overrides the site default. Validated against a simple @user@host regex. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
138 lines
4.3 KiB
Ruby
138 lines
4.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "test_helper"
|
|
|
|
class PostTest < Minitest::Test
|
|
def test_parse_builds_post
|
|
content = <<~POST
|
|
+++
|
|
title = "Hello"
|
|
slug = "hello"
|
|
lang = "en"
|
|
tags = ["intro", "ruby"]
|
|
date = 2026-01-15
|
|
draft = true
|
|
+++
|
|
|
|
First paragraph.
|
|
POST
|
|
post = Volumen::Post.parse(content)
|
|
assert_equal "hello", post.slug
|
|
assert_equal "Hello", post.title
|
|
assert_equal "en", post.lang
|
|
assert_equal %w[intro ruby], post.tags
|
|
assert_predicate post, :draft?
|
|
assert_equal "2026-01-15", post.date_string
|
|
end
|
|
|
|
def test_excerpt_derived_from_body
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" }, body: "# Heading\n\nThe body paragraph.")
|
|
assert_equal "The body paragraph.", post.excerpt
|
|
end
|
|
|
|
def test_derived_excerpt_strips_html_tags
|
|
body = "<strong>Bold</strong> and <em>italic</em>."
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" }, body: body)
|
|
assert_equal "Bold and italic.", post.excerpt
|
|
end
|
|
|
|
def test_summary_shape
|
|
post = Volumen::Post.new(metadata: { "slug" => "x", "title" => "X" }, body: "Body")
|
|
summary = post.summary
|
|
assert_equal "/api/volumen/posts/x", summary["url"]
|
|
assert_equal "X", summary["title"]
|
|
refute_predicate post, :draft?
|
|
end
|
|
|
|
def test_detail_includes_rendered_html
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" }, body: "**hi**")
|
|
assert_includes post.detail["html"], "<strong>hi</strong>"
|
|
end
|
|
|
|
def test_summary_includes_cover_and_reading_time
|
|
post = Volumen::Post.new(
|
|
metadata: { "slug" => "x", "cover" => "/media/c.png" },
|
|
body: ("word " * 250)
|
|
)
|
|
assert_equal "/media/c.png", post.summary["cover"]
|
|
assert_equal 2, post.summary["reading_time"]
|
|
end
|
|
|
|
def test_reading_time_is_at_least_one
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" }, body: "short")
|
|
assert_equal 1, post.reading_time
|
|
end
|
|
|
|
def test_scheduled_post_is_not_scheduled_when_publish_at_is_past
|
|
post = Volumen::Post.new(metadata: { "publish_at" => Date.today - 1 })
|
|
refute_predicate post, :scheduled?
|
|
end
|
|
|
|
def test_scheduled_post_is_scheduled_when_publish_at_is_future
|
|
post = Volumen::Post.new(metadata: { "publish_at" => Date.today + 7 })
|
|
assert_predicate post, :scheduled?
|
|
end
|
|
|
|
def test_post_without_publish_at_is_not_scheduled
|
|
post = Volumen::Post.new(metadata: {})
|
|
refute_predicate post, :scheduled?
|
|
end
|
|
|
|
def test_fediverse_creator_returns_metadata_value
|
|
post = Volumen::Post.new(
|
|
metadata: { "slug" => "x", "fediverse_creator" => "@user@example.social" }
|
|
)
|
|
assert_equal "@user@example.social", post.fediverse_creator
|
|
end
|
|
|
|
def test_fediverse_creator_is_nil_when_missing
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" })
|
|
assert_nil post.fediverse_creator
|
|
end
|
|
|
|
def test_fediverse_creator_is_nil_when_blank
|
|
post = Volumen::Post.new(metadata: { "slug" => "x", "fediverse_creator" => " " })
|
|
assert_nil post.fediverse_creator
|
|
end
|
|
|
|
def test_fediverse_creator_validation_accepts_well_formed_handles
|
|
post = Volumen::Post.new(
|
|
metadata: { "slug" => "x", "fediverse_creator" => "@ada@lovelace.org" }
|
|
)
|
|
assert_predicate post, :valid_fediverse_creator?
|
|
end
|
|
|
|
def test_fediverse_creator_validation_rejects_malformed_handles
|
|
[
|
|
"ada@example.com",
|
|
"@only-one-at",
|
|
"@user@example.com extra",
|
|
"@user@",
|
|
"@@example.com"
|
|
].each do |value|
|
|
post = Volumen::Post.new(metadata: { "slug" => "x", "fediverse_creator" => value })
|
|
refute_predicate post, :valid_fediverse_creator?, "expected #{value.inspect} to be invalid"
|
|
end
|
|
end
|
|
|
|
def test_fediverse_creator_validation_accepts_padded_value
|
|
post = Volumen::Post.new(
|
|
metadata: { "slug" => "x", "fediverse_creator" => " @user@example.com " }
|
|
)
|
|
assert_predicate post, :valid_fediverse_creator?
|
|
end
|
|
|
|
def test_summary_includes_fediverse_creator
|
|
post = Volumen::Post.new(
|
|
metadata: { "slug" => "x", "fediverse_creator" => "@user@example.social" },
|
|
body: "body"
|
|
)
|
|
assert_equal "@user@example.social", post.summary["fediverse_creator"]
|
|
end
|
|
|
|
def test_summary_omits_fediverse_creator_when_absent
|
|
post = Volumen::Post.new(metadata: { "slug" => "x" }, body: "body")
|
|
assert_nil post.summary["fediverse_creator"]
|
|
end
|
|
end
|