// test_rfc8187.mbt — Tests for RFC 8187 extended parameter values (rfc8187.mbt).
///|
test "parse a basic UTF-8 extended value" {
let ev = unwrap_ok(parse_extended_value_string("UTF-8'en'hello"))
assert_str_eq(ev.charset(), "UTF-8")
match ev.language() {
Some(l) => assert_str_eq(l, "en")
None => fail("language missing")
}
assert_str_eq(ev.value(), "hello")
}
///|
test "parse an extended value without a language" {
let ev = unwrap_ok(parse_extended_value_string("UTF-8''hello"))
assert_true(ev.language() is None)
assert_str_eq(ev.value(), "hello")
}
///|
test "percent-encoded bytes decode to the underlying UTF-8" {
let ev = unwrap_ok(parse_extended_value_string("UTF-8''caf%C3%A9"))
assert_str_eq(ev.value(), "café")
}
///|
test "percent-encoded multi-byte characters decode correctly" {
let ev = unwrap_ok(parse_extended_value_string("UTF-8''%E2%82%AC"))
assert_str_eq(ev.value(), "€")
}
///|
test "charset matching is case-insensitive" {
let ev = unwrap_ok(parse_extended_value_string("utf-8'en'hello"))
assert_str_eq(ev.charset(), "UTF-8")
}
///|
test "unsupported charset is rejected" {
expect_err_kind(
parse_extended_value_string("ISO-8859-1'en'hello"),
UnsupportedCharset,
)
}
///|
test "malformed percent-encoding is rejected" {
expect_err_kind(
parse_extended_value_string("UTF-8''%ZZ"),
InvalidPercentEncoding,
)
expect_err_kind(
parse_extended_value_string("UTF-8''%4"),
InvalidPercentEncoding,
)
expect_err_kind(
parse_extended_value_string("UTF-8''%"),
InvalidPercentEncoding,
)
}
///|
test "percent-decoded bytes that are not UTF-8 are rejected" {
expect_err_kind(parse_extended_value_string("UTF-8''%FF"), InvalidUtf8)
}
///|
test "invalid language tag is rejected" {
expect_err_kind(
parse_extended_value_string("UTF-8'e'hello"),
InvalidLanguageTag,
)
expect_err_kind(
parse_extended_value_string("UTF-8'1en'hello"),
InvalidLanguageTag,
)
}
///|
test "missing apostrophe after charset is rejected" {
expect_err_kind(
parse_extended_value_string("UTF-8hello"),
UnexpectedCharacter,
)
}
///|
test "missing apostrophe after language is rejected" {
expect_err_kind(
parse_extended_value_string("UTF-8'enhello"),
UnexpectedCharacter,
)
}
///|
test "empty value is allowed" {
let ev = unwrap_ok(parse_extended_value_string("UTF-8''"))
assert_str_eq(ev.value(), "")
assert_true(ev.language() is None)
}
///|
test "trailing bytes after the value are rejected" {
expect_err_kind(
parse_extended_value_string("UTF-8''hello extra"),
TrailingInput,
)
}
///|
test "serialize_extended_value emits uppercase percent-encoding" {
let ev = { charset: "UTF-8", language: None, value: "café" }
assert_str_eq(serialize_extended_value(ev), "UTF-8''caf%C3%A9")
}
///|
test "serialize_extended_value round-trips through the parser" {
let ev = { charset: "UTF-8", language: Some("en"), value: "a b/c" }
let s = serialize_extended_value(ev)
assert_str_eq(s, "UTF-8'en'a%20b%2Fc")
let parsed = unwrap_ok(parse_extended_value_string(s))
assert_str_eq(parsed.value(), "a b/c")
match parsed.language() {
Some(l) => assert_str_eq(l, "en")
None => fail("language missing")
}
}
///|
test "attr-char bytes are emitted unencoded" {
let ev = { charset: "UTF-8", language: None, value: "hello_world-1.2" }
assert_str_eq(serialize_extended_value(ev), "UTF-8''hello_world-1.2")
}
///|
test "valid_language_tag accepts well-formed tags" {
assert_true(valid_language_tag("en"))
assert_true(valid_language_tag("en-US"))
assert_true(valid_language_tag("sr-Latn-RS"))
assert_true(valid_language_tag("zh-Hans-CN"))
assert_true(valid_language_tag("x-private"))
assert_true(valid_language_tag("es-419"))
}
///|
test "valid_language_tag rejects malformed tags" {
assert_false(valid_language_tag(""))
assert_false(valid_language_tag("e"))
assert_false(valid_language_tag("123"))
assert_false(valid_language_tag("en-US-"))
assert_false(valid_language_tag("en_US"))
assert_false(valid_language_tag("averylongsubtagthatexceedslength"))
assert_false(valid_language_tag("en-123456789"))
}
///|
test "ext-value grammar integrates with the link parser" {
// The value may not contain whitespace, ";" or "," unencoded.
let links = unwrap_ok(
parse_link_header(
"; rel=\"next\"; title*=UTF-8'en'hello%20world",
Limits::default(),
),
)
match links[0].title_star() {
Some(ev) => assert_str_eq(ev.value(), "hello world")
None => fail("title* missing")
}
}
///|
test "multiple title* occurrences are first-wins and recorded" {
let parsed = unwrap_ok(
parse_link_header_detailed(
"; rel=\"next\"; title*=UTF-8'en'a; title*=UTF-8'de'b",
Limits::default(),
),
)
match parsed.links()[0].title_star() {
Some(ev) => assert_str_eq(ev.value(), "a")
None => fail("title* missing")
}
assert_str_eq(parsed.duplicates()[0], "title*")
}