libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

commit be38f8db9f360db676c2820a22f19e66ef662f5d
parent eae6148bfc29daa9ee8c29798f552d7f2f3f9b22
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date:   Wed,  1 Oct 2025 23:24:14 +0200

Implemented HPACK tables unit testing

Diffstat:
Msrc/tests/unit/Makefile.am | 14++++++++++++++
Asrc/tests/unit/unit_hpack_tables.c | 2546+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 2560 insertions(+), 0 deletions(-)

diff --git a/src/tests/unit/Makefile.am b/src/tests/unit/Makefile.am @@ -1,4 +1,5 @@ # This Makefile.am is in the public domain +# src/tests/unit/Makefile.am EMPTY_ITEM = H2_SRC_DIR = $(srcdir)/../../mhd2/h2 @@ -32,6 +33,9 @@ if MHD_SUPPORT_HTTP2 check_PROGRAMS += \ unit_h2_huffman_encode \ unit_h2_huffman_decode \ + unit_hpack_tables_dynamic \ + unit_hpack_tables_static \ + unit_hpack_tables_combined \ $(EMPTY_ITEM) endif @@ -44,3 +48,13 @@ unit_h2_huffman_encode_SOURCES = \ $(HPACK_SRC_DIR)/h2_huffman_codec.c unit_h2_huffman_decode_SOURCES = $(unit_h2_huffman_encode_SOURCES) + +unit_hpack_tables_dynamic_SOURCES = \ + unit_hpack_tables.c \ + $(srcdir)/../mhdt_has_in_name.h \ + $(srcdir)/../mhdt_has_param.h \ + $(srcdir)/../mhdt_checks.h + +unit_hpack_tables_static_SOURCES = $(unit_hpack_tables_dynamic_SOURCES) + +unit_hpack_tables_combined_SOURCES = $(unit_hpack_tables_dynamic_SOURCES) diff --git a/src/tests/unit/unit_hpack_tables.c b/src/tests/unit/unit_hpack_tables.c @@ -0,0 +1,2546 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ +/* + This file is part of GNU libmicrohttpd. + Copyright (C) 2025 Evgeny Grin (Karlson2k) + + GNU libmicrohttpd is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + GNU libmicrohttpd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + Alternatively, you can redistribute GNU libmicrohttpd and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version, together + with the eCos exception, as follows: + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile this + file and link it with other works to produce a work based on this + file, this file does not by itself cause the resulting work to be + covered by the GNU General Public License. However the source code + for this file must still be made available in accordance with + section (3) of the GNU General Public License v2. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + + You should have received copies of the GNU Lesser General Public + License and the GNU General Public License along with this library; + if not, see <https://www.gnu.org/licenses/>. +*/ + +/** + * @file src/test/unit/unit_hpack_tables.c + * @brief The tests for HPACK tables functions + * @author Karlson2k (Evgeny Grin) + */ + + +#include "mhd_sys_options.h" + +#define mhd_HPACK_TESTING_TABLES_ONLY 1 +/* Include .c file (!) to access static functions. + Only official interface mhd_* is used to handle the tables. */ +#include "h2/hpack/mhd_hpack_codec.c" + +#include "mhdt_has_in_name.h" +#include "mhdt_has_param.h" +#include "mhdt_checks.h" + +#ifndef MHD_ENABLE_SLOW_TESTS +static int mhdtl_enable_deep_tests = 0; +#else +static int mhdtl_enable_deep_tests = ! 0; +#endif + +#define MHDTL_DYN_ENTRY_MIN_SIZE mhd_HPACK_ENTRY_OVERHEAD + +/* + * Local test helpers + */ + +#define MHDTL_HPACK_ENTRY_SIZE(name_len,val_len) \ + (name_len + val_len + mhd_HPACK_ENTRY_OVERHEAD) + + +static inline uint_least16_t +mhdtl_rotl16 (uint_least16_t val, unsigned int rot) +{ + return + (uint_least16_t) + (((val & 0xFFFFu) << (rot % 16u)) + | ((val & 0xFFFFu) >> ((16u - (rot % 16u)) % 16u))); +} + + +static inline uint_least16_t +mhdtl_mix16 (uint_fast16_t a, uint_fast16_t b) +{ + /* Mix with Golden Ratio's fractional part */ + uint_least16_t res = + (uint_least16_t) (((a & 0xFFFFu) * 0x9E37u) + ^ mhdtl_rotl16 ((uint_least16_t) b, 5)); + /* Re-mix bits better */ + res ^= (uint_least16_t) (res >> 7); + res = (uint_least16_t) ((res * 0x9E37u) & 0xFFFFu); + res ^= (uint_least16_t) (res >> 9); + + return res; +} + + +static size_t +mhdtl_dyn_get_size_used (const struct mhd_HpackDTblContext *dyn) +{ + const size_t used = mhd_dtbl_get_table_used (dyn); + MHDT_EXPECT_UINT_GE_VAL (mhd_dtbl_get_table_max_size (dyn), \ + used); + return used; +} + + +static size_t +mhdtl_dyn_get_free (const struct mhd_HpackDTblContext *dyn) +{ + const size_t used = mhd_dtbl_get_table_used (dyn); + const size_t max_size = mhd_dtbl_get_table_max_size (dyn); + MHDT_EXPECT_UINT_GE_VAL (max_size, used); + return max_size - used; +} + + +#define MHDTL_DTBL_FIND_ENTRY_STR(dyn,name,val) \ + mhd_dtbl_find_entry (dyn, strlen (name), name, strlen (val), val) + +#define MHDTL_DTBL_FIND_NAME_STR(dyn,name) \ + mhd_dtbl_find_name (dyn, strlen (name), name) + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_dyn_check_get_valid_invalid (const struct mhd_HpackDTblContext *dyn) +{ + const dtbl_idx_ft num_entries = (dtbl_idx_t) mhd_dtbl_get_num_entries (dyn); + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + if (! MHDT_EXPECT_FALSE_D (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 1u \ + + num_entries, \ + &check_name, \ + &check_value), \ + "getting entry with the index outside valid " + "range should fail")) + return 0; + + if (0u == num_entries) + return ! 0; + + if (! MHDT_EXPECT_TRUE_D (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 1u, \ + &check_name, \ + &check_value), \ + "non-empty table should return successfully " \ + "the first valid entry")) + return 0; + if (! MHDT_EXPECT_TRUE_D (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX \ + + num_entries, \ + &check_name, \ + &check_value), \ + "non-empty table should return successfully " \ + "the last valid entry")) + return 0; + + return ! 0; +} + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_dyn_check_entry_n_at_idx (struct mhd_HpackDTblContext *dyn, + size_t idx, + size_t expect_name_len, + const char *expect_name, + size_t expect_value_len, + const char *expect_value) +{ + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + dtbl_idx_t idx_idx = (dtbl_idx_t) idx; + if (0 == idx) + MHDT_ERR_EXIT (); + if (idx_idx != idx) + MHDT_ERR_EXIT (); + + if (MHDT_EXPECT_TRUE_D (mhd_dtbl_get_entry (dyn, \ + idx_idx, \ + &check_name, \ + &check_value), \ + "the entry with specified index should exist")) + { + MHDT_EXPECT_STRN_EQ_STR_D (check_name.size, \ + check_name.data, \ + expect_name, \ + "the name of the entry should match " \ + "expected value"); + MHDT_EXPECT_STRN_EQ_STR_D (check_value.size, \ + check_value.data, \ + expect_value, \ + "the name of the entry should match " \ + "expected value"); + } + else + return 0; + + /* It should be possible to find the entry. The index could be different + if entries are duplicated. */ + + MHDT_EXPECT_UINT_GT_VAL_D (mhd_dtbl_find_entry (dyn, \ + expect_name_len, \ + expect_name, \ + expect_value_len, \ + expect_value), \ + mhd_HPACK_STBL_LAST_IDX, \ + "search by known entry name and value " \ + "should succeed"); + MHDT_EXPECT_UINT_GT_VAL_D (mhd_dtbl_find_name (dyn, \ + expect_name_len, \ + expect_name), \ + mhd_HPACK_STBL_LAST_IDX, \ + "search by known entry name " \ + "should succeed"); + + return ! 0; +} + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_dyn_check_entry_at_idx (struct mhd_HpackDTblContext *dyn, + size_t idx, + const char *expect_name, + const char *expect_value) +{ + return mhdtl_dyn_check_entry_n_at_idx (dyn, + idx, + strlen (expect_name), + expect_name, + strlen (expect_value), + expect_value); +} + + +/* Return non-zero if succeeded, zero if failed */ +static MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_IN_SIZE_ (5,4) int +mhdtl_dyn_add_hdr_n_with_check (struct mhd_HpackDTblContext *dyn, + size_t hdr_name_len, + const char *hdr_name, + size_t hdr_value_len, + const char *hdr_value) +{ + char prev_name_buf[512]; + size_t prev_name_len = 0u; + char prev_val_buf[512]; + size_t prev_val_len = 0u; + int have_prev_entry = 0; + char last_name_buf[512]; + size_t last_name_len = 0u; + char last_val_buf[512]; + size_t last_val_len = 0u; + int have_last_entry = 0; + const size_t hdr_size = MHDTL_HPACK_ENTRY_SIZE (hdr_name_len, hdr_value_len); + const size_t table_max_size = mhd_dtbl_get_table_max_size (dyn); + const size_t table_free_before = mhdtl_dyn_get_free (dyn); + const dtbl_idx_ft num_entries_before = (dtbl_idx_t) + mhd_dtbl_get_num_entries (dyn); + struct mhd_BufferConst check_name = {0u, NULL}; + struct mhd_BufferConst check_value = {0u, NULL}; + + if ((mhd_DTBL_MAX_SIZE < hdr_name_len) || + (mhd_DTBL_MAX_SIZE < hdr_value_len) || + (mhd_DTBL_MAX_SIZE < hdr_size)) + MHDT_ERR_EXIT (); + + MHDT_EXPECT_UINT_GE_VAL (table_max_size, table_free_before); + MHDT_EXPECT_UINT_GE_VAL_D (mhdtl_dyn_get_size_used (dyn), \ + num_entries_before * MHDTL_DYN_ENTRY_MIN_SIZE, \ + "Each entry should have at least a minimal size"); + + if (mhd_dtbl_get_entry (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + &check_name, &check_value)) + { /* Check whether the current newest entry and the new entry will fit + the table together */ + if (hdr_size + MHDTL_HPACK_ENTRY_SIZE (check_name.size, check_value.size) + <= mhd_dtbl_get_table_max_size (dyn)) + { + if ((sizeof(prev_name_buf) > check_name.size) + && (sizeof(prev_val_buf) > check_value.size)) + { + /* Save the first entry to check later that it is not changed after + adding the new entry */ + memcpy (prev_name_buf, + check_name.data, + check_name.size); + prev_name_buf[check_name.size] = 0; /* Zero-terminate for convenience */ + prev_name_len = check_name.size; + memcpy (prev_val_buf, + check_value.data, + check_value.size); + prev_val_buf[check_value.size] = 0; /* Zero-terminate for convenience */ + prev_val_len = check_value.size; + have_prev_entry = ! 0; + } + } + } + if ((1u < mhd_dtbl_get_num_entries (dyn)) + && (hdr_size <= table_free_before)) + { + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, + mhd_HPACK_STBL_LAST_IDX + + num_entries_before, + &check_name, &check_value))) + { + if ((sizeof(last_name_buf) > check_name.size) + && (sizeof(last_val_buf) > check_value.size)) + { + /* Save the last entry to check later that it is not changed after + adding the new entry */ + memcpy (last_name_buf, + check_name.data, + check_name.size); + last_name_buf[check_name.size] = 0; /* Zero-terminate for convenience */ + last_name_len = check_name.size; + memcpy (last_val_buf, + check_value.data, + check_value.size); + last_val_buf[check_value.size] = 0; /* Zero-terminate for convenience */ + last_val_len = check_value.size; + have_last_entry = ! 0; + } + } + } + + mhd_dtbl_new_entry (dyn, + hdr_name_len, + hdr_name, + hdr_value_len, + hdr_value); + + if (hdr_size <= table_free_before) + { + /* No eviction */ + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_dtbl_get_num_entries (dyn), \ + num_entries_before + 1u, \ + "added one entry without eviction"); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_free (dyn), \ + table_free_before - hdr_size); + if (have_last_entry) + mhdtl_dyn_check_entry_n_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + + num_entries_before + 1u, + last_name_len, + last_name_buf, + last_val_len, + last_val_buf); + } + else + { + /* Eviction */ + MHDT_EXPECT_UINT_LE_VAL_D (mhd_dtbl_get_num_entries (dyn), \ + num_entries_before, + "some entries evicted when adding new entry"); + if (hdr_size > table_max_size) + { + /* Full eviction */ + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_dtbl_get_num_entries (dyn), 0u, \ + "all entries evicted by adding too large " \ + "new entry"); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_free (dyn), table_max_size); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), \ + table_max_size); + return ! 0; + } + else if (hdr_size + MHDTL_DYN_ENTRY_MIN_SIZE > table_max_size) + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_dtbl_get_num_entries (dyn), 1u, \ + "exactly one new entry fits the table"); + else + MHDT_EXPECT_UINT_GE_VAL_D (mhd_dtbl_get_num_entries (dyn), 1u, + "some entries evicted and one entry added"); + + } + + /* The new entry has been added to the table */ + + if (1u == mhd_dtbl_get_num_entries (dyn)) + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), hdr_size); + else + MHDT_EXPECT_UINT_GE_VAL (mhdtl_dyn_get_size_used (dyn), \ + hdr_size + MHDTL_DYN_ENTRY_MIN_SIZE); + + if (! MHDT_EXPECT_TRUE_D (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 1u, \ + &check_name, \ + &check_value), \ + "new entry should be available as the newest " \ + "entry in the dynamic table")) + return 0; + + if (! MHDT_EXPECT_STRN_EQ_D (check_name.size, \ + check_name.data, \ + hdr_name_len, \ + hdr_name, \ + "The name of the newest entry should " \ + "match the last added entry's name")) + return 0; + if (! MHDT_EXPECT_STRN_EQ_D (check_value.size, \ + check_value.data, \ + hdr_value_len, \ + hdr_value, \ + "The value of the newest entry should " \ + "match the last added entry's value")) + return 0; + + if (! MHDT_EXPECT_UINT_GT_VAL_D (mhd_dtbl_find_entry (dyn, \ + hdr_name_len, \ + hdr_name, \ + hdr_value_len, \ + hdr_value), \ + mhd_HPACK_STBL_LAST_IDX, \ + "search for the newly added entry should " \ + "be successful")) + return 0; + if (! MHDT_EXPECT_UINT_GT_VAL_D (mhd_dtbl_find_name (dyn, \ + hdr_name_len, \ + hdr_name), \ + mhd_HPACK_STBL_LAST_IDX, \ + "search for the newly added entry name " + "should be successful")) + return 0; + + if (have_prev_entry) + { + if (MHDT_EXPECT_TRUE_D (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 2u, \ + &check_name, &check_value), \ + "previous entry must remain the same")) + { + MHDT_EXPECT_STRN_EQ_D (check_name.size, check_name.data, \ + prev_name_len, prev_name_buf, \ + "previous entry must be unchanged"); + MHDT_EXPECT_STRN_EQ_D (check_value.size, check_value.data, \ + prev_val_len, prev_val_buf, \ + "previous entry must be unchanged"); + } + } + + + mhdtl_dyn_check_get_valid_invalid (dyn); + + return ! 0; +} + + +/* Return non-zero if succeeded, zero if failed */ +static MHD_FN_PAR_CSTR_ (2) MHD_FN_PAR_CSTR_ (3) int +mhdtl_dyn_add_hdr_with_check (struct mhd_HpackDTblContext *dyn, + const char *hdr_name, + const char *hdr_value) +{ + const size_t hdr_name_len = strlen (hdr_name); + const size_t hdr_value_len = strlen (hdr_value); + + return mhdtl_dyn_add_hdr_n_with_check (dyn, + hdr_name_len, + hdr_name, + hdr_value_len, + hdr_value); +} + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_dyn_add_sized_strs_with_check (struct mhd_HpackDTblContext *dyn, + size_t hdr_strings_size) +{ +#define MHDTL_NAMES_BUF_SIZE 512 + static char names[MHDTL_NAMES_BUF_SIZE] = ""; + static char values[MHDTL_NAMES_BUF_SIZE] = ""; +#undef MHDTL_NAMES_BUF_SIZE + /* Use '- 1u' to have valid addresses for zero-sized names and values */ + static const size_t bufs_size = sizeof(names) - 1u; + static size_t names_off = 0u; + static size_t values_off = 0u; + size_t name_size; + size_t value_size; + char *hdr_name; + char *hdr_value; + + if ((bufs_size + bufs_size) < hdr_strings_size) + MHDT_ERR_EXIT_D ("the entry must not be larger than a hardcoded limit"); + + if (0 == values[0]) + { + size_t i; + for (i = 0; i < sizeof(names); ++i) + { + names[i] = (char) ('a' + (char) (i % ('z' - 'a' + 1))); + values[i] = (char) (' ' + (char) ((bufs_size - i) % ('~' - ' ' + 1))); + } + } + + value_size = hdr_strings_size / 2; + name_size = hdr_strings_size - value_size; + + hdr_name = + names + (names_off++) % (bufs_size - name_size + 1u); + hdr_value = + values + (bufs_size - value_size) + - ((values_off++) % (bufs_size - value_size + 1u)); + + return mhdtl_dyn_add_hdr_n_with_check (dyn, + name_size, + hdr_name, + value_size, + hdr_value); +} + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_dyn_add_sized_entry_with_check (struct mhd_HpackDTblContext *dyn, + size_t entry_size) +{ + if (MHDTL_DYN_ENTRY_MIN_SIZE > entry_size) + MHDT_ERR_EXIT_D ("the entry must be at least a minimal entry size"); + + return mhdtl_dyn_add_sized_strs_with_check (dyn, + entry_size + - mhd_HPACK_ENTRY_OVERHEAD); +} + + +static void +mhdtl_stat_check_entry_n_at_idx (size_t idx, + size_t expect_name_len, + const char *expect_name, + size_t expect_value_len, + const char *expect_value) +{ + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + dtbl_idx_t idx_idx = (dtbl_idx_t) idx; + if (0 == idx) + MHDT_ERR_EXIT (); + if (idx_idx != idx) + MHDT_ERR_EXIT (); + if (0u == idx) + MHDT_ERR_EXIT (); + if (mhd_HPACK_STBL_LAST_IDX < idx) + MHDT_ERR_EXIT (); + if (0u == expect_name_len) + MHDT_ERR_EXIT (); + if ((':' == expect_name[0]) != (idx < (mhd_HPACK_STBL_NORM_START_POS + 1u))) + MHDT_ERR_EXIT (); + + mhd_stbl_get_entry (idx_idx, + &check_name, + &check_value); + + MHDT_EXPECT_STRN_EQ_STR_D (check_name.size, \ + check_name.data, \ + expect_name, \ + "the name of the entry should match " \ + "expected value"); + MHDT_EXPECT_STRN_EQ_STR_D (check_value.size, \ + check_value.data, \ + expect_value, \ + "the name of the entry should match " \ + "expected value"); + + /* It should be possible to find the entry. The index could be different + if entries are duplicated. */ + + if (':' != expect_name[0]) + { + MHDT_EXPECT_UINT_NE_VAL_D (mhd_stbl_find_entry_real (expect_name_len, \ + expect_name, \ + expect_value_len, + expect_value), \ + 0u, \ + "search by known entry name and value " \ + "should not fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_stbl_find_entry_real (expect_name_len, \ + expect_name, \ + expect_value_len, + expect_value), \ + idx, \ + "search by known entry name and value " \ + "should return the " \ + "known entry index"); + + MHDT_EXPECT_UINT_NE_VAL_D (mhd_stbl_find_name_real (expect_name_len, \ + expect_name), \ + 0u, \ + "search by known entry name " \ + "should not fail"); + MHDT_EXPECT_UINT_LE_VAL_D (mhd_stbl_find_name_real (expect_name_len, \ + expect_name), \ + idx, \ + "search by known entry name " \ + "should return value not greater than the " \ + "known entry index"); + } + else + { + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_stbl_find_entry_real (expect_name_len, \ + expect_name, \ + expect_value_len, + expect_value), \ + 0u, \ + "search by pseudo-header entry name " \ + "and value should fail"); + + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_stbl_find_name_real (expect_name_len, \ + expect_name), \ + 0u, \ + "search by pseudo-header entry name " \ + "should fail"); + } +} + + +static void +mhdtl_stat_check_entry_at_idx (size_t idx, + const char *expect_name, + const char *expect_value) +{ + mhdtl_stat_check_entry_n_at_idx (idx, + strlen (expect_name), + expect_name, + strlen (expect_value), + expect_value); +} + + +#define MHDTL_STBL_FIND_ENTRY_REAL_STR(name,value) \ + mhd_stbl_find_entry_real (strlen (name),(name), \ + strlen (value),(value)) +#define MHDTL_STBL_FIND_NAME_REAL_STR(name) \ + mhd_stbl_find_name_real (strlen (name),(name)) + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_comb_check_entry_n_at_idx (struct mhd_HpackDTblContext *dyn, + size_t idx, + size_t expect_name_len, + const char *expect_name, + size_t expect_value_len, + const char *expect_value) +{ + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + dtbl_idx_t idx_idx = (dtbl_idx_t) idx; + dtbl_idx_t found_by_name_and_value; + dtbl_idx_t found_by_name_only; + if (0 == idx) + MHDT_ERR_EXIT (); + if (idx_idx != idx) + MHDT_ERR_EXIT (); + if ((':' == expect_name[0]) != (idx < (mhd_HPACK_STBL_NORM_START_POS + 1u))) + MHDT_ERR_EXIT_D ("pseudo-header entries are allowed only at first " \ + "static table positions"); + + if (MHDT_EXPECT_TRUE_D (mhd_htbl_get_entry (dyn, \ + idx_idx, \ + &check_name, \ + &check_value), \ + "the entry with specified index should exist")) + { + MHDT_EXPECT_STRN_EQ_STR_D (check_name.size, \ + check_name.data, \ + expect_name, \ + "the name of the entry should match " \ + "expected value"); + MHDT_EXPECT_STRN_EQ_STR_D (check_value.size, \ + check_value.data, \ + expect_value, \ + "the name of the entry should match " \ + "expected value"); + } + else + return 0; + + /* It should be possible to find the entry. */ + found_by_name_and_value = + mhd_htbl_find_entry_real (dyn, + expect_name_len, + expect_name, + expect_value_len, + expect_value); + found_by_name_only = + mhd_htbl_find_name_real (dyn, + expect_name_len, + expect_name); + + if ((0u == expect_name_len) || + (':' != expect_name[0])) + { + MHDT_EXPECT_UINT_NE_VAL_D (found_by_name_and_value, \ + 0u, \ + "search by known entry name and value " \ + "should not fail"); + MHDT_EXPECT_UINT_LE_VAL_D (found_by_name_and_value, \ + mhd_HPACK_STBL_LAST_IDX \ + + mhd_dtbl_get_num_entries (dyn), \ + "search by known entry name and value " \ + "should return a valid index number"); + if (mhd_HPACK_STBL_LAST_IDX >= idx) + MHDT_EXPECT_UINT_EQ_VAL_D (found_by_name_and_value, \ + idx, \ + "search by known entry name and value " \ + "should return the " \ + "known entry index"); + + + MHDT_EXPECT_UINT_NE_VAL_D (found_by_name_only, \ + 0u, \ + "search by known entry name " \ + "should not fail"); + MHDT_EXPECT_UINT_LE_VAL_D (found_by_name_only, \ + mhd_HPACK_STBL_LAST_IDX \ + + mhd_dtbl_get_num_entries (dyn), \ + "search by known entry name " \ + "should return a valid index number"); + /* The next check is not required by RFC, but guaranteed by implementation + design. */ + if (mhd_HPACK_STBL_LAST_IDX >= idx) + MHDT_EXPECT_UINT_LE_VAL_D (found_by_name_and_value, \ + mhd_HPACK_STBL_LAST_IDX, \ + "search by known static entry name " \ + "should return the " \ + "static table index"); + } + else + { + MHDT_EXPECT_UINT_EQ_VAL_D (found_by_name_and_value, \ + 0u, \ + "search by pseudo-header entry name " \ + "and value should fail"); + + MHDT_EXPECT_UINT_EQ_VAL_D (found_by_name_only, \ + 0u, \ + "search by pseudo-header entry name " \ + "should fail"); + } + + return ! 0; +} + + +/* Return non-zero if succeeded, zero if failed */ +static int +mhdtl_comb_check_entry_at_idx (struct mhd_HpackDTblContext *dyn, + size_t idx, + const char *expect_name, + const char *expect_value) +{ + return mhdtl_comb_check_entry_n_at_idx (dyn, + idx, + strlen (expect_name), + expect_name, + strlen (expect_value), + expect_value); +} + + +#define MHDTL_HTBL_FIND_ENTRY_REAL_STR(dyn,name,value) \ + mhd_htbl_find_entry_real (dyn,strlen (name),(name), \ + strlen (value),(value)) +#define MHDTL_HTBL_FIND_NAME_REAL_STR(dyn,name) \ + mhd_htbl_find_name_real (dyn,strlen (name),(name)) + + +/* + * The dynamic table tests + */ + +static int +test_dyn_create_destroy (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = \ + mhd_dtbl_create (mhd_hpack_def_dyn_table_size), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_dtbl_get_num_entries (dyn), 0u, \ + "an empty table must have no entries"); + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_create_destroy_larger (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (59u * 1024u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + MHDT_EXPECT_UINT_EQ_VAL_D (mhd_dtbl_get_num_entries (dyn), 0u, \ + "an empty table must have no entries"); + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_destroy (dyn); + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (mhd_DTBL_MAX_SIZE), \ + "Create HPACK dynamic table with maximum size"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + /* Add some entries with checks */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 123u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 234u); + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_three (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (256u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "header1", "value1"); + mhdtl_dyn_add_hdr_with_check (dyn, "header2", "longer value of the header2"); + mhdtl_dyn_add_hdr_with_check (dyn, "Header3", "value of the header with the " + "uppercase name"); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_empty (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (256u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "h", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "", "v"); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_evict_simple (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (128u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "header1", "value1"); + mhdtl_dyn_add_hdr_with_check (dyn, "header2", "longer value of the header2"); + mhdtl_dyn_add_hdr_with_check (dyn, "Header3", "value of the header with the " + "uppercase name"); + mhdtl_dyn_add_hdr_with_check (dyn, "header4", "smaller header"); + mhdtl_dyn_add_hdr_with_check (dyn, "header5", "value5"); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_evict_wrap (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (280u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + +#define MHDTL_H01N "notably-long-name1" /* length: 18 */ +#define MHDTL_H01V "some notably long data1" /* length: 23 */ +#define MHDTL_H02N "longer-name2" /* length: 12 */ +#define MHDTL_H02V "some longer data2" /* length: 17 */ +#define MHDTL_H03N "abcdefgh3" /* length: 9 */ +#define MHDTL_H03V "random data3" /* length: 12 */ +#define MHDTL_H04N "short-hdr4" /* length: 10 */ +#define MHDTL_H04V "value4" /* length: 6 */ +#define MHDTL_H05N "some-header5" /* length: 12 */ +#define MHDTL_H05V "even longer value of the header5" /* length: 32 */ +#define MHDTL_H06N "longer-name6" /* length: 12 */ +#define MHDTL_H06V "some longer data6" /* length: 17 */ +#define MHDTL_H07N "some-extremely-long-name7" /* length: 25 */ +#define MHDTL_H07V "some really long value of the header7" /* length: 37 */ +#define MHDTL_H08N "someheader8" /* length: 11 */ +#define MHDTL_H08V "value8" /* length: 6 */ +#define MHDTL_H09N "the-long-long-long-long-long-long-long-name9" /* length: 44 */ +#define MHDTL_H09V "the header (field) value, with commas and other " \ + "extra characters to make it really huge, larger " \ + "enough to replace all other headers but one, the " \ + "last one." /* length: 154 */ +#define MHDTL_H10N "the-long-long-long-long-long-long-long-name10" /* length: 45 */ +#define MHDTL_H10V "the header (field) value, with commas and other " \ + "extra characters to make it really huge, larger " \ + "enough to replace all other headers, leaving space " \ + "only for a tiny header" /* length: 169 */ +#define MHDTL_H11N "a" /* length: 1 */ +#define MHDTL_H11V "B" /* length: 1 */ +#define MHDTL_H12N "c" /* length: 1 */ +#define MHDTL_H12V "D" /* length: 1 */ +#define MHDTL_H13N "e" /* length: 1 */ +#define MHDTL_H13V "F" /* length: 1 */ +#define MHDTL_H14N "g" /* length: 1 */ +#define MHDTL_H14V "H" /* length: 1 */ +#define MHDTL_H15N "i" /* length: 1 */ +#define MHDTL_H15V "J" /* length: 1 */ +#define MHDTL_H16N "k" /* length: 1 */ +#define MHDTL_H16V "L" /* length: 1 */ +#define MHDTL_H17N "m" /* length: 1 */ +#define MHDTL_H17V "N" /* length: 1 */ +#define MHDTL_H18N "name18" /* length: 6 */ +#define MHDTL_H18V "vl18" /* length: 4 */ +#define MHDTL_H19N "o" /* length: 1 */ +#define MHDTL_H19V "P" /* length: 1 */ +#define MHDTL_H20N "m" /* length: 1 */ +#define MHDTL_H20V "N" /* length: 1 */ + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H01N, MHDTL_H01V); /* 18 + 23 + 32 = 73 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H02N, MHDTL_H02V); /* 12 + 17 + 32 = 61 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H03N, MHDTL_H03V); /* 9 + 12 + 32 = 53 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H04N, MHDTL_H04V); /* 10 + 6 + 32 = 48 */ + /* 73 + 61 + 48 + 76 = 258 */ + + /* '1', '2', '3', '4' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 235u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H04N, MHDTL_H04V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H03N, MHDTL_H03V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H02N, MHDTL_H02V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H01N, MHDTL_H01V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H05N, MHDTL_H05V); /* 12 + 32 + 32 = 76 */ + /* '5' [insert pos], '2', '3', '4' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 238u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H05N, MHDTL_H05V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H04N, MHDTL_H04V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H03N, MHDTL_H03V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H02N, MHDTL_H02V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H06N, MHDTL_H06V); /* 12 + 17 + 32 = 61 */ + /* '5', '6' [insert pos], '3', '4' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 238u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H06N, MHDTL_H06V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H05N, MHDTL_H05V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H04N, MHDTL_H04V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H03N, MHDTL_H03V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H07N, MHDTL_H07V); /* 25 + 37 + 32 = 94 */ + /* '5', '6', '7' [insert pos], '4' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 279u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H07N, MHDTL_H07V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H06N, MHDTL_H06V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H05N, MHDTL_H05V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H04N, MHDTL_H04V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H08N, MHDTL_H08V); /* 11 + 6 + 32 = 49 */ + /* '5', '6', '7', '8' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H08N, MHDTL_H08V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H07N, MHDTL_H07V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H06N, MHDTL_H06V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H05N, MHDTL_H05V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H09N, MHDTL_H09V); /* 44 + 154 + 32 = 230 */ + /* '9' [insert pos], '8' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 279u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H09N, MHDTL_H09V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H08N, MHDTL_H08V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H10N, MHDTL_H10V); /* 45 + 169 + 32 = 246 */ + /* '10' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 246u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H10N, MHDTL_H10V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H11N, MHDTL_H11V); /* 1 + 1 + 32 = 34 */ + /* '10', '11' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H11N, MHDTL_H11V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H10N, MHDTL_H10V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H12N, MHDTL_H12V); /* 1 + 1 + 32 = 34 */ + /* '12' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 68u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H13N, MHDTL_H13V); /* 1 + 1 + 32 = 34 */ + /* '12', '13' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 102u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H14N, MHDTL_H14V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 136u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H15N, MHDTL_H15V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14', '15' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 170u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H16N, MHDTL_H16V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14', '15', '16' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 204u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 6u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H17N, MHDTL_H17V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14', '15', '16', '17' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 238u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 7u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H17N, MHDTL_H17V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 7u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H18N, MHDTL_H18V); /* 6 + 4 + 32 = 42 */ + /* '12', '13', '14', '15', '16', '17', '18' [insert pos], '11' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 8u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H18N, MHDTL_H18V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H17N, MHDTL_H17V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 7u, + MHDTL_H12N, MHDTL_H12V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 8u, + MHDTL_H11N, MHDTL_H11V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H19N, MHDTL_H19V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14', '15', '16', '17', '18', '19' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 8u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H19N, MHDTL_H19V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H18N, MHDTL_H18V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H17N, MHDTL_H17V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 7u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 8u, + MHDTL_H12N, MHDTL_H12V); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 246u); + /* 'generated' [insert pos], '19' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H19N, MHDTL_H19V); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 247u); /* Should be reset on the next add */ + /* Re-use headers */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H12N, MHDTL_H12V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H13N, MHDTL_H13V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H14N, MHDTL_H14V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H15N, MHDTL_H15V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H16N, MHDTL_H16V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H17N, MHDTL_H17V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H18N, MHDTL_H18V); /* 6 + 4 + 32 = 42 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H19N, MHDTL_H19V); /* 1 + 1 + 32 = 34 */ + /* '12', '13', '14', '15', '16', '17', '18', '19' [insert pos] */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 8u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H19N, MHDTL_H19V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H18N, MHDTL_H18V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H17N, MHDTL_H17V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 7u, + MHDTL_H13N, MHDTL_H13V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 8u, + MHDTL_H12N, MHDTL_H12V); + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H20N, MHDTL_H20V); /* 1 + 1 + 32 = 34 */ + /* '20' [insert pos], '13', '14', '15', '16', '17', '18', '19' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 8u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H20N, MHDTL_H20V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H19N, MHDTL_H19V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H18N, MHDTL_H18V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H17N, MHDTL_H17V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + MHDTL_H16N, MHDTL_H16V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 6u, + MHDTL_H15N, MHDTL_H15V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 7u, + MHDTL_H14N, MHDTL_H14V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 8u, + MHDTL_H13N, MHDTL_H13V); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 212u); + /* '20', 'generated' [insert pos], '19' */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 280u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H20N, MHDTL_H20V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H19N, MHDTL_H19V); + + mhd_dtbl_destroy (dyn); + +#undef MHDTL_H01N +#undef MHDTL_H01V +#undef MHDTL_H02N +#undef MHDTL_H02V +#undef MHDTL_H03N +#undef MHDTL_H03V +#undef MHDTL_H04N +#undef MHDTL_H04V +#undef MHDTL_H05N +#undef MHDTL_H05V +#undef MHDTL_H06N +#undef MHDTL_H06V +#undef MHDTL_H07N +#undef MHDTL_H07V +#undef MHDTL_H08N +#undef MHDTL_H08V +#undef MHDTL_H09N +#undef MHDTL_H09V +#undef MHDTL_H10N +#undef MHDTL_H10V +#undef MHDTL_H11N +#undef MHDTL_H11V +#undef MHDTL_H12N +#undef MHDTL_H12V +#undef MHDTL_H13N +#undef MHDTL_H13V +#undef MHDTL_H14N +#undef MHDTL_H14V +#undef MHDTL_H15N +#undef MHDTL_H15V +#undef MHDTL_H16N +#undef MHDTL_H16V +#undef MHDTL_H17N +#undef MHDTL_H17V +#undef MHDTL_H18N +#undef MHDTL_H18V +#undef MHDTL_H19N +#undef MHDTL_H19V +#undef MHDTL_H20N +#undef MHDTL_H20V + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_evict_inter (void) +{ + struct mhd_HpackDTblContext*dyn; + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (705u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 50u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 50u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 75u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 125u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 100u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 225u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 125u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 350u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 150u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 500u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 175u); + + /* { 50, 75, 100, 125, 150, 175 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 675u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 6u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 6u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 50u); + + /* First two entries should be replaced with a single entry, which + is 2 bytes smaller than two entries. + (50, 75) -> (123) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 123u); + /* { 123 [insert pos], 100, 125, 150, 175 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 673u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 5u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 100u); + + /* Next entry should be replaced with a smaller entry. + (100) -> (35) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 35u); + /* { 123, 35 [insert pos], 125, 150, 175 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 608u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 5u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 125u); + + /* Should be added without eviction. + -> (97) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 97u); + /* { 123, 35, 97 [insert pos], 125, 150, 175 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 705u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 6u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 6u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 125u); + + /* Two entries should be replaced with single one. + (125, 150) -> (275) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 275u); + /* { 123, 35, 97, 275 [insert pos], 175 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 705u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 5u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 175u); + + /* Two entries should be replaced with single one. + (175, 123) -> (251) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 251u); + /* { 35, 97, 275, 251 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 658u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 4u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 35u); + + /* Should be added without eviction. + -> (42) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 42u); + /* { 42 [insert pos], 35, 97, 275, 251 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 700u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 5u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 5u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 35u); + + /* Two entries should be replaced with single one. + (35, 97) -> (51) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 51u); + /* { 42, 51 [insert pos], 275, 251 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 619u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 4u, \ + &check_name, \ + &check_value))) + MHDT_EXPECT_UINT_EQ_VAL (MHDTL_HPACK_ENTRY_SIZE (check_name.size, \ + check_value.size), \ + 275u); + + /* Three entries should be replaced with single one. + (275, 251, 42) -> (613) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 613u); + /* { 51, 613 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 664u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + /* (51, 613) -> (672) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 672u); + /* { 672 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 672u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + + /* -> (33) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 672, 33 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 705u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + /* (672) -> (33) */ + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33 [insert pos], 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 66u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33 [insert pos], 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 693u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 21u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33 [insert pos] } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 693u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 21u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33 [insert pos], 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 693u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 21u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 639u); + /* { 33, 639 [insert pos], 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 705u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33 [insert pos], 639, 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 705u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33, 33 [insert pos], 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 99u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 33u); + /* { 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33 [insert pos], 33 } */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 693u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 21u); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_series (void) +{ + const uint_fast16_t num_inter = + (uint_fast16_t) + (mhdtl_enable_deep_tests ? (16u * 1024u) : (1024u)); + struct mhd_HpackDTblContext*dyn; + uint_fast16_t i; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (925u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + /* Add large strings */ + for (i = 0; i < num_inter; ++i) + { + size_t prev_used; + size_t cur_used; + size_t strs_size; + + cur_used = mhdtl_dyn_get_size_used (dyn); + do + { + strs_size = 50u + mhdtl_mix16 (i, + (uint_least16_t) prev_used) % 256u; + prev_used = cur_used; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + cur_used = mhdtl_dyn_get_size_used (dyn); + } while (prev_used + strs_size + mhd_HPACK_ENTRY_OVERHEAD + == cur_used); + mhd_dtbl_evict_to_size (dyn, + 0u); + } + + /* Add small strings */ + for (i = 0; i < num_inter; ++i) + { + size_t prev_used; + size_t cur_used; + size_t strs_size; + + cur_used = mhdtl_dyn_get_size_used (dyn); + do + { + strs_size = mhdtl_mix16 (i, + (uint_least16_t) prev_used) % 16u; + prev_used = cur_used; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + cur_used = mhdtl_dyn_get_size_used (dyn); + } while (prev_used + strs_size + mhd_HPACK_ENTRY_OVERHEAD + == cur_used); + mhd_dtbl_evict_to_size (dyn, + 0u); + } + + /* Add mixed-size strings */ + for (i = 0; i < num_inter; ++i) + { + size_t prev_used; + size_t cur_used; + size_t strs_size; + + cur_used = mhdtl_dyn_get_size_used (dyn); + do + { + strs_size = mhdtl_mix16 (i, + (uint_least16_t) prev_used) % 312u; + prev_used = cur_used; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + cur_used = mhdtl_dyn_get_size_used (dyn); + } while (prev_used + strs_size + mhd_HPACK_ENTRY_OVERHEAD + == cur_used); + mhd_dtbl_evict_to_size (dyn, + 0u); + } + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_add_evict_series (void) +{ + const uint_fast16_t num_inter = + (uint_fast16_t) + (mhdtl_enable_deep_tests ? (1024u) : (64u)); + struct mhd_HpackDTblContext*dyn; + uint_fast16_t i; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (925u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + for (i = 0; i < num_inter; ++i) + { + uint_fast16_t j; + /* Add large strings */ + for (j = 0; j < 128u; ++j) + { + size_t strs_size = 50u + mhdtl_mix16 (i, j) % 256u; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + /* Sometimes repeat the same size */ + if (16u == (j % 32u)) + { + unsigned int num_rep = mhdtl_mix16 (j, i) % 16u; + while (0 != num_rep--) + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + } + } + /* Add small strings */ + for (j = 0; j < 512u; ++j) + { + size_t strs_size = mhdtl_mix16 (i, j) % 15u; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + /* Sometimes repeat the same size */ + if (16u == (j % 32u)) + { + unsigned int num_rep = mhdtl_mix16 (j, i) % 32u; + while (0 != num_rep--) + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + } + } + /* Add mixed-size strings */ + for (j = 0; j < 256u; ++j) + { + size_t strs_size = mhdtl_mix16 (i, j) % 312u; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + /* Sometimes repeat the same size */ + if (16u == (j % 32u)) + { + unsigned int num_rep = mhdtl_mix16 (j, i) % 24u; + while (0 != num_rep--) + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + } + } + /* Again add small strings before adding large strings */ + for (j = 0; j < 32u; ++j) + { + size_t strs_size = mhdtl_mix16 (i, j) % 15u; + mhdtl_dyn_add_sized_strs_with_check (dyn, + strs_size); + } + } + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_evict_to_size (void) +{ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (256u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + +#define MHDTL_H01N "a" /* length: 1 */ +#define MHDTL_H01V "b" /* length: 1 */ +#define MHDTL_H02N "cd" /* length: 2 */ +#define MHDTL_H02V "ef" /* length: 2 */ +#define MHDTL_H03N "header3" /* length: 7 */ +#define MHDTL_H03V "value of header3" /* length: 16 */ +#define MHDTL_H04N "some-header4" /* length: 12 */ +#define MHDTL_H04V "even longer value of the header4" /* length: 32 */ + + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H01N, MHDTL_H01V); /* 1 + 1 + 32 = 34 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H02N, MHDTL_H02V); /* 2 + 2 + 32 = 36 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H03N, MHDTL_H03V); /* 7 + 16 + 32 = 55 */ + mhdtl_dyn_add_hdr_with_check (dyn, MHDTL_H04N, MHDTL_H04V); /* 12 + 32 + 32 = 76 */ + /* Total size: 34 + 36 + 55 + 76 = 201 */ + + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 201u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H04N, MHDTL_H04V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H03N, MHDTL_H03V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H02N, MHDTL_H02V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + MHDTL_H01N, MHDTL_H01V); + + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_evict_to_size (dyn, 202u); /* Nothing should be evicted */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 201u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_evict_to_size (dyn, 201u); /* Still nothing should be evicted */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 201u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_evict_to_size (dyn, 200u); /* Oldest entry should be evicted */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 201u - 34u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H04N, MHDTL_H04V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + MHDTL_H03N, MHDTL_H03V); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + MHDTL_H02N, MHDTL_H02V); + + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_evict_to_size (dyn, 76u + 1u); /* Only last entry should be left */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 76u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + MHDTL_H04N, MHDTL_H04V); + + mhdtl_dyn_check_get_valid_invalid (dyn); + + mhd_dtbl_evict_to_size (dyn, 76u - 1u); /* Everything should be evicted */ + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + mhdtl_dyn_check_get_valid_invalid (dyn); + +#undef MHDTL_H01N +#undef MHDTL_H01V +#undef MHDTL_H02N +#undef MHDTL_H02V +#undef MHDTL_H03N +#undef MHDTL_H03V +#undef MHDTL_H04N +#undef MHDTL_H04V + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_resize (void) +{ + struct mhd_HpackDTblContext*dyn; + + /* zero-sized table */ + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (321u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_sized_entry_with_check (dyn, 150u); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 218u); + + /* Resize table (should be no eviction) */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 230u), "resize of the table"); + MHDT_EXPECT_PTR_NONNULL (dyn); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 230u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 218u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + "a", + "b"); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "c", + "d"); + + /* Resize table (should be still no eviction) */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 218u), "resize of the table"); + MHDT_EXPECT_PTR_NONNULL (dyn); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 218u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 218u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + "a", + "b"); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "c", + "d"); + + /* Resize table (oldest entry should be evicted) */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 217u), "resize of the table"); + MHDT_EXPECT_PTR_NONNULL (dyn); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 217u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 184u); + mhdtl_dyn_add_hdr_with_check (dyn, "x", ""); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 217u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "x", + ""); + + /* Resize table (all entries except the newest should be evicted) */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 33u), "resize of the table"); + MHDT_EXPECT_PTR_NONNULL (dyn); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 33u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 33u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "x", + ""); + + /* Resize table (grow, no eviction) */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 501u), "resize of the table"); + MHDT_EXPECT_PTR_NONNULL (dyn); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 501u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 33u); + mhdtl_dyn_add_sized_entry_with_check (dyn, 468u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 501u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + "x", + ""); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_find (void) +{ + static const char *hdr1_name = "first-hdr"; + static const char *hdr1_val = "first value"; + static const char *hdr2_name = "second-hdr"; + static const char *hdr2_val = "second value"; + static const char *hdr3_name = "third-hdr"; + static const char *hdr3_val = "third value"; + static const char *hdr4_name = "fourth-hdr"; + static const char *hdr4_val = "fourth value"; + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (256u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, hdr1_name, hdr1_val); + mhdtl_dyn_add_hdr_with_check (dyn, hdr2_name, hdr2_val); + mhdtl_dyn_add_hdr_with_check (dyn, hdr3_name, hdr3_val); + mhdtl_dyn_add_hdr_with_check (dyn, hdr4_name, hdr4_val); + + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 4u, + hdr1_name, hdr1_val); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + hdr2_name, hdr2_val); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + hdr3_name, hdr3_val); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + hdr4_name, hdr4_val); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_reset_on_too_large (void) +{ + static const size_t tbl_size = 133u; /* not a power of two */ + struct mhd_HpackDTblContext*dyn; + + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (tbl_size), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + /* Add small entries */ + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, tbl_size + 1); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Re-add small entries */ + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, tbl_size); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + + if (1) + { + struct mhd_BufferConst check_name; + struct mhd_BufferConst check_value; + + if (MHDT_EXPECT_TRUE (mhd_dtbl_get_entry (dyn, \ + mhd_HPACK_STBL_LAST_IDX + 1u, \ + &check_name, + &check_value))) + { + MHDT_EXPECT_UINT_GT_VAL (check_name.size, 1u); + MHDT_EXPECT_UINT_GT_VAL (check_value.size, 1u); + } + } + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_dyn_zero_sizes (void) +{ + struct mhd_HpackDTblContext*dyn; + + /* zero-sized table */ + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (0u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + /* smallest entry (zero-sized strings) */ + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Resize table to the same zero size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 0u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 0u); + /* smallest entry (zero-sized strings) */ + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Resize table to non-zero size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 127u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 127u); + + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhd_dtbl_evict_to_size (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 2u); + + mhdtl_dyn_add_sized_entry_with_check (dyn, 45u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + "a", + "b"); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + "c", + "d"); + + /* smallest entries (zero-sized strings) */ + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "", + ""); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 2u, + "", + ""); + + /* Resize table to zero size again */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 0u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + mhd_dtbl_evict_to_size (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "d"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Resize table to the size smaller than minimal entry size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 31u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + mhdtl_dyn_add_hdr_with_check (dyn, "a", "b"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Resize table to the minimal size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 32u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 32u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 1u); + /* Resize table back to the size smaller than minimal entry size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 31u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 31u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 0u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + /* Resize table to the usable size */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 128u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 128u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + mhdtl_dyn_add_sized_strs_with_check (dyn, 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 4u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 128u); + mhdtl_dyn_add_hdr_with_check (dyn, "a", "1"); + mhdtl_dyn_add_hdr_with_check (dyn, "b", "2"); + mhdtl_dyn_add_hdr_with_check (dyn, "c", "3"); + mhdtl_dyn_add_hdr_with_check (dyn, "d", "4"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 3u); + MHDT_EXPECT_UINT_EQ_VAL (mhdtl_dyn_get_size_used (dyn), 102u); + mhdtl_dyn_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 3u, + "b", + "2"); + /* Resize table to zero size again */ + MHDT_EXPECT_TRUE_D (mhd_dtbl_resize (&dyn, 0u), \ + "resize of the table"); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_table_max_size (dyn), 0u); + MHDT_EXPECT_UINT_EQ_VAL (mhd_dtbl_get_num_entries (dyn), 0u); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_stat_get_find (void) +{ + mhdtl_stat_check_entry_at_idx (1u, + ":authority", + ""); + mhdtl_stat_check_entry_at_idx (5u, + ":path", + "/index.html"); + mhdtl_stat_check_entry_at_idx (14u, + ":status", + "500"); + mhdtl_stat_check_entry_at_idx (15u, + "accept-charset", + ""); + mhdtl_stat_check_entry_at_idx (16u, + "accept-encoding", + "gzip, deflate"); + mhdtl_stat_check_entry_at_idx (17u, + "accept-language", + ""); + mhdtl_stat_check_entry_at_idx (31u, + "content-type", + ""); + mhdtl_stat_check_entry_at_idx (42u, + "if-range", + ""); + mhdtl_stat_check_entry_at_idx (47u, + "max-forwards", + ""); + mhdtl_stat_check_entry_at_idx (51u, + "referer", + ""); + mhdtl_stat_check_entry_at_idx (58u, + "user-agent", + ""); + mhdtl_stat_check_entry_at_idx (61u, + "www-authenticate", + ""); + + return MHDT_TEST_RESULT (); +} + + +static int +test_stat_find_non_pseudo_entry_absent (void) +{ + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR ("foo","bar"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR ("foo",""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR ("","bar"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR ("",""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR (":foo",""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR (":authority",""), \ + 0u, \ + "search for pseudo-header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_ENTRY_REAL_STR (":status", \ + "200"), \ + 0u, \ + "search for pseudo-header should fail"); + + return MHDT_TEST_RESULT_D ("search for non-existing non-pseudo headers"); +} + + +static int +test_stat_find_non_pseudo_name_absent (void) +{ + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_NAME_REAL_STR ("foo"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_NAME_REAL_STR (""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_NAME_REAL_STR (":foo"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_NAME_REAL_STR (":authority"), \ + 0u, \ + "search for pseudo-header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_STBL_FIND_NAME_REAL_STR (":status"), \ + 0u, \ + "search for pseudo-header should fail"); + + return MHDT_TEST_RESULT_D ("search for non-existing non-pseudo names"); +} + + +static int +test_comb_get_find (void) +{ + struct mhd_HpackDTblContext *dyn; + + /* zero-sized table */ + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (456u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "abc", "xyz"); + mhdtl_dyn_add_hdr_with_check (dyn, "", "empty-name"); + mhdtl_dyn_add_hdr_with_check (dyn, "empty-value", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "2", "two"); + + mhdtl_comb_check_entry_at_idx (dyn, + 1u, + ":authority", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 5u, + ":path", + "/index.html"); + mhdtl_comb_check_entry_at_idx (dyn, + 16u, + "accept-encoding", + "gzip, deflate"); + mhdtl_comb_check_entry_at_idx (dyn, + 17u, + "accept-language", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 42u, + "if-range", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 61u, + "www-authenticate", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 62u, + "2", + "two"); + mhdtl_comb_check_entry_at_idx (dyn, + 63u, + "", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 64u, + "empty-value", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + 65u, + "", + "empty-name"); + mhdtl_comb_check_entry_at_idx (dyn, + 66u, + "abc", + "xyz"); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_comb_find_entry_absent (void) +{ + struct mhd_HpackDTblContext *dyn; + + /* zero-sized table */ + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (456u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "hdr1", "value1"); + mhdtl_dyn_add_hdr_with_check (dyn, "", "empty-name"); + mhdtl_dyn_add_hdr_with_check (dyn, "hdr2", "value2"); + mhdtl_dyn_add_hdr_with_check (dyn, "empty-value", ""); + + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, "foo","bar"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, "foo",""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, "","bar"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, ":foo",""), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, \ + ":authority",""), \ + 0u, \ + "search for pseudo-header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_ENTRY_REAL_STR (dyn, ":status", \ + "200"), \ + 0u, \ + "search for pseudo-header should fail"); + + mhdtl_comb_check_entry_at_idx (dyn, mhd_HPACK_STBL_LAST_IDX + 5u, + "", + ""); + mhdtl_comb_check_entry_at_idx (dyn, mhd_HPACK_STBL_LAST_IDX + 1u, + "empty-value", + ""); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +static int +test_comb_find_name_absent (void) +{ + struct mhd_HpackDTblContext *dyn; + + /* zero-sized table */ + MHDT_EXPECT_PTR_NONNULL_D (dyn = mhd_dtbl_create (456u), \ + "Create HPACK dynamic table"); + if (NULL == dyn) + return MHDT_TEST_RESULT (); + + mhdtl_dyn_add_hdr_with_check (dyn, "hdr1", "value1"); + mhdtl_dyn_add_hdr_with_check (dyn, "hdr2", "value2"); + mhdtl_dyn_add_hdr_with_check (dyn, "empty-value", ""); + mhdtl_dyn_add_hdr_with_check (dyn, "", "empty-name"); + mhdtl_dyn_add_hdr_with_check (dyn, "", ""); + + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_NAME_REAL_STR (dyn, "foo"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_NAME_REAL_STR (dyn, ":foo"), \ + 0u, \ + "search for non-existing header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_NAME_REAL_STR (dyn, ":authority"), \ + 0u, \ + "search for pseudo-header should fail"); + MHDT_EXPECT_UINT_EQ_VAL_D (MHDTL_HTBL_FIND_NAME_REAL_STR (dyn, ":status"), \ + 0u, \ + "search for pseudo-header should fail"); + + mhdtl_comb_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 1u, + "", + ""); + mhdtl_comb_check_entry_at_idx (dyn, + mhd_HPACK_STBL_LAST_IDX + 5u, + "hdr1", + "value1"); + + mhd_dtbl_destroy (dyn); + + return MHDT_TEST_RESULT (); +} + + +int +main (int argc, + char *const *argv) +{ + if (argc < 1) + return 99; + + if (mhdt_has_param (argc, argv, "-v") || + mhdt_has_param (argc, argv, "--verbose")) + MHDT_set_verbosity (MHDT_VERB_LVL_VERBOSE); + else if (mhdt_has_param (argc, argv, "-s") || + mhdt_has_param (argc, argv, "--silent")) + MHDT_set_verbosity (MHDT_VERB_LVL_SILENT); + + if (! mhdtl_enable_deep_tests) + mhdtl_enable_deep_tests = mhdt_has_param (argc, argv, "--deep"); + + if (mhdt_has_in_name (argv[0], "_dynamic")) + { + test_dyn_create_destroy (); + test_dyn_create_destroy_larger (); + test_dyn_add_three (); + test_dyn_add_empty (); + test_dyn_add_evict_simple (); + test_dyn_add_evict_wrap (); + test_dyn_add_evict_inter (); + test_dyn_evict_to_size (); + test_dyn_resize (); + test_dyn_find (); + test_dyn_reset_on_too_large (); + test_dyn_zero_sizes (); + test_dyn_add_series (); + test_dyn_add_evict_series (); + } + else if (mhdt_has_in_name (argv[0], "_static")) + { + test_stat_get_find (); + test_stat_find_non_pseudo_entry_absent (); + test_stat_find_non_pseudo_name_absent (); + } + else if (mhdt_has_in_name (argv[0], "_combined")) + { + test_comb_get_find (); + test_comb_find_entry_absent (); + test_comb_find_name_absent (); + } + else + MHDT_ERR_EXIT_D ("The test subtype marker string was not found in " \ + "the name of this binary"); + + return MHDT_FINAL_RESULT (argv[0]); +}