mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
Move Minitest files from spec/ to test/ and update bake tasks to discover and run tests from test/**/*_test.rb. Update README and AGENTS guidance to reference test/ and tests, and drop the obsolete spec/examples.txt ignore entry.
147 lines
4.3 KiB
Ruby
147 lines
4.3 KiB
Ruby
require "test_helper"
|
|
require "tmpdir"
|
|
|
|
class Pressa::Config::SimpleTomlTest < Minitest::Test
|
|
def parser
|
|
@parser ||= Pressa::Config::SimpleToml.new
|
|
end
|
|
|
|
def test_load_file_raises_parse_error_for_missing_file
|
|
Dir.mktmpdir do |dir|
|
|
missing = File.join(dir, "missing.toml")
|
|
|
|
error = assert_raises(Pressa::Config::ParseError) do
|
|
Pressa::Config::SimpleToml.load_file(missing)
|
|
end
|
|
|
|
assert_match(/Config file not found/, error.message)
|
|
end
|
|
end
|
|
|
|
def test_parse_supports_tables_array_tables_comments_and_multiline_arrays
|
|
content = <<~TOML
|
|
title = "samhuri # not a comment"
|
|
[projects_plugin]
|
|
scripts = ["js/a.js", "js/b.js"]
|
|
styles = [
|
|
"css/a.css",
|
|
"css/b.css"
|
|
]
|
|
|
|
[[projects]]
|
|
name = "alpha"
|
|
title = "Alpha"
|
|
description = "Project Alpha"
|
|
url = "https://github.com/samsonjs/alpha"
|
|
|
|
[[projects]]
|
|
name = "beta"
|
|
title = "Beta"
|
|
description = "Project Beta"
|
|
url = "https://github.com/samsonjs/beta"
|
|
TOML
|
|
|
|
parsed = parser.parse(content)
|
|
|
|
assert_equal("samhuri # not a comment", parsed["title"])
|
|
assert_equal(["js/a.js", "js/b.js"], parsed.dig("projects_plugin", "scripts"))
|
|
assert_equal(["css/a.css", "css/b.css"], parsed.dig("projects_plugin", "styles"))
|
|
assert_equal(2, parsed["projects"].length)
|
|
assert_equal("alpha", parsed["projects"][0]["name"])
|
|
assert_equal("beta", parsed["projects"][1]["name"])
|
|
end
|
|
|
|
def test_parse_rejects_duplicate_keys
|
|
content = <<~TOML
|
|
author = "Sami"
|
|
author = "Sam"
|
|
TOML
|
|
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
|
assert_match(/Duplicate key 'author'/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_invalid_assignment
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse("invalid") }
|
|
assert_match(/Invalid assignment/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_invalid_key_names
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse("bad-key = 1") }
|
|
assert_match(/Invalid key/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_missing_value
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse("author = ") }
|
|
assert_match(/Missing value for key 'author'/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_invalid_table_paths
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse("[projects..plugin]") }
|
|
assert_match(/Invalid table path/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_array_table_when_table_already_exists
|
|
content = <<~TOML
|
|
[projects]
|
|
title = "single"
|
|
[[projects]]
|
|
title = "array item"
|
|
TOML
|
|
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
|
assert_match(/Expected array for '\[\[projects\]\]'/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_nested_table_on_non_table_path
|
|
content = <<~TOML
|
|
projects = 1
|
|
[projects.plugin]
|
|
enabled = true
|
|
TOML
|
|
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
|
assert_match(/Expected table path 'projects.plugin'/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_unsupported_value_types
|
|
error = assert_raises(Pressa::Config::ParseError) do
|
|
parser.parse("published_at = 2025-01-01")
|
|
end
|
|
|
|
assert_match(/Unsupported TOML value/, error.message)
|
|
end
|
|
|
|
def test_parse_rejects_unterminated_multiline_value
|
|
content = <<~TOML
|
|
scripts = [
|
|
"a.js",
|
|
"b.js"
|
|
TOML
|
|
|
|
error = assert_raises(Pressa::Config::ParseError) { parser.parse(content) }
|
|
assert_match(/Unterminated value for key 'scripts'/, error.message)
|
|
end
|
|
|
|
def test_parse_ignores_comments_but_not_hashes_inside_strings
|
|
content = <<~TOML
|
|
url = "https://example.com/#anchor" # remove me
|
|
TOML
|
|
|
|
parsed = parser.parse(content)
|
|
assert_equal("https://example.com/#anchor", parsed["url"])
|
|
end
|
|
|
|
def test_private_parsing_helpers_handle_escaped_quotes_inside_strings
|
|
refute(parser.send(:needs_continuation?, "\"a\\\\\\\"b\""))
|
|
|
|
stripped = parser.send(:strip_comments, "title = \"a\\\\\\\"b # keep\" # drop\n")
|
|
assert_equal("title = \"a\\\\\\\"b # keep\" ", stripped)
|
|
|
|
source = "\"a\\\\\\\"=b\" = 1"
|
|
index = parser.send(:index_of_unquoted, source, "=")
|
|
refute_nil(index)
|
|
assert_equal("=", source[index])
|
|
assert(index > source.rindex('"'))
|
|
end
|
|
end
|