use super::*;
#[test]
fn insert_literal_name_for_unknown_header_without_prior_entry() {
let table = new_table(4096);
let abs = table.insert(qen("x-custom"), fv("hello")).unwrap();
assert_eq!(abs, 0);
assert_eq!(table.insert_count(), 1);
assert_eq!(
drain_instructions(&table),
vec![
EncoderInstruction::SetCapacity(4096),
EncoderInstruction::InsertWithLiteralName {
name: qen("x-custom"),
value: b"hello".to_vec(),
},
]
);
}
#[test]
fn insert_roundtrips_through_decoder_as_literal_name() {
let table = new_table(4096);
table.insert(qen("x-custom"), fv("hello")).unwrap();
let decoder = apply_ops_to_decoder(&table, 4096);
assert_eq!(decoder.name_at_relative(0).unwrap().as_ref(), "x-custom");
}
#[test]
fn insert_rejects_entry_exceeding_capacity() {
let table = new_table(64);
let big = fvo(vec![b'x'; 64]);
assert!(table.insert(qen("n"), big).is_err());
}
#[test]
fn literal_name_inserts_evict_oldest_when_unpinned() {
let table = new_table(70);
table.insert(qen("a"), fv("1")).unwrap();
table.insert(qen("b"), fv("2")).unwrap();
assert_eq!(table.entry_count(), 2);
table.insert(qen("c"), fv("3")).unwrap();
assert_eq!(table.insert_count(), 3);
assert_eq!(table.entry_count(), 2);
assert_eq!(table.find_name_match(&qen("a")), None);
assert!(table.find_name_match(&qen("b")).is_some());
assert!(table.find_name_match(&qen("c")).is_some());
}
#[test]
fn insert_known_header_with_static_slot_chooses_static_name_ref() {
let table = new_table(4096);
table
.insert(KnownHeaderName::AcceptEncoding.into(), fv("identity"))
.unwrap();
let instrs = drain_instructions(&table);
assert!(matches!(
instrs.as_slice(),
[
EncoderInstruction::SetCapacity(_),
EncoderInstruction::InsertWithStaticNameRef { value, .. },
] if value == b"identity"
));
}
#[test]
fn insert_pseudo_header_with_static_slot_chooses_static_name_ref() {
let table = new_table(4096);
table.insert(qen(":path"), fv("/api/users")).unwrap();
let instrs = drain_instructions(&table);
assert!(matches!(
instrs.as_slice(),
[
EncoderInstruction::SetCapacity(_),
EncoderInstruction::InsertWithStaticNameRef {
name_index: 1,
value,
},
] if value == b"/api/users"
));
}
#[test]
fn insert_pseudo_header_without_static_slot_uses_literal_name() {
let table = new_table(4096);
table.insert(qen(":protocol"), fv("webtransport")).unwrap();
let instrs = drain_instructions(&table);
assert!(matches!(
&instrs[..],
[
EncoderInstruction::SetCapacity(_),
EncoderInstruction::InsertWithLiteralName { name, value },
] if name == &qen(":protocol") && value == b"webtransport"
));
}
#[test]
fn insert_second_value_for_unknown_name_chooses_dynamic_name_ref() {
let table = new_table(4096);
table.insert(qen("x-custom"), fv("first")).unwrap();
let abs = table.insert(qen("x-custom"), fv("second")).unwrap();
assert_eq!(abs, 1);
let instrs = drain_instructions(&table);
assert_eq!(instrs.len(), 3);
assert!(matches!(instrs[0], EncoderInstruction::SetCapacity(_)));
assert!(matches!(
instrs[1],
EncoderInstruction::InsertWithLiteralName { .. }
));
assert!(matches!(
&instrs[2],
EncoderInstruction::InsertWithDynamicNameRef { relative_index: 0, value }
if value == b"second"
));
}
#[test]
fn dynamic_name_ref_insert_preserves_source_when_capacity_tight() {
let table = new_table(34);
table.insert(qen("a"), fv("1")).unwrap();
assert!(table.insert(qen("a"), fv("2")).is_err());
assert_eq!(table.entry_count(), 1);
assert_eq!(table.find_full_match(&qen("a"), b"1"), Some(0));
}
#[test]
fn second_insert_of_same_name_value_chooses_duplicate() {
let table = new_table(4096);
table.insert(qen("x-custom"), fv("hello")).unwrap();
let second = table.insert(qen("x-custom"), fv("hello")).unwrap();
assert_eq!(second, 1);
assert_eq!(table.insert_count(), 2);
assert_eq!(table.entry_count(), 2);
let instrs = drain_instructions(&table);
assert_eq!(instrs.len(), 3);
assert!(matches!(
instrs[2],
EncoderInstruction::Duplicate { relative_index: 0 }
));
}
#[test]
fn duplicate_is_chosen_even_when_static_name_ref_is_available() {
let table = new_table(4096);
table
.insert(KnownHeaderName::ContentType.into(), fv("application/json"))
.unwrap();
table
.insert(KnownHeaderName::ContentType.into(), fv("application/json"))
.unwrap();
let instrs = drain_instructions(&table);
assert!(matches!(
instrs[1],
EncoderInstruction::InsertWithStaticNameRef { .. }
));
assert!(matches!(
instrs[2],
EncoderInstruction::Duplicate { relative_index: 0 }
));
}
#[test]
fn duplicate_picks_matching_entry_across_multiple_names() {
let table = new_table(4096);
table.insert(qen("a"), fv("1")).unwrap();
table.insert(qen("b"), fv("1")).unwrap();
let third = table.insert(qen("a"), fv("1")).unwrap();
assert_eq!(third, 2);
let instrs = drain_instructions(&table);
assert_eq!(instrs.len(), 4);
assert_eq!(
instrs[3],
EncoderInstruction::Duplicate { relative_index: 1 }
);
}
#[test]
fn duplicate_source_remains_live_after_duplicate() {
let table = new_table(4096);
let first = table.insert(qen("x-custom"), fv("hello")).unwrap();
let second = table.insert(qen("x-custom"), fv("hello")).unwrap();
assert_eq!((first, second), (0, 1));
assert_eq!(table.entry_count(), 2);
assert_eq!(
table.find_full_match(&qen("x-custom"), b"hello"),
Some(second)
);
}
#[test]
fn duplicate_fails_when_capacity_only_fits_one_entry() {
let table = new_table(34);
table.insert(qen("a"), fv("1")).unwrap();
assert!(table.insert(qen("a"), fv("1")).is_err());
assert_eq!(table.entry_count(), 1);
}
#[test]
fn duplicate_succeeds_when_capacity_fits_two_entries() {
let table = new_table(68);
table.insert(qen("a"), fv("1")).unwrap();
table.insert(qen("a"), fv("1")).unwrap();
assert_eq!(table.entry_count(), 2);
let instrs = drain_instructions(&table);
assert!(matches!(
instrs[2],
EncoderInstruction::Duplicate { relative_index: 0 }
));
}
#[test]
fn roundtrip_static_name_ref_insert() {
let table = new_table(4096);
table
.insert(KnownHeaderName::AcceptEncoding.into(), fv("identity"))
.unwrap();
let decoder = apply_ops_to_decoder(&table, 4096);
assert_eq!(
decoder.name_at_relative(0).unwrap().as_ref(),
"accept-encoding"
);
}
#[test]
fn roundtrip_dynamic_name_ref_insert() {
let table = new_table(4096);
table.insert(qen("x-custom"), fv("first")).unwrap();
table.insert(qen("x-custom"), fv("second")).unwrap();
let decoder = apply_ops_to_decoder(&table, 4096);
assert_eq!(decoder.name_at_relative(0).unwrap().as_ref(), "x-custom");
assert_eq!(decoder.name_at_relative(1).unwrap().as_ref(), "x-custom");
}
#[test]
fn roundtrip_duplicate() {
let table = new_table(4096);
table.insert(qen("x-custom"), fv("hello")).unwrap();
table.insert(qen("x-custom"), fv("hello")).unwrap();
let decoder = apply_ops_to_decoder(&table, 4096);
assert_eq!(decoder.name_at_relative(0).unwrap().as_ref(), "x-custom");
assert_eq!(decoder.name_at_relative(1).unwrap().as_ref(), "x-custom");
}
#[test]
fn roundtrip_pseudo_header_without_static_slot() {
let table = new_table(4096);
table
.insert(
EntryName::Pseudo(PseudoHeaderName::Protocol),
fv("webtransport"),
)
.unwrap();
let decoder = apply_ops_to_decoder(&table, 4096);
assert_eq!(decoder.name_at_relative(0).unwrap().as_ref(), ":protocol");
}